diff --git a/findversion.sh b/findversion.sh
--- a/findversion.sh
+++ b/findversion.sh
@@ -106,22 +106,29 @@
 	fi
 elif [ -d "$ROOT_DIR/.hg" ]; then
 	# We are a hg checkout
-	if [ -n "`hg status | grep -v '^?'`" ]; then
-		MODIFIED="2"
-	fi
 	HASH=`LC_ALL=C hg id -i | cut -c1-12`
 	REV="h`echo $HASH | cut -c1-8`"
 	BRANCH="`hg branch | sed 's@^default$@@'`"
-	TAG="`hg id -t | grep -v 'tip$'`"
+	if [ "`hg id -t | grep qtip`" ]; then
+		# Mercurial Patch Queue
+		TAG="`hg id -t -rqparent | sed "s/ /\n/g" | grep -v qparent | head -n1`"
+		REV_NR=`LC_ALL=C hg --debug log -rqparent | grep "extra:       convert_revision=svn:" | sed "s/.*@//"`
+		MODIFIED="2"
+	else
+		TAG="`hg id -t | grep -v 'tip$'`"
+		REV_NR=`LC_ALL=C hg --debug parent | grep "extra:       convert_revision=svn:" | sed "s/.*@//"`
+		if [ -n "`hg status | grep -v '^?'`" ]; then
+			MODIFIED="2"
+		fi
+	fi
+	if [ -z "$REV_NR" ]; then
+		# No rev? try alternative way
+		REV_NR=`LC_ALL=C hg log -f -k "(svn r" -l 1 --template "{desc|firstline}\n" | grep "^(svn r[0-9]*)" | sed "s@.*(svn r\([0-9]*\)).*@\1@"`
+	fi
 	if [ -n "$TAG" ]; then
 		BRANCH=""
 		REV="$TAG"
 	fi
-	REV_NR=`LC_ALL=C hg log -f -k "(svn r" -l 1 --template "{desc|firstline}\n" | grep "^(svn r[0-9]*)" | sed "s@.*(svn r\([0-9]*\)).*@\1@"`
-	if [ -z "$REV_NR" ]; then
-		# No rev? Maybe it is a custom hgsubversion clone
-		REV_NR=`LC_ALL=C hg parent --template="{svnrev}"`
-	fi
 elif [ -f "$ROOT_DIR/.ottdrev" ]; then
 	# We are an exported source bundle
 	cat $ROOT_DIR/.ottdrev
diff --git a/src/blitter/32bpp_base.hpp b/src/blitter/32bpp_base.hpp
--- a/src/blitter/32bpp_base.hpp
+++ b/src/blitter/32bpp_base.hpp
@@ -14,7 +14,12 @@
 
 #include "base.hpp"
 #include "../core/bitmath_func.hpp"
+#include "../core/math_func.hpp"
 #include "../gfx_func.h"
+#include "../debug.h"
+#include <math.h>
+
+extern int _sat, _li;
 
 /** Base for all 32bpp blitters. */
 class Blitter_32bppBase : public Blitter {
@@ -101,6 +106,140 @@
 	}
 
 	/**
+	 * Blend a colour based on Pixel value and the current pixel value.
+	 */
+	static inline uint ComposeColourBlend(uint colour, uint32 current)
+	{
+		if (colour == current) return colour;
+
+		/* Converting to HSL */
+
+		/* Colour (cc) */
+		int r_colour = GB(colour,  16, 8);
+		int g_colour = GB(colour,  8,  8);
+		int b_colour = GB(colour,  0,  8);
+		int hue = 0;
+		int saturation = 0;
+		int lightness_colour = 0;
+
+		/* Find max and min cc */
+		int min_colour = min(min(r_colour, g_colour),b_colour);
+		
+		if ((r_colour > g_colour) && (r_colour > b_colour)) {
+			if (min_colour != r_colour) {
+				hue = 60 * (g_colour - b_colour) / (r_colour - min_colour) + 360;
+				hue %= 360;
+				if ((r_colour + min_colour) <= 256) {
+					saturation = (r_colour - min_colour) * 255 / (r_colour + min_colour);
+				} else {
+					saturation = (r_colour - min_colour) * 255 / (512 - (r_colour + min_colour));
+				}
+			} else {
+				saturation = 0;
+				lightness_colour = r_colour;
+			}
+		} else if (g_colour > b_colour){
+			if (min_colour != g_colour) {
+				hue = 60 * (b_colour - r_colour) / (g_colour - min_colour) + 120;
+				if ((g_colour + min_colour) <= 256) {
+					saturation = (g_colour - min_colour) * 255 / (g_colour + min_colour);
+				} else {
+					saturation = (g_colour - min_colour) * 255 / (512 - (g_colour + min_colour));
+				}
+			} else {
+				saturation = 0;
+				lightness_colour = g_colour;
+			}
+		} else {
+			if (min_colour != b_colour) {
+				hue = 60 * (r_colour - g_colour) / (b_colour - min_colour) + 240;
+				if ((b_colour + min_colour) <= 256) {
+					saturation = (b_colour - min_colour) * 255 / (b_colour + min_colour);
+				} else {
+					saturation = (b_colour - min_colour) * 255 / (512 - (b_colour + min_colour));
+				}
+			} else {
+				saturation = 0;
+				lightness_colour = b_colour;
+			}
+		}
+
+		/* Original colour */
+		int r_current = GB(current,  16, 8);
+		int g_current = GB(current,  8,  8);
+		int b_current = GB(current,  0,  8);
+		/* Find max and min original colour */
+		int min_current = min(min(r_current, g_current),b_current);
+		int max_current = max(max(r_current, g_current),b_current);
+
+		/* Lightness original colour */
+		int lightness_current = (max_current + min_current) / 2;
+
+		/* Converting to RGB */
+		unsigned int red, green, blue;
+
+		if (saturation == 0) {
+			red = (lightness_colour + lightness_current) / 2;
+			green = red;
+			blue = red;
+		} else {
+			float q;
+			if (lightness_current < 128) {
+				q = lightness_current * (1 + saturation / 255.0);
+			} else {
+				q = lightness_current + saturation - (lightness_current * saturation / 255.0);
+			}
+
+			float p = (2 * lightness_current) - q;
+
+			/* Red */
+			int hue_r = hue + 120;
+			if (hue_r > 360) {
+				hue_r -= 360;
+			}
+			if (hue_r < 60) {
+				red = p + ((q - p) * hue_r / 60.0);
+			} else if (hue_r < 180){
+				red = q;
+			} else if (hue_r < 240) {
+				red = p + ((q - p) * (4.0 - hue_r / 60.0));
+			} else {
+				red = p;
+			}
+
+			/* Green */
+			int hue_g = hue;
+
+			if (hue_g < 60) {
+				green = p + ((q - p) * hue_g / 60.0);
+			} else if (hue_g < 180){
+				green = q;
+			} else if (hue_g < 240) {
+				green = p + ((q - p) * (4.0 - hue_g / 60.0));
+			} else {
+				green = p;
+			}
+
+			/* Blue */
+			int hue_b = hue - 120;
+			if (hue_b < 0.0) {
+				hue_b += 360;
+			} 
+			if (hue_b < 60) {
+				blue = p + ((q - p) * hue_b / 60.0);
+			} else if (hue_b < 180){
+				blue = q;
+			} else if (hue_b < 240) {
+				blue = p + ((q - p) * (4.0 - hue_b / 60.0));
+			} else {
+				blue = p;
+			}
+		}
+
+		return ComposeColour(0xff, red, green, blue);
+	}
+
+	/**
 	 * Make a pixel looks like it is transparent.
 	 * @param colour the colour already on the screen.
 	 * @param nom the amount of transparency, nominator, makes colour lighter.
diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp
--- a/src/blitter/32bpp_optimized.cpp
+++ b/src/blitter/32bpp_optimized.cpp
@@ -10,6 +10,7 @@
 /** @file 32bpp_optimized.cpp Implementation of the optimized 32 bpp blitter. */
 
 #include "../stdafx.h"
+#include "../core/alloc_func.hpp"
 #include "../zoom_func.h"
 #include "../settings_type.h"
 #include "../core/math_func.hpp"
@@ -32,6 +33,7 @@
 
 	/* src_px : each line begins with uint32 n = 'number of bytes in this line',
 	 *          then n times is the Colour struct for this line */
+	zoom = ZOOM_LVL_BEGIN;
 	const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
 	/* src_n  : each line begins with uint32 n = 'number of bytes in this line',
 	 *          then interleaved stream of 'm' and 'n' channels. 'm' is remap,
@@ -112,42 +114,69 @@
 
 			switch (mode) {
 				case BM_COLOUR_REMAP:
-					if (src_px->a == 255) {
-						do {
-							uint m = *src_n;
-							/* In case the m-channel is zero, do not remap this pixel in any way */
-							if (m == 0) {
+					do {
+						uint m = *src_n;
+						/* In case the m-channel is zero, do not remap this pixel in any way */
+						if (m == 0) {
+							if (src_px->a == 255) {
 								*dst = src_px->data;
 							} else {
+								*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
+							}
+						} else {
+							uint r = remap[m];
+							if (r != 0) {
+								uint src_col = ComposeColour(src_px->a, src_px->r, src_px->g, src_px->b);
+								uint comp_col = ComposeColourBlend(this->LookupColourInPalette(r), src_col);
+								*dst = ComposeColourPA(comp_col, src_px->a, *dst);
+							}
+						}
+						dst++;
+						src_px++;
+						src_n++;
+					} while (--n != 0);
+					break;
+				case BM_COLOUR_OPAQUE:
+					do {
+						uint m = *src_n;
+						/* In case the m-channel is zero, do not remap this pixel in any way */
+						if (m == 0) {
+							*dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
+						} else {
+							uint r = remap[m];
+							if (r != 0) *dst = ComposeColourPA(this->LookupColourInPalette(r), src_px->a, *dst);
+						}
+						dst++;
+						src_px++;
+						src_n++;
+					} while (--n != 0);
+					break;
+				case BM_TRANSPARENT:
+					/* Make the current color a bit more black, so it looks like this image is transparent */
+					do {
+						uint m = *src_n;
+						if (m == 0) {
+							*dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
+						} else {
+							if (remap){
 								uint r = remap[m];
-								if (r != 0) *dst = this->LookupColourInPalette(r);
+								if (r != 0) *dst = ComposeColourPA(this->LookupColourInPalette(r), src_px->a / 2, *dst);
 							}
-							dst++;
-							src_px++;
-							src_n++;
-						} while (--n != 0);
-					} else {
-						do {
-							uint m = *src_n;
-							if (m == 0) {
-								*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
-							} else {
-								uint r = remap[m];
-								if (r != 0) *dst = ComposeColourPANoCheck(this->LookupColourInPalette(r), src_px->a, *dst);
+							else {
+								*dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
 							}
-							dst++;
-							src_px++;
-							src_n++;
-						} while (--n != 0);
-					}
-					break;
+						}
 
-				case BM_TRANSPARENT:
+						dst++;
+						src_px++;
+						src_n++;
 					/* TODO -- We make an assumption here that the remap in fact is transparency, not some colour.
 					 *  This is never a problem with the code we produce, but newgrfs can make it fail... or at least:
 					 *  we produce a result the newgrf maker didn't expect ;) */
-
-					/* Make the current colour a bit more black, so it looks like this image is transparent */
+					} while (--n != 0);
+					break;
+				case BM_SHADOW:
+					/* Make the current colour a bit more black */
 					src_n += n;
 					if (src_px->a == 255) {
 						src_px += n;
@@ -162,8 +191,8 @@
 							src_px++;
 						} while (--n != 0);
 					}
+
 					break;
-
 				default:
 					if (src_px->a == 255) {
 						/* faster than memcpy(), n is usually low */
@@ -184,7 +213,6 @@
 					break;
 			}
 		}
-
 		dst = dst_ln;
 		src_px = src_px_ln;
 		src_n  = src_n_ln;
@@ -200,61 +228,26 @@
  */
 void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
 {
-	switch (mode) {
+		switch (mode) {
 		default: NOT_REACHED();
-		case BM_NORMAL:       Draw<BM_NORMAL>      (bp, zoom); return;
-		case BM_COLOUR_REMAP: Draw<BM_COLOUR_REMAP>(bp, zoom); return;
-		case BM_TRANSPARENT:  Draw<BM_TRANSPARENT> (bp, zoom); return;
+		case BM_NORMAL:        Draw<BM_NORMAL>       (bp, zoom); return;
+		case BM_COLOUR_REMAP:  Draw<BM_COLOUR_REMAP> (bp, zoom); return;
+		case BM_COLOUR_OPAQUE: Draw<BM_COLOUR_OPAQUE>(bp, zoom); return;
+		case BM_TRANSPARENT:   Draw<BM_TRANSPARENT>  (bp, zoom); return;
+		case BM_SHADOW:        Draw<BM_SHADOW>       (bp, zoom); return;
 	}
 }
 
 /**
  * Resizes the sprite in a very simple way, takes every n-th pixel and every n-th row
- *
+ * not used in extra zoom patch, because all zoomlevels are in the spritecache
  * @param sprite_src sprite to resize
  * @param zoom resizing scale
  * @return resized sprite
  */
 static const SpriteLoader::Sprite *ResizeSprite(const SpriteLoader::Sprite *sprite_src, ZoomLevel zoom)
 {
-	SpriteLoader::Sprite *sprite = MallocT<SpriteLoader::Sprite>(1);
-
-	if (zoom == ZOOM_LVL_NORMAL) {
-		memcpy(sprite, sprite_src, sizeof(*sprite));
-		uint size = sprite_src->height * sprite_src->width;
-		sprite->data = MallocT<SpriteLoader::CommonPixel>(size);
-		memcpy(sprite->data, sprite_src->data, size * sizeof(SpriteLoader::CommonPixel));
-		return sprite;
-	}
-
-	sprite->height = UnScaleByZoom(sprite_src->height, zoom);
-	sprite->width  = UnScaleByZoom(sprite_src->width,  zoom);
-	sprite->x_offs = UnScaleByZoom(sprite_src->x_offs, zoom);
-	sprite->y_offs = UnScaleByZoom(sprite_src->y_offs, zoom);
-
-	uint size = sprite->height * sprite->width;
-	SpriteLoader::CommonPixel *dst = sprite->data = CallocT<SpriteLoader::CommonPixel>(size);
-
-	const SpriteLoader::CommonPixel *src = (SpriteLoader::CommonPixel *)sprite_src->data;
-	const SpriteLoader::CommonPixel *src_end = src + sprite_src->height * sprite_src->width;
-
-	uint scaled_1 = ScaleByZoom(1, zoom);
-
-	for (uint y = 0; y < sprite->height; y++) {
-		if (src >= src_end) src = src_end - sprite_src->width;
-
-		const SpriteLoader::CommonPixel *src_ln = src + sprite_src->width * scaled_1;
-		for (uint x = 0; x < sprite->width; x++) {
-			if (src >= src_ln) src = src_ln - 1;
-			*dst = *src;
-			dst++;
-			src += scaled_1;
-		}
-
-		src = src_ln;
-	}
-
-	return sprite;
+	return sprite_src;
 }
 
 Sprite *Blitter_32bppOptimized::Encode(SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
@@ -327,17 +320,11 @@
 				if (a != 0) {
 					dst_px->a = a;
 					*dst_n = src->m;
-					if (src->m != 0) {
-						/* Pre-convert the mapping channel to a RGB value */
-						uint32 colour = this->LookupColourInPalette(src->m);
-						dst_px->r = GB(colour, 16, 8);
-						dst_px->g = GB(colour, 8,  8);
-						dst_px->b = GB(colour, 0,  8);
-					} else {
-						dst_px->r = src->r;
-						dst_px->g = src->g;
-						dst_px->b = src->b;
-					}
+
+					dst_px->r = src->r;
+					dst_px->g = src->g;
+					dst_px->b = src->b;
+
 					dst_px++;
 					dst_n++;
 				} else if (len == 1) {
diff --git a/src/blitter/32bpp_optimized.hpp b/src/blitter/32bpp_optimized.hpp
--- a/src/blitter/32bpp_optimized.hpp
+++ b/src/blitter/32bpp_optimized.hpp
@@ -25,6 +25,12 @@
 
 	/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
 	/* virtual */ Sprite *Encode(SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
+					  void RescaleSpriteHalfSize( const SpriteLoader::Sprite *src_sprite,
+															SpriteLoader::Sprite *dest_sprite,
+															bool prevent_alpha_bleeding);
+					  void RescaleSpriteDoubleSize(const SpriteLoader::Sprite *src_sprite,
+															 SpriteLoader::Sprite *dest_sprite);
+					  void FillRGBFromPalette(SpriteLoader::Sprite *sprite);
 
 	/* virtual */ const char *GetName() { return "32bpp-optimized"; }
 
diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp
--- a/src/blitter/base.hpp
+++ b/src/blitter/base.hpp
@@ -20,6 +20,8 @@
 	BM_NORMAL,       ///< Perform the simple blitting.
 	BM_COLOUR_REMAP, ///< Perform a colour remapping.
 	BM_TRANSPARENT,  ///< Perform transparency colour remapping.
+	BM_COLOUR_OPAQUE,
+	BM_SHADOW
 };
 
 /**
@@ -43,6 +45,8 @@
 
 		void *dst;          ///< Destination buffer
 		int pitch;          ///< The pitch of the destination buffer
+		uint hue;
+		uint m;
 	};
 
 	/** Types of palette animation. */
diff --git a/src/blitter/factory.hpp b/src/blitter/factory.hpp
--- a/src/blitter/factory.hpp
+++ b/src/blitter/factory.hpp
@@ -91,7 +91,7 @@
 #if defined(DEDICATED)
 		const char *default_blitter = "null";
 #else
-		const char *default_blitter = "8bpp-optimized";
+		const char *default_blitter = "32bpp-optimized";
 
 #if defined(WITH_COCOA)
 		/* Some people reported lack of fullscreen support in 8 bpp mode.
@@ -99,7 +99,7 @@
 		if (!QZ_CanDisplay8bpp()) {
 			/* The main display can't go to 8 bpp fullscreen mode.
 			 * We will have to switch to 32 bpp by default. */
-			default_blitter = "32bpp-anim";
+			default_blitter = "32bpp-optimized";
 		}
 #endif /* defined(WITH_COCOA) */
 #endif /* defined(DEDICATED) */
diff --git a/src/company_gui.cpp b/src/company_gui.cpp
--- a/src/company_gui.cpp
+++ b/src/company_gui.cpp
@@ -1001,7 +1001,7 @@
 			NWidget(NWID_VERTICAL),
 				NWidget(NWID_HORIZONTAL),
 					NWidget(NWID_SPACER), SetFill(1, 0),
-					NWidget(WWT_EMPTY, COLOUR_GREY, SCMFM_WIDGET_FACE), SetMinimalSize(92, 119),
+					NWidget(WWT_EMPTY, COLOUR_GREY, SCMFM_WIDGET_FACE), SetMinimalSize(210, 279),
 					NWidget(NWID_SPACER), SetFill(1, 0),
 				EndContainer(),
 				NWidget(NWID_SPACER), SetMinimalSize(0, 2),
@@ -1429,7 +1429,14 @@
 				break;
 
 			case SCMFM_WIDGET_FACE:
+				DrawPixelInfo bk, *old_dpi;
+				old_dpi = _cur_dpi;
+				_cur_dpi = &bk;
+				*_cur_dpi = *old_dpi;
+				_cur_dpi->zoom = ZOOM_LVL_IN_2X;
+				/* Draw the company manager face picture */
 				DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top);
+				_cur_dpi = old_dpi;
 				break;
 		}
 	}
@@ -1586,6 +1593,7 @@
 	_nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets)
 );
 
+
 /**
  * Open the simple/advanced company manager face selection window
  *
diff --git a/src/elrail.cpp b/src/elrail.cpp
--- a/src/elrail.cpp
+++ b/src/elrail.cpp
@@ -424,7 +424,7 @@
 						continue; // No neighbour, go looking for a better position
 					}
 
-					AddSortableSpriteToDraw(pylon_base + pylon_sprites[temp], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE,
+					AddSortableSpriteToDraw(pylon_base + pylon_sprites[temp], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE + 5,
 						elevation, IsTransparencySet(TO_CATENARY), -1, -1);
 
 					break; // We already have drawn a pylon, bail out
diff --git a/src/gfx.cpp b/src/gfx.cpp
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -267,16 +267,17 @@
 
 	static const byte colour = PC_WHITE;
 
-	GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour);
-	GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour);
-	GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, colour);
 
-	GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour);
-	GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour);
-	GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour);
-	GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour);
-	GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour);
-	GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour);
+	GfxDrawLine(x, y, x + dx1, y + dy1, colour);
+	GfxDrawLine(x, y, x + dx2, y + dy2, colour);
+	GfxDrawLine(x, y, x + dx3, y + dy3, colour);
+
+	GfxDrawLine(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour);
+	GfxDrawLine(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour);
+	GfxDrawLine(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour);
+	GfxDrawLine(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour);
+	GfxDrawLine(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour);
+	GfxDrawLine(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour);
 }
 
 /**
@@ -1097,7 +1098,7 @@
 				const Sprite *glyph = GetGlyph(params.fontsize, c);
 				if (draw_shadow && params.fontsize == FS_NORMAL && params.cur_colour != TC_BLACK && !(c >= SCC_SPRITE_START && c <= SCC_SPRITE_END)) {
 					SetColourRemap(TC_BLACK);
-					GfxMainBlitter(glyph, x + 1, y + 1, BM_COLOUR_REMAP);
+					GfxMainBlitter(glyph, x + 1, y + 1, BM_COLOUR_OPAQUE);
 					SetColourRemap(params.cur_colour);
 				}
 				GfxMainBlitter(glyph, x, y, BM_COLOUR_REMAP);
@@ -1215,15 +1216,16 @@
 	bp.sprite = sprite->data;
 	bp.sprite_width = sprite->width;
 	bp.sprite_height = sprite->height;
-	bp.width = UnScaleByZoom(sprite->width - clip_left - clip_right, dpi->zoom);
-	bp.height = UnScaleByZoom(sprite->height - clip_top - clip_bottom, dpi->zoom);
+
+	bp.width = (sprite->width - clip_left - clip_right) ;
+	bp.height = (sprite->height - clip_top - clip_bottom) ;
 	bp.top = 0;
 	bp.left = 0;
-	bp.skip_left = UnScaleByZoomLower(clip_left, dpi->zoom);
-	bp.skip_top = UnScaleByZoomLower(clip_top, dpi->zoom);
+	bp.skip_left = clip_left ;
+	bp.skip_top = clip_top ;
 
-	x += ScaleByZoom(bp.skip_left, dpi->zoom);
-	y += ScaleByZoom(bp.skip_top, dpi->zoom);
+	x += bp.skip_left;
+	y += bp.skip_top;
 
 	bp.dst = dpi->dst_ptr;
 	bp.pitch = dpi->pitch;
@@ -1237,43 +1239,43 @@
 
 	y -= dpi->top;
 	/* Check for top overflow */
+
 	if (y < 0) {
-		bp.height -= -UnScaleByZoom(y, dpi->zoom);
+		bp.height -= -y;
 		if (bp.height <= 0) return;
-		bp.skip_top += -UnScaleByZoom(y, dpi->zoom);
+		bp.skip_top += -y;
 		y = 0;
 	} else {
-		bp.top = UnScaleByZoom(y, dpi->zoom);
+		bp.top = y;
 	}
 
 	/* Check for bottom overflow */
-	y += ScaleByZoom(bp.height, dpi->zoom) - dpi->height;
+
+	y += bp.height - dpi->height;
+
 	if (y > 0) {
-		bp.height -= UnScaleByZoom(y, dpi->zoom);
+		bp.height -= y; //UnScaleByZoom(y, dpi->zoom);
 		if (bp.height <= 0) return;
 	}
 
 	x -= dpi->left;
 	/* Check for left overflow */
 	if (x < 0) {
-		bp.width -= -UnScaleByZoom(x, dpi->zoom);
+		bp.width -= -x;
 		if (bp.width <= 0) return;
-		bp.skip_left += -UnScaleByZoom(x, dpi->zoom);
+		bp.skip_left += -x ;
 		x = 0;
 	} else {
-		bp.left = UnScaleByZoom(x, dpi->zoom);
+		bp.left = x;
 	}
 
 	/* Check for right overflow */
-	x += ScaleByZoom(bp.width, dpi->zoom) - dpi->width;
+	x += bp.width - dpi->width;
 	if (x > 0) {
-		bp.width -= UnScaleByZoom(x, dpi->zoom);
+		bp.width -= x;
 		if (bp.width <= 0) return;
 	}
 
-	assert(bp.skip_left + bp.width <= UnScaleByZoom(sprite->width, dpi->zoom));
-	assert(bp.skip_top + bp.height <= UnScaleByZoom(sprite->height, dpi->zoom));
-
 	/* We do not want to catch the mouse. However we also use that spritenumber for unknown (text) sprites. */
 	if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && sprite_id != SPR_CURSOR_MOUSE) {
 		Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
@@ -1801,7 +1803,10 @@
 	byte *b;
 	int width;
 	int height;
-
+	left -=7;
+	right += 7;
+	top -= 7;
+	bottom += 7;
 	if (left < 0) left = 0;
 	if (top < 0) top = 0;
 	if (right > _screen.width) right = _screen.width;
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -41,6 +41,7 @@
 
 #include "table/sprites.h"
 #include "table/strings.h"
+#include "debug.h"
 
 static int _rename_id = 1;
 static int _rename_what = -1;
@@ -174,8 +175,8 @@
 			break;
 	}
 	if (vp != NULL) { // the vp can be null when how == ZOOM_NONE
-		vp->virtual_left = w->viewport->scrollpos_x;
-		vp->virtual_top = w->viewport->scrollpos_y;
+		vp->virtual_left = UnScaleByZoom(w->viewport->scrollpos_x, vp->zoom);
+		vp->virtual_top = UnScaleByZoom(w->viewport->scrollpos_y, vp->zoom);
 	}
 	/* Update the windows that have zoom-buttons to perhaps disable their buttons */
 	w->InvalidateData();
@@ -215,6 +216,9 @@
 	_nested_main_window_widgets, lengthof(_nested_main_window_widgets)
 );
 
+int _sat = 0;
+int _li = 0;
+
 enum {
 	GHK_QUIT,
 	GHK_ABANDON,
@@ -402,7 +406,18 @@
 				}
 				break;
 #endif
-
+			case '3' : _sat = (_sat - 1) % 256;
+				DEBUG(misc, 0, "saturation delta %d ", _sat);
+				break;
+			case '4' : _sat = (_sat + 1) % 256;
+				DEBUG(misc, 0, "saturation delta %d ", _sat);
+				break;
+			case '5' : _li = (_li - 1) % 256;
+				DEBUG(misc, 0, "lightness delta %d ", _li);
+				break;
+			case '6' : _li = (_li + 1) % 256;
+				DEBUG(misc, 0, "lightness delta %d ", _li);
+				break;
 			default: return ES_NOT_HANDLED;
 		}
 		return ES_HANDLED;
diff --git a/src/openttd.cpp b/src/openttd.cpp
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -527,6 +527,10 @@
 	_switch_mode_errorstr = INVALID_STRING_ID;
 	_config_file = NULL;
 
+	DrawPixelInfo dpi;
+	_cur_dpi = &dpi;
+	_cur_dpi->zoom = ZOOM_LVL_NORMAL;
+
 	GetOptData mgo(argc - 1, argv + 1, _options);
 
 	int i;
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -1731,7 +1731,7 @@
 	RailFenceOffset rfo = RFO_FLAT_X;
 	if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
 	AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
-		ti->x, ti->y + 1, 16, 1, 4, ti->z);
+		ti->x, ti->y, 16, 1, 4, ti->z);
 }
 
 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
@@ -1739,7 +1739,7 @@
 	RailFenceOffset rfo = RFO_FLAT_X;
 	if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
 	AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
-		ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
+		ti->x, ti->y + TILE_SIZE, 16, -1, 4, ti->z);
 }
 
 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
@@ -1753,7 +1753,7 @@
 	RailFenceOffset rfo = RFO_FLAT_Y;
 	if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
 	AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
-		ti->x + 1, ti->y, 1, 16, 4, ti->z);
+		ti->x, ti->y, -6, 16, 4, ti->z);
 }
 
 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
@@ -1761,7 +1761,7 @@
 	RailFenceOffset rfo = RFO_FLAT_Y;
 	if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
 	AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
-		ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
+		ti->x + TILE_SIZE, ti->y, -1, 16, 4, ti->z);
 }
 
 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
@@ -2668,12 +2668,10 @@
 
 		case RAIL_TILE_DEPOT:
 			td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
-			if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
-				if (td->rail_speed > 0) {
-					td->rail_speed = min(td->rail_speed, 61);
-				} else {
-					td->rail_speed = 61;
-				}
+			if (td->rail_speed > 0) {
+				td->rail_speed = min(td->rail_speed, 61);
+			} else {
+				td->rail_speed = 61;
 			}
 			td->build_date = Depot::GetByTile(tile)->build_date;
 			break;
diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -1215,25 +1215,32 @@
 		case ROAD_TILE_CROSSING: {
 			if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
 
+			const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
 			PaletteID pal = PAL_NONE;
-			const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
+
+			Roadside roadside = GetRoadside(ti->tile);
 
 			if (rti->UsesOverlay()) {
 				Axis axis = GetCrossingRailAxis(ti->tile);
-				SpriteID road = SPR_ROAD_Y + axis;
 
-				Roadside roadside = GetRoadside(ti->tile);
+				SpriteID road = GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.crossing;
+				if (GetCrossingRoadAxis(ti->tile) == AXIS_X) road++;
+
 
 				if (AlwaysDrawUnpavedRoads(ti->tile, roadside)) {
-					road += 19;
+					road += 8;
 				} else {
 					switch (roadside) {
-						case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break;
-						case ROADSIDE_GRASS:  break;
-						default:              road -= 19; break; // Paved
+						case ROADSIDE_BARREN:
+							pal = PALETTE_TO_BARE_LAND;
+							break;
+						case ROADSIDE_GRASS:
+							break;
+						default:
+							road += 4;
+							break; // Paved
 					}
 				}
-
 				DrawGroundSprite(road, pal);
 
 				SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis;
@@ -1248,8 +1255,6 @@
 				if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++;
 				if (IsCrossingBarred(ti->tile)) image += 2;
 
-				Roadside roadside = GetRoadside(ti->tile);
-
 				if (AlwaysDrawUnpavedRoads(ti->tile, roadside)) {
 					image += 8;
 				} else {
diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -392,14 +392,14 @@
 {
 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
 	static const uint32 _delta_xy_table[8] = {
-		MKIT(3, 3, -1, -1),
-		MKIT(3, 7, -1, -3),
-		MKIT(3, 3, -1, -1),
-		MKIT(7, 3, -3, -1),
-		MKIT(3, 3, -1, -1),
-		MKIT(3, 7, -1, -3),
-		MKIT(3, 3, -1, -1),
-		MKIT(7, 3, -3, -1),
+		MKIT(3, 3, -1, -1),   // N
+		MKIT(3, 14, -1, -3),   // NE
+		MKIT(3, 3, -1, -1),   // E
+		MKIT(7, 3, -3, -1),   // SE
+		MKIT(3, 3, -1, -1),   // S
+		MKIT(3, 14, -1, -3),   // SW
+		MKIT(3, 3, -1, -1),   // W
+		MKIT(7, 3, -3, -1),   // NW
 	};
 #undef MKIT
 
diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp
--- a/src/saveload/misc_sl.cpp
+++ b/src/saveload/misc_sl.cpp
@@ -52,7 +52,7 @@
 	w->viewport->dest_scrollpos_y = _saved_scrollpos_y;
 
 	ViewPort *vp = w->viewport;
-	vp->zoom = (ZoomLevel)min(_saved_scrollpos_zoom, ZOOM_LVL_MAX);
+	vp->zoom = ZOOM_LVL_NORMAL;
 	vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
 	vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
 
diff --git a/src/sound.cpp b/src/sound.cpp
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -16,6 +16,7 @@
 #include "fios.h"
 #include "window_gui.h"
 #include "vehicle_base.h"
+#include "zoom_func.h"
 
 /* The type of set we're replacing */
 #define SET_TYPE "sounds"
@@ -234,9 +235,9 @@
 		const ViewPort *vp = w->viewport;
 
 		if (vp != NULL &&
-				left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
-				top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
-			int screen_x = (left + right) / 2 - vp->virtual_left;
+				left < ScaleByZoom(vp->virtual_left, vp->zoom) + vp->virtual_width && right > ScaleByZoom(vp->virtual_left, vp->zoom) &&
+				top < ScaleByZoom(vp->virtual_top, vp->zoom) + vp->virtual_height && bottom > ScaleByZoom(vp->virtual_top, vp->zoom)) {
+			int screen_x = (left + right) / 2 - ScaleByZoom(vp->virtual_left, vp->zoom);
 			int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
 			float panning = (float)screen_x / width;
 
diff --git a/src/sprite.h b/src/sprite.h
--- a/src/sprite.h
+++ b/src/sprite.h
@@ -150,7 +150,7 @@
  */
 static inline PaletteID SpriteLayoutPaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
 {
-	if (HasBit(image, PALETTE_MODIFIER_TRANSPARENT) || HasBit(image, PALETTE_MODIFIER_COLOUR)) {
+	if (HasBit(image, PALETTE_MODIFIER_COLOUR)) {
 		return (pal != 0 ? pal : default_pal);
 	} else {
 		return PAL_NONE;
diff --git a/src/spritecache.cpp b/src/spritecache.cpp
--- a/src/spritecache.cpp
+++ b/src/spritecache.cpp
@@ -10,6 +10,8 @@
 /** @file spritecache.cpp Caching of sprites. */
 
 #include "stdafx.h"
+#include "gfx_func.h"
+#include "table/sprites.h"
 #include "fileio_func.h"
 #include "spriteloader/grf.hpp"
 #include "gfx_func.h"
@@ -17,18 +19,20 @@
 #include "spriteloader/png.hpp"
 #endif /* WITH_PNG */
 #include "blitter/factory.hpp"
+#include "blitter/32bpp_optimized.hpp"
+
 #include "core/math_func.hpp"
 
 #include "table/sprites.h"
 #include "table/palette_convert.h"
 
 /* Default of 4MB spritecache */
-uint _sprite_cache_size = 4;
+uint _sprite_cache_size = 64;
 
 typedef SimpleTinyEnumT<SpriteType, byte> SpriteTypeByte;
 
 struct SpriteCache {
-	void *ptr;
+	void *ptr[ZOOM_LVL_END];
 	size_t file_pos;
 	uint32 id;
 	uint16 file_slot;
@@ -62,6 +66,10 @@
 
 		_spritecache = ReallocT(_spritecache, items);
 
+		if (_spritecache == NULL) {
+			error("Unable to allocate sprite cache of %u items (" PRINTF_SIZE " bytes)", items, items * sizeof(*_spritecache));
+		}
+
 		/* Reset the new items and update the count */
 		memset(_spritecache + _spritecache_items, 0, (items - _spritecache_items) * sizeof(*_spritecache));
 		_spritecache_items = items;
@@ -189,6 +197,13 @@
 	uint8 file_slot = sc->file_slot;
 	size_t file_pos = sc->file_pos;
 
+	ZoomLevel zoom = ZOOM_LVL_NORMAL;
+
+	if (_cur_dpi) {
+		zoom = ZoomLevel(_cur_dpi->zoom);
+	}
+
+
 	assert(IsMapgenSpriteID(id) == (sprite_type == ST_MAPGEN));
 	assert(sc->type == sprite_type);
 
@@ -323,7 +338,12 @@
 	SpriteCache *sc = AllocateSpriteCache(load_index);
 	sc->file_slot = file_slot;
 	sc->file_pos = file_pos;
-	sc->ptr = NULL;
+	sc->ptr[ZOOM_LVL_IN_4X] = NULL;
+	sc->ptr[ZOOM_LVL_IN_2X] = NULL;
+	sc->ptr[ZOOM_LVL_NORMAL] = NULL;
+	sc->ptr[ZOOM_LVL_OUT_2X] = NULL;
+	sc->ptr[ZOOM_LVL_OUT_4X] = NULL;
+	sc->ptr[ZOOM_LVL_OUT_8X] = NULL;
 	sc->lru = 0;
 	sc->id = file_sprite_id;
 	sc->type = type;
@@ -337,10 +357,12 @@
 {
 	SpriteCache *scnew = AllocateSpriteCache(new_spr); // may reallocate: so put it first
 	SpriteCache *scold = GetSpriteCache(old_spr);
+	ZoomLevel zoom;
 
 	scnew->file_slot = scold->file_slot;
 	scnew->file_pos = scold->file_pos;
-	scnew->ptr = NULL;
+	zoom = ZoomLevel(_cur_dpi->zoom);
+	scnew->ptr[zoom] = NULL;
 	scnew->id = scold->id;
 	scnew->type = scold->type;
 	scnew->warned = false;
@@ -379,6 +401,7 @@
 
 void IncreaseSpriteLRU()
 {
+	ZoomLevel zoom;
 	/* Increase all LRU values */
 	if (_sprite_lru_counter > 16384) {
 		SpriteID i;
@@ -387,7 +410,8 @@
 
 		for (i = 0; i != _spritecache_items; i++) {
 			SpriteCache *sc = GetSpriteCache(i);
-			if (sc->ptr != NULL) {
+			zoom = ZoomLevel(_cur_dpi->zoom);
+			if (sc->ptr[zoom] != NULL) {
 				if (sc->lru >= 0) {
 					sc->lru = -1;
 				} else if (sc->lru != -32768) {
@@ -412,6 +436,7 @@
 static void CompactSpriteCache()
 {
 	MemBlock *s;
+	ZoomLevel zoom;
 
 	DEBUG(sprite, 3, "Compacting sprite cache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
 
@@ -428,11 +453,16 @@
 			if (next->size == 0) break;
 
 			/* Locate the sprite belonging to the next pointer. */
-			for (i = 0; GetSpriteCache(i)->ptr != next->data; i++) {
-				assert(i != _spritecache_items);
+			bool found = false;
+			for (zoom = ZOOM_LVL_MIN;
+				  (zoom < ZOOM_LVL_END) && (!found);
+				  zoom = ZoomLevel(zoom + 1)) {
+				for (i = 0; i < _spritecache_items && !found; i++) {
+					found = (GetSpriteCache(i)->ptr[zoom] == next->data);
+				}
 			}
-
-			GetSpriteCache(i)->ptr = s->data; // Adjust sprite array entry
+			assert(found);
+			GetSpriteCache(i - 1)->ptr[zoom - 1] = s->data; // Adjust sprite array entry
 			/* Swap this and the next block */
 			temp = *s;
 			memmove(s, next, next->size);
@@ -454,16 +484,21 @@
 	SpriteID i;
 	uint best = UINT_MAX;
 	MemBlock *s;
-	int cur_lru;
+	int16 cur_lru;
+	ZoomLevel zoom;
 
 	DEBUG(sprite, 3, "DeleteEntryFromSpriteCache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
 
-	cur_lru = 0xffff;
+	cur_lru = -1;
 	for (i = 0; i != _spritecache_items; i++) {
 		SpriteCache *sc = GetSpriteCache(i);
-		if (sc->ptr != NULL && sc->lru < cur_lru) {
-			cur_lru = sc->lru;
-			best = i;
+		if (sc->lru < cur_lru) {
+			for (zoom = ZOOM_LVL_MIN; zoom < ZOOM_LVL_END; zoom ++) {
+				if (sc->ptr[zoom]) {
+					cur_lru = sc->lru;
+					best = i;
+				}
+			}
 		}
 	}
 
@@ -471,17 +506,22 @@
 	 * This shouldn't really happen, unless all sprites are locked. */
 	if (best == UINT_MAX) error("Out of sprite memory");
 
+	SpriteCache *sc = GetSpriteCache(best);
 	/* Mark the block as free (the block must be in use) */
-	s = (MemBlock*)GetSpriteCache(best)->ptr - 1;
-	assert(!(s->size & S_FREE_MASK));
-	s->size |= S_FREE_MASK;
-	GetSpriteCache(best)->ptr = NULL;
+	for (zoom = ZOOM_LVL_MIN ; zoom < ZOOM_LVL_END ; zoom = ZoomLevel(zoom + 1)) {
+		if (sc->ptr[zoom]) {
+			s = (MemBlock*)sc->ptr[zoom] - 1;
+			assert(!(s->size & S_FREE_MASK));
+			s->size |= S_FREE_MASK;
+			sc->ptr[zoom] = NULL;
 
-	/* And coalesce adjacent free blocks */
-	for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
-		if (s->size & S_FREE_MASK) {
-			while (NextBlock(s)->size & S_FREE_MASK) {
-				s->size += NextBlock(s)->size & ~S_FREE_MASK;
+			/* And coalesce adjacent free blocks */
+			for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) {
+				if (s->size & S_FREE_MASK) {
+					while (NextBlock(s)->size & S_FREE_MASK) {
+						s->size += NextBlock(s)->size & ~S_FREE_MASK;
+					}
+				}
 			}
 		}
 	}
@@ -494,7 +534,7 @@
 	/* Align this to correct boundary. This also makes sure at least one
 	 * bit is not used, so we can use it for other things. */
 	mem_req = Align(mem_req, S_FREE_MASK + 1);
-
+	DEBUG(sprite, 3, "AllocSprite, memreq=" PRINTF_SIZE, mem_req);
 	for (;;) {
 		MemBlock *s;
 
@@ -581,6 +621,7 @@
 {
 	assert(IsMapgenSpriteID(sprite) == (type == ST_MAPGEN));
 	assert(type < ST_INVALID);
+	ZoomLevel zoom;
 
 	if (!SpriteExists(sprite)) {
 		DEBUG(sprite, 1, "Tried to load non-existing sprite #%d. Probable cause: Wrong/missing NewGRFs", sprite);
@@ -599,10 +640,12 @@
 		/* Update LRU */
 		sc->lru = ++_sprite_lru_counter;
 
+	zoom = ZoomLevel(_cur_dpi->zoom);
+	void *p = sc->ptr[zoom];
 		/* Load the sprite, if it is not loaded, yet */
-		if (sc->ptr == NULL) sc->ptr = ReadSprite(sc, sprite, type, AllocSprite);
+		if (p == NULL) p = ReadSprite(sc, sprite, type, AllocSprite);
 
-		return sc->ptr;
+		return p;
 	} else {
 		/* Do not use the spritecache, but a different allocator. */
 		return ReadSprite(sc, sprite, type, allocator);
@@ -629,7 +672,6 @@
 	free(_spritecache);
 	_spritecache_items = 0;
 	_spritecache = NULL;
-
 	_compact_cache_counter = 0;
 }
 
diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp
--- a/src/spriteloader/grf.cpp
+++ b/src/spriteloader/grf.cpp
@@ -41,7 +41,7 @@
 	return false;
 }
 
-bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type)
+bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, ZoomLevel zoom)
 {
 	/* Open the right file and go to the correct position */
 	FioSeekToFile(file_slot, file_pos);
diff --git a/src/spriteloader/grf.hpp b/src/spriteloader/grf.hpp
--- a/src/spriteloader/grf.hpp
+++ b/src/spriteloader/grf.hpp
@@ -17,7 +17,7 @@
 /** Sprite loader for graphics coming from a (New)GRF. */
 class SpriteLoaderGrf : public SpriteLoader {
 public:
-	bool LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type);
+	bool LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, ZoomLevel zoom);
 };
 
 #endif /* SPRITELOADER_GRF_HPP */
diff --git a/src/spriteloader/png.cpp b/src/spriteloader/png.cpp
--- a/src/spriteloader/png.cpp
+++ b/src/spriteloader/png.cpp
@@ -35,23 +35,30 @@
 	DEBUG(sprite, 0, "WARNING (libpng): %s - %s", message, (char *)png_get_error_ptr(png_ptr));
 }
 
-static bool OpenPNGFile(const char *filename, uint32 id, bool mask)
+static bool OpenPNGFile(const char *filename, uint32 id, bool mask, ZoomLevel zoom)
 {
 	char png_file[MAX_PATH];
 
 	/* Add path separator after 'sprites' if not present */
 	const char *sep = (filename[0] == PATHSEPCHAR) ? "" : PATHSEP;
-	snprintf(png_file, sizeof(png_file), "sprites%s%s" PATHSEP "%d%s.png", sep, filename, id, mask ? "m" : "");
+	snprintf(png_file, sizeof(png_file), "sprites%s%s" PATHSEP "%d_%s%d%s.png", sep, filename, id, "z", zoom, mask ? "m" : "");
 	if (FioCheckFileExists(png_file, NEWGRF_DIR)) {
 		FioOpenFile(PNG_SLOT, png_file, NEWGRF_DIR);
 		return true;
 	}
-
+	/* if failed, try to find it in the trunk tars, only for default zoom */
+	if ( zoom == ZOOM_LVL_NORMAL) {
+		snprintf(png_file, sizeof(png_file), "sprites%s%s" PATHSEP "%d%s.png", sep, filename, id, mask ? "m" : "");
+		if (FioCheckFileExists(png_file, NEWGRF_DIR)) {
+			FioOpenFile(PNG_SLOT, png_file, NEWGRF_DIR);
+			return true;
+		}
+	}
 	/* TODO -- Add TAR support */
 	return false;
 }
 
-static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, volatile bool mask)
+static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, volatile bool mask, ZoomLevel zoom)
 {
 	png_byte header[8];
 	png_structp png_ptr;
@@ -60,7 +67,7 @@
 	uint i, pixelsize;
 	SpriteLoader::CommonPixel *dst;
 
-	if (!OpenPNGFile(filename, id, mask)) return mask; // If mask is true, and file not found, continue true anyway, as it isn't a show-stopper
+	if (!OpenPNGFile(filename, id, mask, zoom)) return mask; // If mask is true, and file not found, continue true anyway, as it isn't a show-stopper
 
 	/* Check the header */
 	FioReadBlock(header, 8);
@@ -126,13 +133,16 @@
 	bit_depth  = png_get_bit_depth(png_ptr, info_ptr);
 	colour_type = png_get_color_type(png_ptr, info_ptr);
 
-	if (mask && (bit_depth != 8 || colour_type != PNG_COLOR_TYPE_PALETTE)) {
+	if (mask && colour_type != PNG_COLOR_TYPE_PALETTE) {
 		DEBUG(misc, 0, "Ignoring mask for SpriteID %d as it isn't a 8 bit palette image", id);
 		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 		return true;
 	}
+	/* Convert mask file with bit depth of 1, 2 or 4 into 8 bits */
+	if (mask && bit_depth < 8 && colour_type == PNG_COLOR_TYPE_PALETTE) {
+		png_set_packing(png_ptr);
+	}
 
-	bool win_palette = false;
 	if (!mask) {
 		if (bit_depth == 16) png_set_strip_16(png_ptr);
 
@@ -186,13 +196,12 @@
 		for (uint x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) {
 			if (mask) {
 				if (row_pointer[x * sizeof(uint8)] != 0) {
-					dst[x].r = 0;
-					dst[x].g = 0;
-					dst[x].b = 0;
-					/* Alpha channel is used from the original image (to allow transparency in remap colours) */
-					extern const byte _palmap_w2d[];
-					byte color = row_pointer[x * sizeof(uint8)];
-					dst[x].m = win_palette ? _palmap_w2d[color] : color;
+					/* Force the value of the palette if it is not in the correct range */
+					if (bit_depth < 8 && (row_pointer[x * sizeof(uint8)] < 196 || row_pointer[x * sizeof(uint8)] > 203)) {
+						dst[x].m = 199;
+					} else {
+						dst[x].m = row_pointer[x * sizeof(uint8)];
+					}
 				}
 			} else {
 				dst[x].r = row_pointer[x * sizeof(uint32) + 0];
diff --git a/src/spriteloader/png.hpp b/src/spriteloader/png.hpp
--- a/src/spriteloader/png.hpp
+++ b/src/spriteloader/png.hpp
@@ -17,7 +17,7 @@
 /** Sprite loader for graphics coming from a PNG image. */
 class SpriteLoaderPNG : public SpriteLoader {
 public:
-	bool LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type);
+	bool LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, ZoomLevel zoom);
 };
 
 #endif /* SPRITELOADER_PNG_HPP */
diff --git a/src/spriteloader/spriteloader.hpp b/src/spriteloader/spriteloader.hpp
--- a/src/spriteloader/spriteloader.hpp
+++ b/src/spriteloader/spriteloader.hpp
@@ -59,7 +59,8 @@
 	 * @param sprite_type The type of sprite we're trying to load.
 	 * @return true iff loading went okay.
 	 */
-	virtual bool LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type) = 0;
+
+	virtual bool LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, ZoomLevel zoom) = 0;
 
 	virtual ~SpriteLoader() { }
 };
diff --git a/src/table/sprites.h b/src/table/sprites.h
--- a/src/table/sprites.h
+++ b/src/table/sprites.h
@@ -1456,7 +1456,7 @@
 	RECOLOUR_BIT = 30,          ///< toggles recolouring in the sprite
 	CUSTOM_BIT = 29,
 	OPAQUE_BIT = 28,
-
+	SHADOW_BIT = 27,
 	PALETTE_WIDTH = 24,         ///< number of bits of the sprite containing the recolour palette
 	SPRITE_WIDTH = 24,          ///< number of bits for the sprite number
 };
@@ -1474,6 +1474,7 @@
 	SPRITE_MODIFIER_OPAQUE        = OPAQUE_BIT,      ///< Set when a sprite must not ever be displayed transparently
 	PALETTE_MODIFIER_TRANSPARENT  = TRANSPARENT_BIT, ///< when a sprite is to be displayed transparently, this bit needs to be set.
 	PALETTE_MODIFIER_COLOUR       = RECOLOUR_BIT,    ///< this bit is set when a recolouring process is in action
+	PALETTE_MODIFIER_SHADOW       = SHADOW_BIT,
 };
 
 /**
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -951,9 +951,6 @@
 
 	if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 
-	/* Check whether the vehicle shall be transparent due to the game state */
-	bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
-
 	if (v->type == VEH_EFFECT) {
 		/* Check whether the vehicle shall be transparent/invisible due to GUI settings.
 		 * However, transparent smoke and bubbles look weird, so always hide them. */
@@ -1003,11 +1000,7 @@
 			const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
 
 			while (v != NULL) {
-				if (!(v->vehstatus & VS_HIDDEN) &&
-						l <= v->coord.right &&
-						t <= v->coord.bottom &&
-						r >= v->coord.left &&
-						b >= v->coord.top) {
+				if (!(v->vehstatus & VS_HIDDEN) ) {
 					DoDrawVehicle(v);
 				}
 				v = v->next_hash;
@@ -1034,8 +1027,8 @@
 
 	if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
 
-	x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
-	y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
+	x = ScaleByZoom(x + vp->virtual_left, vp->zoom);
+	y = ScaleByZoom(y + vp->virtual_top, vp->zoom) ;
 
 	FOR_ALL_VEHICLES(v) {
 		if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
diff --git a/src/viewport.cpp b/src/viewport.cpp
--- a/src/viewport.cpp
+++ b/src/viewport.cpp
@@ -126,7 +126,7 @@
 /** Data structure storing rendering information */
 struct ViewportDrawer {
 	DrawPixelInfo dpi;
-
+	const ViewPort *vp;
 	StringSpriteToDrawVector string_sprites_to_draw;
 	TileSpriteToDrawVector tile_sprites_to_draw;
 	ParentSpriteToDrawVector parent_sprites_to_draw;
@@ -293,16 +293,16 @@
 	int i;
 	int left, top, width, height;
 
-	vp->virtual_left = x;
-	vp->virtual_top = y;
 
 	/* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower)
 	 * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL)
 	 */
-	old_left = UnScaleByZoomLower(old_left, vp->zoom);
-	old_top = UnScaleByZoomLower(old_top, vp->zoom);
-	x = UnScaleByZoomLower(x, vp->zoom);
-	y = UnScaleByZoomLower(y, vp->zoom);
+
+	x = UnScaleByZoom(x, vp->zoom);
+	y = UnScaleByZoom(y, vp->zoom);
+
+	vp->virtual_left = x;
+	vp->virtual_top  = y;
 
 	old_left -= x;
 	old_top -= y;
@@ -604,10 +604,13 @@
 	Point pt = RemapCoords(x, y, z);
 	const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL);
 
-	if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width ||
-			pt.x + spr->x_offs + spr->width <= _vd.dpi.left ||
-			pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height ||
-			pt.y + spr->y_offs + spr->height <= _vd.dpi.top)
+	int xu = UnScaleByZoom(pt.x, _vd.dpi.zoom);
+	int yu = UnScaleByZoom(pt.y, _vd.dpi.zoom);
+
+	if (xu + spr->x_offs >= _vd.vp->virtual_left + _vd.vp->width ||
+		 xu + spr->x_offs + spr->width <= _vd.vp->virtual_left ||
+		 yu + spr->y_offs >= _vd.vp->virtual_top + _vd.vp->height ||
+		 yu + spr->y_offs + spr->height <= _vd.vp->virtual_top)
 		return;
 
 	const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1;
@@ -648,7 +651,6 @@
 	/* make the sprites transparent with the right palette */
 	if (transparent) {
 		SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
-		pal = PALETTE_TO_TRANSPARENT;
 	}
 
 	if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) {
@@ -669,10 +671,16 @@
 		bottom          = RemapCoords(x + w          , y + h          , z + bb_offset_z).y + 1;
 	} else {
 		const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL);
-		left = tmp_left = (pt.x += spr->x_offs);
-		right           = (pt.x +  spr->width );
-		top  = tmp_top  = (pt.y += spr->y_offs);
-		bottom          = (pt.y +  spr->height);
+		int x_offs, y_offs,swidth, sheight;
+
+		x_offs = ScaleByZoom(spr->x_offs, _vd.vp->zoom);
+		y_offs = ScaleByZoom(spr->y_offs, _vd.vp->zoom);
+		swidth = ScaleByZoom(spr->width, _vd.vp->zoom);
+		sheight = ScaleByZoom(spr->height, _vd.vp->zoom);
+		left = tmp_left = (pt.x += x_offs);
+		right = (pt.x +  swidth );
+		top  = tmp_top  = (pt.y += y_offs);
+		bottom = (pt.y +  sheight);
 	}
 
 	if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
@@ -684,10 +692,10 @@
 	}
 
 	/* Do not add the sprite to the viewport, if it is outside */
-	if (left   >= _vd.dpi.left + _vd.dpi.width ||
-	    right  <= _vd.dpi.left                 ||
-	    top    >= _vd.dpi.top + _vd.dpi.height ||
-	    bottom <= _vd.dpi.top) {
+	if (UnScaleByZoom(left, _vd.vp->zoom)    >= _vd.vp->virtual_left + _vd.vp->width ||
+		 UnScaleByZoom(right, _vd.vp->zoom)  <= _vd.vp->virtual_left ||
+		 UnScaleByZoom(top, _vd.vp->zoom)    >= _vd.vp->virtual_top + _vd.vp->height  ||
+		 UnScaleByZoom(bottom, _vd.vp->zoom) <= _vd.vp->virtual_top) {
 		return;
 	}
 
@@ -804,7 +812,6 @@
 	/* make the sprites transparent with the right palette */
 	if (transparent) {
 		SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
-		pal = PALETTE_TO_TRANSPARENT;
 	}
 
 	*_vd.last_child = _vd.child_screen_sprites_to_draw.Length();
@@ -813,8 +820,8 @@
 	cs->image = image;
 	cs->pal = pal;
 	cs->sub = sub;
-	cs->x = x;
-	cs->y = y;
+	cs->x = UnScaleByZoom(x, _vd.dpi.zoom);
+	cs->y = UnScaleByZoom(y, _vd.dpi.zoom);
 	cs->next = -1;
 
 	/* Append the sprite to the active ChildSprite list.
@@ -1059,7 +1066,7 @@
 		int width_cur = width;
 		uint x_cur = x;
 		uint y_cur = y;
-
+		nof_sprites_drawn = 0;
 		do {
 			TileType tt = MP_VOID;
 
@@ -1089,22 +1096,17 @@
 				}
 			}
 
-			_vd.foundation_part = FOUNDATION_PART_NONE;
-			_vd.foundation[0] = -1;
-			_vd.foundation[1] = -1;
-			_vd.last_foundation_child[0] = NULL;
-			_vd.last_foundation_child[1] = NULL;
-
-			_tile_type_procs[tt]->draw_tile_proc(&ti);
-
-			if ((x_cur == (int)MapMaxX() * TILE_SIZE && IsInsideMM(y_cur, 0, MapMaxY() * TILE_SIZE + 1)) ||
-					(y_cur == (int)MapMaxY() * TILE_SIZE && IsInsideMM(x_cur, 0, MapMaxX() * TILE_SIZE + 1))) {
-				TileIndex tile = TileVirtXY(x_cur, y_cur);
-				ti.tile = tile;
-				ti.tileh = GetTilePixelSlope(tile, &ti.z);
-				tt = GetTileType(tile);
+			pt = RemapCoords(ti.x,ti.y,ti.z);
+			if (pt.y < bottom) {
+				_vd.foundation_part = FOUNDATION_PART_NONE;
+				_vd.foundation[0] = -1;
+				_vd.foundation[1] = -1;
+				_vd.last_foundation_child[0] = NULL;
+				_vd.last_foundation_child[1] = NULL;
+				_tile_type_procs[tt]->draw_tile_proc(&ti);
+				if (ti.tile != INVALID_TILE) DrawTileSelection(&ti);
+				nof_sprites_drawn++;
 			}
-			if (ti.tile != INVALID_TILE) DrawTileSelection(&ti);
 
 			y_cur += 0x10;
 			x_cur -= 0x10;
@@ -1115,7 +1117,7 @@
 		} else {
 			x += 0x10;
 		}
-	} while (--height);
+	} while (nof_sprites_drawn || (pt.y < top));
 }
 
 /**
@@ -1140,6 +1142,13 @@
 	int sign_height     = ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM, dpi->zoom);
 	int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom);
 
+
+	left = ScaleByZoom(_vd.vp->virtual_left  + dpi->left, dpi->zoom);
+	top =  ScaleByZoom(_vd.vp->virtual_top  + dpi->top, dpi->zoom);
+	right = left + ScaleByZoom(dpi->width, dpi->zoom);
+	bottom = top + ScaleByZoom(dpi->height, dpi->zoom);
+
+
 	if (bottom < sign->top ||
 			top   > sign->top + sign_height ||
 			right < sign->center - sign_half_width ||
@@ -1346,13 +1355,27 @@
  */
 static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
 {
+	ZoomLevel zoom = _cur_dpi->zoom;
+
 	const ParentSpriteToDraw * const *psd_end = psd->End();
 	for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) {
 		const ParentSpriteToDraw *ps = *it;
-		Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner
-		Point pt2 = RemapCoords(ps->xmin    , ps->ymax + 1, ps->zmax + 1); // top left corner
-		Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin    , ps->zmax + 1); // top right corner
-		Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin    ); // bottom front corner
+
+		Point pt1 = RemapCoords(ps->xmax, ps->ymax, ps->zmax); // top front corner
+		Point pt2 = RemapCoords(ps->xmin, ps->ymax, ps->zmax); // top left corner
+		Point pt3 = RemapCoords(ps->xmax, ps->ymin, ps->zmax); // top right corner
+		Point pt4 = RemapCoords(ps->xmax, ps->ymax, ps->zmin); // bottom front corner
+
+
+		pt1.x = UnScaleByZoom(pt1.x, zoom) - _vd.vp->virtual_left;
+		pt1.y = UnScaleByZoom(pt1.y, zoom) - _vd.vp->virtual_top;
+		pt2.x = UnScaleByZoom(pt2.x, zoom) - _vd.vp->virtual_left;
+		pt2.y = UnScaleByZoom(pt2.y, zoom) - _vd.vp->virtual_top;
+		pt3.x = UnScaleByZoom(pt3.x, zoom) - _vd.vp->virtual_left;
+		pt3.y = UnScaleByZoom(pt3.y, zoom) - _vd.vp->virtual_top;
+		pt4.x = UnScaleByZoom(pt4.x, zoom) - _vd.vp->virtual_left;
+		pt4.y = UnScaleByZoom(pt4.y, zoom) - _vd.vp->virtual_top;
+
 
 		DrawBox(        pt1.x,         pt1.y,
 		        pt2.x - pt1.x, pt2.y - pt1.y,
@@ -1370,20 +1393,17 @@
 	dp = *dpi;
 
 	zoom = dp.zoom;
+	zoom = _vd.vp->zoom;
 	dp.zoom = ZOOM_LVL_NORMAL;
 
-	dp.left   = UnScaleByZoom(dp.left,   zoom);
-	dp.top    = UnScaleByZoom(dp.top,    zoom);
-	dp.width  = UnScaleByZoom(dp.width,  zoom);
-	dp.height = UnScaleByZoom(dp.height, zoom);
-
 	const StringSpriteToDraw *ssend = sstdv->End();
 	for (const StringSpriteToDraw *ss = sstdv->Begin(); ss != ssend; ++ss) {
 		TextColour colour = TC_BLACK;
 		bool small = HasBit(ss->width, 15);
 		int w = GB(ss->width, 0, 15);
-		int x = UnScaleByZoom(ss->x, zoom);
-		int y = UnScaleByZoom(ss->y, zoom);
+
+		int x = UnScaleByZoom(ss->x, zoom) - _vd.vp->virtual_left;
+		int y = UnScaleByZoom(ss->y, zoom) - _vd.vp->virtual_top;
 		int h = VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM;
 
 		SetDParam(0, ss->params[0]);
@@ -1410,7 +1430,6 @@
 				);
 			}
 		}
-
 		DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss->string, colour, SA_HOR_CENTER);
 	}
 }
@@ -1418,27 +1437,41 @@
 void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom)
 {
 	DrawPixelInfo *old_dpi = _cur_dpi;
+	DrawPixelInfo tmp_dpi;
+
 	_cur_dpi = &_vd.dpi;
+	_cur_dpi->zoom = vp->zoom;
+
+
+	int x = left;
+	int y = top;
+
+	left = left - vp->left;
+	top  = top - vp->top;
+	right = right - vp->left;
+	bottom = bottom - vp->top;
 
 	_vd.dpi.zoom = vp->zoom;
-	int mask = ScaleByZoom(-1, vp->zoom);
-
 	_vd.combine_sprites = SPRITE_COMBINE_NONE;
-
-	_vd.dpi.width = (right - left) & mask;
-	_vd.dpi.height = (bottom - top) & mask;
-	_vd.dpi.left = left & mask;
-	_vd.dpi.top = top & mask;
+	_vd.dpi.width = (right - left) ;
+	_vd.dpi.height = (bottom - top) ;
+	_vd.dpi.left = left ;
+	_vd.dpi.top = top ;
 	_vd.dpi.pitch = old_dpi->pitch;
 	_vd.last_child = NULL;
-
-	int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
-	int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
-
+	_vd.vp = vp;
 	_vd.dpi.dst_ptr = BlitterFactoryBase::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
 
 	ViewportAddLandscape();
-	ViewportAddVehicles(&_vd.dpi);
+
+	tmp_dpi = _vd.dpi;
+	tmp_dpi.left = ScaleByZoom(vp->virtual_left, vp->zoom);
+	tmp_dpi.top = ScaleByZoom(vp->virtual_top, vp->zoom);
+	tmp_dpi.width = ScaleByZoom(vp->width, vp->zoom);
+	tmp_dpi.height = ScaleByZoom(vp->height, vp->zoom);
+
+	ViewportAddVehicles(&tmp_dpi);
+	DrawTextEffects(&tmp_dpi);
 
 	ViewportAddTownNames(&_vd.dpi);
 	ViewportAddStationNames(&_vd.dpi);
@@ -1486,12 +1519,7 @@
 			ViewportDrawChk(vp, t, top, right, bottom);
 		}
 	} else {
-		ViewportDoDraw(vp,
-			ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
-			ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top,
-			ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left,
-			ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top
-		);
+		ViewportDoDraw(vp, left, top, right, bottom);
 	}
 }
 
@@ -1603,26 +1631,29 @@
  */
 static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
 {
-	right -= vp->virtual_left;
+	left = UnScaleByZoom(left, vp->zoom);
+	top  = UnScaleByZoom(top, vp->zoom);
+	right = UnScaleByZoom(right, vp->zoom);
+	bottom = UnScaleByZoom(bottom, vp->zoom);
+
+	int vl = vp->virtual_left;
+	int vt = vp->virtual_top;
+	int w  = vp->width;
+	int h  = vp->height;
+
+	left = max(0, left - vl);
+	if (left >= w) return;
+
+	top = max(0, top - vt);
+	if (top >= h ) return;
+
+	right -= vl;
 	if (right <= 0) return;
 
-	bottom -= vp->virtual_top;
+	bottom -= vt;
 	if (bottom <= 0) return;
 
-	left = max(0, left - vp->virtual_left);
-
-	if (left >= vp->virtual_width) return;
-
-	top = max(0, top - vp->virtual_top);
-
-	if (top >= vp->virtual_height) return;
-
-	SetDirtyBlocks(
-		UnScaleByZoomLower(left, vp->zoom) + vp->left,
-		UnScaleByZoomLower(top, vp->zoom) + vp->top,
-		UnScaleByZoom(right, vp->zoom) + vp->left + 1,
-		UnScaleByZoom(bottom, vp->zoom) + vp->top + 1
-	);
+	SetDirtyBlocks(left + vp->left, top + vp->top, right + vp->left, bottom + vp->top);
 }
 
 /**
@@ -1813,8 +1844,8 @@
 	int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom);
 	int sign_height = ScaleByZoom(VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM, vp->zoom);
 
-	x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left;
-	y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top;
+	x = ScaleByZoom(x - vp->left + vp->virtual_left, vp->zoom);
+	y = ScaleByZoom(y - vp->top + vp->virtual_top, vp->zoom);
 
 	return y >= sign->top && y < sign->top + sign_height &&
 			x >= sign->center - sign_half_width && x < sign->center + sign_half_width;
diff --git a/src/window.cpp b/src/window.cpp
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -564,7 +564,9 @@
 void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
 {
 	Window *w;
-	DrawPixelInfo bk;
+	DrawPixelInfo bk, *old_dpi;
+	old_dpi = _cur_dpi;
+	/* GT TODO: find out why the game signals 11 if we don't backup _cur_dpi here */
 	_cur_dpi = &bk;
 
 	FOR_ALL_WINDOWS_FROM_BACK(w) {
@@ -577,6 +579,7 @@
 			DrawOverlappedWindow(w, left, top, right, bottom);
 		}
 	}
+	_cur_dpi = old_dpi;
 }
 
 /**
diff --git a/src/zoom_type.h b/src/zoom_type.h
--- a/src/zoom_type.h
+++ b/src/zoom_type.h
@@ -20,8 +20,10 @@
 /** All zoom levels we know. */
 enum ZoomLevel {
 	/* Our possible zoom-levels */
-	ZOOM_LVL_BEGIN  = 0, ///< Begin for iteration.
-	ZOOM_LVL_NORMAL = 0, ///< The normal zoom level.
+	ZOOM_LVL_BEGIN = 0,  ///< Begin for iteration.
+	ZOOM_LVL_IN_4X = 0,
+	ZOOM_LVL_IN_2X,
+	ZOOM_LVL_NORMAL,     ///< The normal zoom level.
 	ZOOM_LVL_OUT_2X,     ///< Zoomed 2 times out.
 	ZOOM_LVL_OUT_4X,     ///< Zoomed 4 times out.
 	ZOOM_LVL_OUT_8X,     ///< Zoomed 8 times out.
