diff -r a88d0ef8a898 findversion.sh
--- a/findversion.sh	Thu Mar 31 21:21:50 2011 +0000
+++ b/findversion.sh	Tue Apr 12 16:44:09 2011 +0000
@@ -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@qparent@@" | cut -f1 -d' '`"
+		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
@@ -134,14 +141,10 @@
 	REV_NR=""
 fi
 
-if [ "$MODIFIED" -eq "2" ]; then
-	REV="${REV}M"
-fi
-
 CLEAN_REV=${REV}
 
 if [ -n "$BRANCH" ]; then
 	REV="${REV}-$BRANCH"
 fi
 
-echo "$REV	$REV_NR	$MODIFIED	$CLEAN_REV"
+echo "$REV	$REV_NR	$MODIFIED	r$REV_NR"
diff -r a88d0ef8a898 src/blitter/32bpp_base.hpp
--- a/src/blitter/32bpp_base.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/blitter/32bpp_base.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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;
 
 class Blitter_32bppBase : public Blitter {
 public:
@@ -104,6 +109,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 -r a88d0ef8a898 src/blitter/32bpp_optimized.cpp
--- a/src/blitter/32bpp_optimized.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/blitter/32bpp_optimized.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -10,10 +10,20 @@
 /** @file 32bpp_optimized.cpp Implementation of the optimized 32 bpp blitter. */
 
 #include "../stdafx.h"
+#include "../core/alloc_func.hpp"
 #include "../zoom_func.h"
 #include "../core/math_func.hpp"
 #include "32bpp_optimized.hpp"
 
+static const int MAX_PALETTE_TABLES = 50;
+
+struct RecolourTable {
+	SpriteID   id;
+	Colour     tables[256];
+} _rgb_palettes[MAX_PALETTE_TABLES] = {{0,{{0}}}};
+
+Colour _rgb_stringremap[3] = {{0}};
+
 static FBlitter_32bppOptimized iFBlitter_32bppOptimized;
 
 /**
@@ -30,6 +40,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,
@@ -46,8 +57,7 @@
 	uint32 *dst = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left;
 
 	/* store so we don't have to access it via bp everytime (compiler assumes pointer aliasing) */
-	const byte *remap = bp->remap;
-
+	const Colour *remap = (const Colour *)bp->remap;
 	for (int y = 0; y < bp->height; y++) {
 		/* next dst line begins here */
 		uint32 *dst_ln = dst + bp->pitch;
@@ -110,42 +120,70 @@
 
 			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 {
-								uint r = remap[m];
-								if (r != 0) *dst = this->LookupColourInPalette(r);
+								*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *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 {
+							Colour r = remap[m];
+							if (r.a != 0) {
+								uint src_col = ComposeColour(src_px->a, src_px->r, src_px->g, src_px->b);
+								uint comp_col = ComposeColourBlend(r.data, src_col);
+								*dst = ComposeColourPA(comp_col, src_px->a, *dst);
 							}
-							dst++;
-							src_px++;
-							src_n++;
-						} while (--n != 0);
-					}
+						}
+						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 {
+							Colour r = remap[m];
+							if (r.a != 0) {
+								*dst = ComposeColourPA(r.data, src_px->a, *dst);
+							}
+						}
+						dst++;
+						src_px++;
+						src_n++;
+					} while (--n != 0);
+					break;
+				case BM_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){
+								Colour r = remap[m];
+								if (r.a != 0) *dst = ComposeColourPA(r.data, src_px->a / 2, *dst);
+							}
+							else {
+								*dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
+							}
+						}
 
-				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;
@@ -160,8 +198,8 @@
 							src_px++;
 						} while (--n != 0);
 					}
+
 					break;
-
 				default:
 					if (src_px->a == 255) {
 						/* faster than memcpy(), n is usually low */
@@ -182,7 +220,6 @@
 					break;
 			}
 		}
-
 		dst = dst_ln;
 		src_px = src_px_ln;
 		src_n  = src_n_ln;
@@ -198,61 +235,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)
@@ -273,7 +275,7 @@
 	/* lengths of streams */
 	uint32 lengths[ZOOM_LVL_COUNT][2];
 
-	for (ZoomLevel z = ZOOM_LVL_BEGIN; z < ZOOM_LVL_END; z++) {
+	for (ZoomLevel z = ZOOM_LVL_BEGIN; z <= ZOOM_LVL_BEGIN; z++) {
 		const SpriteLoader::Sprite *src_orig = ResizeSprite(sprite, z);
 
 		uint size = src_orig->height * src_orig->width;
@@ -313,17 +315,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) {
@@ -352,12 +348,10 @@
 		lengths[z][0] = (byte *)dst_px_ln - (byte *)dst_px_orig[z]; // all are aligned to 4B boundary
 		lengths[z][1] = (byte *)dst_n_ln  - (byte *)dst_n_orig[z];
 
-		free(src_orig->data);
-		free((void *)src_orig);
 	}
 
 	uint len = 0; // total length of data
-	for (ZoomLevel z = ZOOM_LVL_BEGIN; z < ZOOM_LVL_END; z++) {
+	for (ZoomLevel z = ZOOM_LVL_BEGIN; z <= ZOOM_LVL_BEGIN; z++) {
 		len += lengths[z][0] + lengths[z][1];
 	}
 
@@ -370,16 +364,367 @@
 
 	SpriteData *dst = (SpriteData *)dest_sprite->data;
 
-	for (ZoomLevel z = ZOOM_LVL_BEGIN; z < ZOOM_LVL_END; z++) {
-		dst->offset[z][0] = z == ZOOM_LVL_BEGIN ? 0 : lengths[z - 1][1] + dst->offset[z - 1][1];
-		dst->offset[z][1] = lengths[z][0] + dst->offset[z][0];
+	ZoomLevel z = ZOOM_LVL_BEGIN;
+	dst->offset[z][0] = 0;
+	dst->offset[z][1] = lengths[z][0] + dst->offset[z][0];
 
-		memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]);
-		memcpy(dst->data + dst->offset[z][1], dst_n_orig[z],  lengths[z][1]);
+	memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]);
+	memcpy(dst->data + dst->offset[z][1], dst_n_orig[z],  lengths[z][1]);
 
-		free(dst_px_orig[z]);
-		free(dst_n_orig[z]);
-	}
+	free(dst_px_orig[z]);
+	free(dst_n_orig[z]);
 
 	return dest_sprite;
 }
+
+void Blitter_32bppOptimized::RescaleSpriteHalfSize(const SpriteLoader::Sprite *src_sprite,
+																			SpriteLoader::Sprite *dest_sprite,
+																			bool                 prevent_alpha_bleeding)
+{
+	SpriteLoader::CommonPixel *dst;
+	SpriteLoader::CommonPixel *src;
+	int width, height;
+	int x, y;
+	bool  extra_px_x = false;
+	bool  extra_px_y = false;
+
+	SpriteLoader::CommonPixel clr;
+
+	width = (src_sprite->width + 1) / 2;
+	height = (src_sprite->height + 1) / 2;
+
+	/* src sprite width is odd, just copy last pixel iso taking average */
+	if (src_sprite->width & 1) {
+		extra_px_x = true;
+	}
+	/* src sprite height is odd, just copy last pixel iso taking average */
+	if (src_sprite->height & 1) {
+		extra_px_y = true;
+	}
+
+
+	dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
+	dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
+	src = (SpriteLoader::CommonPixel *)src_sprite->data;
+
+	dest_sprite->width = width ;
+	dest_sprite->height = height;
+
+	dest_sprite->x_offs = src_sprite->x_offs / 2;
+	dest_sprite->y_offs = src_sprite->y_offs / 2;
+
+	for (y = 0; y < height + (extra_px_y ? -1 : 0); y++) {
+		for (x = 0; x < width + (extra_px_x ? -1 : 0); x++) {
+				uint ma = 0;
+				uint a = 0;
+				uint r = 0;
+				uint g = 0;
+				uint b = 0;
+				uint i;
+				uint j;
+
+				for (i = 0; i < 2; i++) {
+					for (j = 0; j < 2; j++) {
+						uint ca;
+						uint cr;
+						uint cg;
+						uint cb;
+
+						clr = src[((2 * y + i ) * src_sprite->width) + (2 * x + j )];
+						ca = clr.a;
+						cr = clr.r;
+						cg = clr.g;
+						cb = clr.b;
+
+						a += ca;
+						r += ca * cr;
+						g += ca * cg;
+						b += ca * cb;
+						if (prevent_alpha_bleeding) {
+							if (ca > ma) ma = ca;
+						} else {
+							ma += ca;
+						}
+					}
+				}
+
+				if (a == 0) {
+					dst[y * width + x].r = 0;
+					dst[y * width + x].g = 0;
+					dst[y * width + x].b = 0;
+					dst[y * width + x].a = 0;
+					dst[y * width + x].m = 0;
+				} else {
+					r /= a;
+					g /= a;
+					b /= a;
+					if (prevent_alpha_bleeding) {
+						a = ma;
+					} else {
+						a /= 4;
+					}
+					dst[y * width + x].r = r;
+					dst[y * width + x].g = g;
+					dst[y * width + x].b = b;
+					dst[y * width + x].a = a;
+					dst[y * width + x].m = clr.m;
+				}
+		}
+		if (extra_px_x) {
+			clr = src[((2 * y ) * src_sprite->width) + (2 * x)];
+			dst[y * width + x] = clr;
+		}
+	}
+
+}
+/*
+void Blitter_32bppOptimized::RescaleSpriteDoubleSizePrev(const SpriteLoader::Sprite *src_sprite,
+																			  SpriteLoader::Sprite *dest_sprite)
+{
+	int width, height;
+	SpriteLoader::CommonPixel *dst;
+	SpriteLoader::CommonPixel *src;
+
+	width = src_sprite->width * 2;
+	height = src_sprite->height * 2;
+
+	dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
+	dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
+	src = (SpriteLoader::CommonPixel *)src_sprite->data;
+
+	dest_sprite->width = width;
+	dest_sprite->height = height;
+	dest_sprite->x_offs = src_sprite->x_offs * 2;
+	dest_sprite->y_offs = src_sprite->y_offs * 2;
+
+	uint dst_y = 0;
+	uint src_y_idx = 0;
+	for (int y = 0; y < src_sprite->height - 1; y++) {
+	   int x;
+
+		uint dst_x = 0;
+		for (x = 0; x < src_sprite->width - 1; x++) {
+			dst[dst_y + dst_x] = src[src_y_idx + x];
+			dst_x++;
+			dst[dst_y + dst_x].r = (src[src_y_idx + x + 1].r + src[src_y_idx + x].r) / 2;
+			dst[dst_y + dst_x].g = (src[src_y_idx + x + 1].g + src[src_y_idx + x].g) / 2;
+			dst[dst_y + dst_x].b = (src[src_y_idx + x + 1].b + src[src_y_idx + x].b) / 2;
+			dst[dst_y + dst_x].a = (src[src_y_idx + x + 1].a + src[src_y_idx + x].a) / 2;
+			dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+			dst_x--;
+			dst_y += width;
+			dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r) / 2;
+			dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g) / 2;
+			dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b) / 2;
+			dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a) / 2;
+			dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+			dst_x++;
+			dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r +
+			                        src[src_y_idx + x + 1].r + src[src_y_idx + src_sprite->width + x + 1].r ) / 4;
+			dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g +
+			                        src[src_y_idx + x + 1].g + src[src_y_idx + src_sprite->width + x + 1].g ) / 4;
+			dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b +
+			                        src[src_y_idx + x + 1].b + src[src_y_idx + src_sprite->width + x + 1].b ) / 4;
+			dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a +
+			                        src[src_y_idx + x + 1].a + src[src_y_idx + src_sprite->width + x + 1].a ) / 4;
+			dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+			dst_y -= width;
+			dst_x++;
+		}
+
+		 last pixels in row cannot be interpolated */
+/*     dst[dst_y + dst_x] = src[src_y_idx + x];
+		dst_x++;
+		dst[dst_y + dst_x] = src[src_y_idx + x];
+		dst_x--;
+		dst_y += width;
+		dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r) / 2;
+		dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g) / 2;
+		dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b) / 2;
+		dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a) / 2;
+		dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+		dst_x++;
+		dst[dst_y + dst_x].r = (src[src_y_idx + x].r + src[src_y_idx + src_sprite->width + x].r) / 2;
+		dst[dst_y + dst_x].g = (src[src_y_idx + x].g + src[src_y_idx + src_sprite->width + x].g) / 2;
+		dst[dst_y + dst_x].b = (src[src_y_idx + x].b + src[src_y_idx + src_sprite->width + x].b) / 2;
+		dst[dst_y + dst_x].a = (src[src_y_idx + x].a + src[src_y_idx + src_sprite->width + x].a) / 2;
+		dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+
+		dst_y += width;
+		src_y_idx += src_sprite->width;
+	}
+	 last row can not be interpolated */
+/* uint dst_x = 0;
+	for (int x = 0; x < src_sprite->width - 1; x++) {
+		dst[dst_y + dst_x] = src[src_y_idx + x];
+		dst_x++;
+		dst[dst_y + dst_x].r = (src[src_y_idx + x + 1].r + src[src_y_idx + x].r) / 2;
+		dst[dst_y + dst_x].g = (src[src_y_idx + x + 1].g + src[src_y_idx + x].g) / 2;
+		dst[dst_y + dst_x].b = (src[src_y_idx + x + 1].b + src[src_y_idx + x].b) / 2;
+		dst[dst_y + dst_x].a = (src[src_y_idx + x + 1].a + src[src_y_idx + x].a) / 2;
+		dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+		dst_x--;
+		dst_y += width;
+		dst[dst_y + dst_x] = src[src_y_idx + x];
+		dst_x++;
+		dst[dst_y + dst_x].r = (src[src_y_idx + x + 1].r + src[src_y_idx + x].r) / 2;
+		dst[dst_y + dst_x].g = (src[src_y_idx + x + 1].g + src[src_y_idx + x].g) / 2;
+		dst[dst_y + dst_x].b = (src[src_y_idx + x + 1].b + src[src_y_idx + x].b) / 2;
+		dst[dst_y + dst_x].a = (src[src_y_idx + x + 1].a + src[src_y_idx + x].a) / 2;
+		dst[dst_y + dst_x].m =  src[src_y_idx + x].m;
+		dst_y -= width;
+		dst_x++;
+	}
+}
+
+*/
+
+void Blitter_32bppOptimized::RescaleSpriteDoubleSize(const SpriteLoader::Sprite *src_sprite,
+																			  SpriteLoader::Sprite *dest_sprite)
+{
+	int width, height;
+	SpriteLoader::CommonPixel *dst;
+	SpriteLoader::CommonPixel *src;
+
+	width = src_sprite->width * 2;
+	height = src_sprite->height * 2;
+
+	dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
+	dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
+	src = (SpriteLoader::CommonPixel *)src_sprite->data;
+
+	dest_sprite->width = width;
+	dest_sprite->height = height;
+	dest_sprite->x_offs = src_sprite->x_offs * 2;
+	dest_sprite->y_offs = src_sprite->y_offs * 2;
+	SpriteLoader::CommonPixel B, D, E, H, F;
+	SpriteLoader::CommonPixel E0, E1, E2, E3;
+	uint dst_y = 0;
+	uint src_y_idx = 0;
+	for (int y = 0; y < src_sprite->height ; y++) {
+		int x;
+
+		uint dst_x = 0;
+		for (x = 0; x < src_sprite->width - 1; x++) {
+			E = src[src_y_idx + x];
+			if (src_y_idx) {
+				B = src[src_y_idx + x - src_sprite->width];
+			} else {
+				B = src[src_y_idx + x];
+			}
+			if (x) {
+				D = src[src_y_idx + x - 1];
+			} else {
+				D = src[src_y_idx + x ];
+			}
+			if (x < src_sprite->width - 1){
+				F = src[src_y_idx + x + 1];
+			} else {
+				F = src[src_y_idx + x ];
+			}
+			if (y < src_sprite->height - 1){
+				H = src[src_y_idx + x + src_sprite->width];
+			} else {
+				H = src[src_y_idx + x];
+			}
+			if ((B.r != H.r && D.r != F.r) ||
+				(B.g != H.g && D.g != F.g) ||
+				(B.b != H.b && D.b != F.b) ||
+				(B.a != H.a && D.a != F.a))
+			 {
+				if ((D.r == B.r) &&
+					(D.g == B.g) &&
+					(D.b == B.b) &&
+					(D.a == B.a)) {
+					E0 = D;
+				} else {
+					E0 = E;
+				}
+				if ((B.r == F.r) &&
+					(B.g == F.g) &&
+					(B.b == F.b) &&
+					(B.a == F.a)) {
+					E1 = F;
+				} else {
+					E1 = E;
+				}
+				if ((D.r == H.r) &&
+					(D.g == H.g) &&
+					(D.b == H.b) &&
+					(D.a == H.a)) {
+					E2 = D;
+				} else {
+					E2 = E;
+				}
+				if ((H.r == F.r) &&
+					(H.g == F.g) &&
+					(H.b == F.b) &&
+					(H.a == F.a)) {
+					E3 = F;
+				} else {
+					E3 = E;
+				}
+			} else {
+				E0 = E;
+				E1 = E;
+				E2 = E;
+				E3 = E;
+			}
+			dst[dst_y + dst_x] = E0;
+			dst_x++;
+			dst[dst_y + dst_x] = E1;
+			dst_x--;
+			dst_y += width;
+			dst[dst_y + dst_x] = E2;
+			dst_x++;
+			dst[dst_y + dst_x] = E3;
+			dst_y -= width;
+			dst_x++;
+		}
+
+		dst_y += width;
+dst_y += width;
+		src_y_idx += src_sprite->width;
+	}
+}
+
+void Blitter_32bppOptimized::FillRGBFromPalette(SpriteLoader::Sprite *sprite)
+{
+	SpriteLoader::CommonPixel *spr = sprite->data;
+
+	for (uint y = 0; y < sprite->height; y++) {
+		uint y_idx  = y * sprite->width;
+		for (uint x = 0; x < sprite->width; x++) {
+			if (spr[y_idx + x].a == 0) {
+				spr[y_idx + x].r = 0;
+				spr[y_idx + x].g = 0;
+				spr[y_idx + x].b = 0;
+				spr[y_idx + x].m = 0;
+			} else {
+				if (spr[y_idx + x].m != 0) {
+					/* Pre-convert the mapping channel to a RGB value */
+					uint color = this->LookupColourInPalette(spr[y_idx + x].m);
+					spr[y_idx + x].r = GB(color, 16, 8);
+					spr[y_idx + x].g = GB(color, 8,  8);
+					spr[y_idx + x].b = GB(color, 0,  8);
+				}
+			}
+		}
+	}
+}
+
+byte *Blitter_32bppOptimized::FillRGBPalette(SpriteID id, byte *remap_data)
+{
+	for (int idx = 0; (idx < MAX_PALETTE_TABLES); idx++) {
+		if ((id == _rgb_palettes[idx].id) || (_rgb_palettes[idx].id == 0)) { 
+			_rgb_palettes[idx].id = id;
+			for (int col_idx = 0; col_idx < 256; col_idx++) { 
+				_rgb_palettes[idx].tables[col_idx].data = this->LookupColourInPalette(remap_data[col_idx + 1]);
+			}
+			return (byte *)&(_rgb_palettes[idx].tables[0]);
+		}
+	}
+	error("No more rgb palette tables available");
+	return NULL;
+}
+
diff -r a88d0ef8a898 src/blitter/32bpp_optimized.hpp
--- a/src/blitter/32bpp_optimized.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/blitter/32bpp_optimized.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -23,7 +23,13 @@
 
 	/* 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);
+					  byte *FillRGBPalette(SpriteID id, byte *remap_data);
 	/* virtual */ const char *GetName() { return "32bpp-optimized"; }
 
 	template <BlitterMode mode> void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
diff -r a88d0ef8a898 src/blitter/base.hpp
--- a/src/blitter/base.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/blitter/base.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -19,6 +19,8 @@
 	BM_NORMAL,
 	BM_COLOUR_REMAP,
 	BM_TRANSPARENT,
+	BM_COLOUR_OPAQUE,
+	BM_SHADOW
 };
 
 /**
@@ -38,6 +40,8 @@
 
 		void *dst;               ///< Destination buffer
 		int pitch;               ///< The pitch of the destination buffer
+		uint hue;
+		uint m;
 	};
 
 	enum PaletteAnimation {
diff -r a88d0ef8a898 src/blitter/factory.hpp
--- a/src/blitter/factory.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/blitter/factory.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -83,7 +83,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.
@@ -91,7 +91,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 -r a88d0ef8a898 src/company_gui.cpp
--- a/src/company_gui.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/company_gui.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -989,7 +989,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),
@@ -1417,7 +1417,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;
 		}
 	}
@@ -1574,6 +1581,7 @@
 	_nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets)
 );
 
+
 /**
  * Open the simple/advanced company manager face selection window
  *
diff -r a88d0ef8a898 src/elrail.cpp
--- a/src/elrail.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/elrail.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -418,7 +418,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 -r a88d0ef8a898 src/gfx.cpp
--- a/src/gfx.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/gfx.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -15,6 +15,7 @@
 #include "genworld.h"
 #include "zoom_func.h"
 #include "blitter/factory.hpp"
+#include "blitter/32bpp_optimized.hpp"
 #include "video/video_driver.hpp"
 #include "strings_func.h"
 #include "settings_type.h"
@@ -147,7 +148,7 @@
  */
 void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
 {
-	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
+	Blitter_32bppOptimized *blitter = (Blitter_32bppOptimized *)BlitterFactoryBase::GetCurrentBlitter();
 	const DrawPixelInfo *dpi = _cur_dpi;
 	void *dst;
 	const int otop = top;
@@ -264,18 +265,20 @@
 
 	static const byte colour = 15;
 
-	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);
 }
 
+Colour _string_colourremap_32bpp[3];
 /**
  * Set the colour remap to be for the given colour.
  * @param colour the new colour of the remap.
@@ -292,7 +295,11 @@
 
 	_string_colourremap[1] = raw_colour ? (byte)colour : _string_colourmap[_use_palette][colour];
 	_string_colourremap[2] = no_shade ? 0 : (_use_palette == PAL_DOS ? 1 : 215);
-	_colour_remap_ptr = _string_colourremap;
+	for (int i = 0; i < 3; i++) {
+		_string_colourremap_32bpp[i].data = _cur_palette[_string_colourremap[i]].data;
+	}	
+
+	_colour_remap_ptr = (byte *)_string_colourremap_32bpp;
 }
 
 #if !defined(WITH_ICU)
@@ -1066,7 +1073,6 @@
 
 switch_colour:;
 	SetColourRemap(params.cur_colour);
-
 check_bounds:
 	if (y + _max_char_height <= dpi->top || dpi->top + dpi->height <= y) {
 skip_char:;
@@ -1085,7 +1091,7 @@
 		if (IsPrintable(c) && !IsTextDirectionChar(c)) {
 			if (x >= dpi->left + dpi->width) goto skip_char;
 			if (x + _max_char_width >= dpi->left) {
-				GfxMainBlitter(GetGlyph(params.fontsize, c), x, y, BM_COLOUR_REMAP);
+				GfxMainBlitter(GetGlyph(params.fontsize, c), x, y, BM_COLOUR_OPAQUE);
 			}
 			x += GetCharacterWidth(params.fontsize, c);
 		} else if (c == '\n') { // newline = {}
@@ -1135,15 +1141,27 @@
  * @param y    Top coordinate of image
  * @param sub  If available, draw only specified part of the sprite
  */
-void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
+ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
 {
 	SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
 	if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
-		_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1;
+		if (pal != PAL_NONE) {
+			_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR);
+		}
+		else {
+			_colour_remap_ptr = NULL;
+		}
 		GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite);
+	} else if (HasBit(img, PALETTE_MODIFIER_SHADOW)){
+		GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_SHADOW, sub, real_sprite);
 	} else if (pal != PAL_NONE) {
-		_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1;
-		GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_REMAP, sub, real_sprite);
+		_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR);
+		memcpy(&_colour_remap_ptr, _colour_remap_ptr + 257, sizeof(_colour_remap_ptr));
+		if(pal >= PALETTE_RECOLOUR_START) {
+			GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_REMAP, sub, real_sprite);
+		} else {
+			GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_COLOUR_OPAQUE, sub, real_sprite);
+		}
 	} else {
 		GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite);
 	}
@@ -1171,15 +1189,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;
@@ -1193,43 +1212,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();
@@ -1673,7 +1692,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 -r a88d0ef8a898 src/main_gui.cpp
--- a/src/main_gui.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/main_gui.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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,
@@ -403,7 +407,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 -r a88d0ef8a898 src/openttd.cpp
--- a/src/openttd.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/openttd.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -452,6 +452,10 @@
 #endif
 	;
 
+	DrawPixelInfo dpi;
+	_cur_dpi = &dpi;
+	_cur_dpi->zoom = ZOOM_LVL_NORMAL;
+
 	MyGetOptData mgo(argc - 1, argv + 1, optformat);
 
 	while ((i = MyGetOpt(&mgo)) != -1) {
@@ -648,7 +652,9 @@
 
 	DEBUG(misc, 1, "Loading blitter...");
 	if (blitter == NULL && _ini_blitter != NULL) blitter = strdup(_ini_blitter);
-	if (BlitterFactoryBase::SelectBlitter(blitter) == NULL) {
+	DEBUG(misc, 1, "Force 32bpp-optimized blitter, needed for extra zoom patch");
+	blitter = strdup("32bpp-optimized");
+	if (BlitterFactoryBase::SelectBlitter(blitter) == NULL){
 		StrEmpty(blitter) ?
 			usererror("Failed to autoprobe blitter") :
 			usererror("Failed to select requested blitter '%s'; does it exist?", blitter);
diff -r a88d0ef8a898 src/rail_cmd.cpp
--- a/src/rail_cmd.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/rail_cmd.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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)
@@ -2671,12 +2671,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 -r a88d0ef8a898 src/road_cmd.cpp
--- a/src/road_cmd.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/road_cmd.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -1217,25 +1217,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;
@@ -1250,8 +1257,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 -r a88d0ef8a898 src/roadveh_cmd.cpp
--- a/src/roadveh_cmd.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/roadveh_cmd.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -372,14 +372,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 -r a88d0ef8a898 src/saveload/misc_sl.cpp
--- a/src/saveload/misc_sl.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/saveload/misc_sl.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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);
 
@@ -60,7 +60,6 @@
 	MarkWholeScreenDirty();
 }
 
-
 static const SaveLoadGlobVarList _date_desc[] = {
 	SLEG_CONDVAR(_date,                   SLE_FILE_U16 | SLE_VAR_I32,  0,  30),
 	SLEG_CONDVAR(_date,                   SLE_INT32,                  31, SL_MAX_VERSION),
diff -r a88d0ef8a898 src/sound.cpp
--- a/src/sound.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/sound.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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"
@@ -178,7 +179,7 @@
 }
 
 
-static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
+static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
 
 static const byte _sound_base_vol[] = {
@@ -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 -r a88d0ef8a898 src/sprite.h
--- a/src/sprite.h	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/sprite.h	Tue Apr 12 16:44:09 2011 +0000
@@ -130,7 +130,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 -r a88d0ef8a898 src/spritecache.cpp
--- a/src/spritecache.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spritecache.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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,17 +19,19 @@
 #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"
 
 /* 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;
@@ -61,6 +65,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;
@@ -188,6 +196,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);
 
@@ -197,10 +212,27 @@
 #ifdef WITH_PNG
 		/* Try loading 32bpp graphics in case we are 32bpp output */
 		SpriteLoaderPNG sprite_loader;
-		SpriteLoader::Sprite sprite;
+		SpriteLoader::Sprite sprite, dst_sprite;
 
-		if (sprite_loader.LoadSprite(&sprite, file_slot, sc->id, sprite_type)) {
+		ZoomLevel zoom_idx = (zoom > ZOOM_LVL_NORMAL ? ZOOM_LVL_NORMAL : zoom);
+		bool found = false;
+		do {
+			found = sprite_loader.LoadSprite(&sprite, sc->file_slot,
+														 sc->id, sprite_type, zoom_idx);
+			zoom_idx--;
+		} while ( !found && (zoom_idx >= ZOOM_LVL_MIN ) );
+		if (found) {
+			zoom_idx++;
+			if (zoom > zoom_idx) {
+				Blitter_32bppOptimized *blitter = (Blitter_32bppOptimized *)BlitterFactoryBase::GetCurrentBlitter();
+				do {
+					blitter->RescaleSpriteHalfSize(&sprite, &dst_sprite, true);
+					sprite = dst_sprite;
+					zoom_idx++;
+				} while (zoom_idx < zoom);
+			}
 			return BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, allocator);
+
 		}
 		/* If the PNG couldn't be loaded, fall back to 8bpp grfs */
 #else
@@ -226,7 +258,7 @@
 		 * GRFs which are the same as 257 byte recolour sprites, but with the last
 		 * 240 bytes zeroed.  */
 		static const int RECOLOUR_SPRITE_SIZE = 257;
-		byte *dest = (byte *)allocator(max(RECOLOUR_SPRITE_SIZE, num));
+		byte *dest = (byte *)allocator(max(RECOLOUR_SPRITE_SIZE, num) + sizeof(byte *));
 
 		if (_palette_remap_grf[sc->file_slot]) {
 			byte *dest_tmp = AllocaM(byte, max(RECOLOUR_SPRITE_SIZE, num));
@@ -243,6 +275,11 @@
 			FioReadBlock(dest, num);
 		}
 
+		if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 32){
+			Blitter_32bppOptimized *blitter = (Blitter_32bppOptimized *)BlitterFactoryBase::GetCurrentBlitter();
+			byte *tmp_ptr = blitter->FillRGBPalette(id, dest);
+			memcpy(&dest[257], &tmp_ptr, sizeof (tmp_ptr));
+		}
 		return dest;
 	}
 
@@ -288,12 +325,32 @@
 	assert(sprite_type == ST_NORMAL || sprite_type == ST_FONT);
 
 	SpriteLoaderGrf sprite_loader;
-	SpriteLoader::Sprite sprite;
+	SpriteLoader::Sprite sprite, dst_sprite;
 
-	if (!sprite_loader.LoadSprite(&sprite, file_slot, file_pos, sprite_type)) {
-		if (id == SPR_IMG_QUERY) usererror("Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?");
-		return (void*)GetRawSprite(SPR_IMG_QUERY, ST_NORMAL, allocator);
+	if (!sprite_loader.LoadSprite(&sprite, file_slot, file_pos, sprite_type, ZOOM_LVL_NORMAL)) {
+		return NULL;
 	}
+	Blitter_32bppOptimized *blitter = (Blitter_32bppOptimized *)BlitterFactoryBase::GetCurrentBlitter();
+	if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 32) {
+		blitter->FillRGBFromPalette(&sprite);
+	}
+	if (zoom < ZOOM_LVL_NORMAL) {
+		ZoomLevel zoom_idx = zoom;
+		do {
+			blitter->RescaleSpriteDoubleSize(&sprite, &dst_sprite);
+			sprite = dst_sprite;
+			zoom_idx++;
+		} while (zoom_idx < ZOOM_LVL_NORMAL);
+	}
+	if (zoom > ZOOM_LVL_NORMAL) {
+		ZoomLevel zoom_idx = ZOOM_LVL_NORMAL;
+		do {
+			blitter->RescaleSpriteHalfSize(&sprite, &dst_sprite, true);
+			sprite = dst_sprite;
+			zoom_idx++;
+		} while (zoom_idx < zoom);
+	}
+
 	return BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, allocator);
 }
 
@@ -320,7 +377,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;
@@ -334,10 +396,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;
@@ -376,6 +440,7 @@
 
 void IncreaseSpriteLRU()
 {
+	ZoomLevel zoom;
 	/* Increase all LRU values */
 	if (_sprite_lru_counter > 16384) {
 		SpriteID i;
@@ -384,7 +449,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) {
@@ -409,6 +475,7 @@
 static void CompactSpriteCache()
 {
 	MemBlock *s;
+	ZoomLevel zoom;
 
 	DEBUG(sprite, 3, "Compacting sprite cache, inuse=" PRINTF_SIZE, GetSpriteCacheUsage());
 
@@ -425,11 +492,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);
@@ -451,16 +523,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;
+				}
+			}
 		}
 	}
 
@@ -468,17 +545,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;
+					}
+				}
 			}
 		}
 	}
@@ -491,7 +573,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;
 
@@ -578,6 +660,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);
@@ -596,10 +679,12 @@
 		/* Update LRU */
 		sc->lru = ++_sprite_lru_counter;
 
+		zoom = ZoomLevel(_cur_dpi->zoom);
+
 		/* Load the sprite, if it is not loaded, yet */
-		if (sc->ptr == NULL) sc->ptr = ReadSprite(sc, sprite, type, AllocSprite);
+		if (sc->ptr[zoom] == NULL) sc->ptr[zoom] = ReadSprite(sc, sprite, type, AllocSprite);
 
-		return sc->ptr;
+		return sc->ptr[zoom];
 	} else {
 		/* Do not use the spritecache, but a different allocator. */
 		return ReadSprite(sc, sprite, type, allocator);
@@ -621,7 +706,6 @@
 	free(_spritecache);
 	_spritecache_items = 0;
 	_spritecache = NULL;
-
 	_compact_cache_counter = 0;
 }
 
diff -r a88d0ef8a898 src/spritecache.h
--- a/src/spritecache.h	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spritecache.h	Tue Apr 12 16:44:09 2011 +0000
@@ -14,9 +14,8 @@
 
 #include "gfx_type.h"
 
-/** Data structure describing a sprite. */
 struct Sprite {
-	byte height;  ///< Height of the sprite.
+	uint16 height;  ///< Height of the sprite.
 	uint16 width; ///< Width of the sprite.
 	int16 x_offs; ///< Number of pixels to shift the sprite to the right.
 	int16 y_offs; ///< Number of pixels to shift the sprite downwards.
diff -r a88d0ef8a898 src/spriteloader/grf.cpp
--- a/src/spriteloader/grf.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spriteloader/grf.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -39,7 +39,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 -r a88d0ef8a898 src/spriteloader/grf.hpp
--- a/src/spriteloader/grf.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spriteloader/grf.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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 -r a88d0ef8a898 src/spriteloader/png.cpp
--- a/src/spriteloader/png.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spriteloader/png.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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)) {
 		FioOpenFile(PNG_SLOT, png_file);
 		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)) {
+			FioOpenFile(PNG_SLOT, png_file);
+			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);
@@ -114,10 +121,14 @@
 	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);
 		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);
+	}
 
 	if (!mask) {
 		if (bit_depth == 16) png_set_strip_16(png_ptr);
@@ -155,11 +166,14 @@
 		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;
+					/* GeekToo: dont overwrite sprite rgb data if mask is present */
 					/* Alpha channel is used from the original image (to allow transparency in remap colours) */
-					dst[x].m = row_pointer[x * sizeof(uint8)];
+					/* 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];
@@ -176,11 +190,13 @@
 	return true;
 }
 
-bool SpriteLoaderPNG::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type)
+bool SpriteLoaderPNG::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, ZoomLevel zoom)
 {
 	const char *filename = FioGetFilename(file_slot);
-	if (!LoadPNG(sprite, filename, (uint32)file_pos, false)) return false;
-	if (!LoadPNG(sprite, filename, (uint32)file_pos, true)) return false;
+
+	if (!LoadPNG(sprite, filename, (uint32)file_pos, false, zoom)) return false;
+	if (!LoadPNG(sprite, filename, (uint32)file_pos, true, zoom)) return false;
+
 	return true;
 }
 
diff -r a88d0ef8a898 src/spriteloader/png.hpp
--- a/src/spriteloader/png.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spriteloader/png.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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 -r a88d0ef8a898 src/spriteloader/spriteloader.hpp
--- a/src/spriteloader/spriteloader.hpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/spriteloader/spriteloader.hpp	Tue Apr 12 16:44:09 2011 +0000
@@ -56,7 +56,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 -r a88d0ef8a898 src/table/settings.h
--- a/src/table/settings.h	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/table/settings.h	Tue Apr 12 16:44:09 2011 +0000
@@ -280,7 +280,7 @@
 	 SDTG_BOOL("medium_aa",                  S, 0, _freetype.medium_aa,   false,    STR_NULL, NULL),
 	 SDTG_BOOL("large_aa",                   S, 0, _freetype.large_aa,    false,    STR_NULL, NULL),
 #endif
-	  SDTG_VAR("sprite_cache_size",SLE_UINT, S, 0, _sprite_cache_size,     4, 1, 64, 0, STR_NULL, NULL),
+	  SDTG_VAR("sprite_cache_size",SLE_UINT, S, 0, _sprite_cache_size,     64, 64, 64, 0, STR_NULL, NULL),
 	  SDTG_VAR("player_face",    SLE_UINT32, S, 0, _company_manager_face,0,0,0xFFFFFFFF,0, STR_NULL, NULL),
 	  SDTG_VAR("transparency_options", SLE_UINT, S, 0, _transparency_opt,  0,0,0x1FF,0, STR_NULL, NULL),
 	  SDTG_VAR("transparency_locks", SLE_UINT, S, 0, _transparency_lock,   0,0,0x1FF,0, STR_NULL, NULL),
diff -r a88d0ef8a898 src/table/sprites.h
--- a/src/table/sprites.h	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/table/sprites.h	Tue Apr 12 16:44:09 2011 +0000
@@ -1469,7 +1469,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
 };
@@ -1491,6 +1491,7 @@
 	PALETTE_MODIFIER_TRANSPARENT  = TRANSPARENT_BIT,
 	/** this bit is set when a recolouring process is in action */
 	PALETTE_MODIFIER_COLOUR       = RECOLOUR_BIT,
+	PALETTE_MODIFIER_SHADOW        = SHADOW_BIT,
 };
 
 /**
diff -r a88d0ef8a898 src/vehicle.cpp
--- a/src/vehicle.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/vehicle.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -898,9 +898,12 @@
 	PaletteID pal = PAL_NONE;
 
 	if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
-
+	if ((v->vehstatus & VS_SHADOW) != 0)
+	{
+		SetBit(image, PALETTE_MODIFIER_SHADOW);
+	}
 	AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
-		v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
+		v->x_extent, v->y_extent, v->z_extent, v->z_pos, false);
 }
 
 /**
@@ -941,11 +944,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;
@@ -972,8 +971,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 -r a88d0ef8a898 src/vehicle_gui.cpp
--- a/src/vehicle_gui.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/vehicle_gui.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -2533,7 +2533,7 @@
 			case VVW_WIDGET_CENTER_MAIN_VIEH: {// center main view
 				const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
 				/* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */
-				if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
+				if (_ctrl_pressed && mainwindow->viewport->zoom <= ZOOM_LVL_NORMAL) {
 					mainwindow->viewport->follow_vehicle = v->index;
 				} else {
 					ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos);
diff -r a88d0ef8a898 src/viewport.cpp
--- a/src/viewport.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/viewport.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -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;
@@ -377,9 +377,8 @@
 				return pt;
 	}
 
-	x = (ScaleByZoom(x, vp->zoom) + vp->virtual_left) >> 2;
-	y = (ScaleByZoom(y, vp->zoom) + vp->virtual_top) >> 1;
-
+	x = (ScaleByZoom(x + vp->virtual_left, vp->zoom) ) >> 2;
+	y = (ScaleByZoom(y + vp->virtual_top, vp->zoom) ) >> 1;
 	a = y - x;
 	b = y + x;
 
@@ -604,10 +603,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 +650,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 +670,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 +691,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 +811,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 +819,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.
@@ -1033,25 +1039,28 @@
 
 static void ViewportAddLandscape()
 {
-	int x, y, width, height;
+	int x, y, x1, y1, width, nof_sprites_drawn;
+	int top, bottom;
 	TileInfo ti;
 	bool direction;
+	Point pt;
 
 	_cur_ti = &ti;
 
-	/* Transform into tile coordinates and round to closest full tile */
-	x = ((_vd.dpi.top >> 1) - (_vd.dpi.left >> 2)) & ~TILE_UNIT_MASK;
-	y = ((_vd.dpi.top >> 1) + (_vd.dpi.left >> 2) - TILE_SIZE) & ~TILE_UNIT_MASK;
-
-	/* determine size of area */
-	{
-		Point pt = RemapCoords(x, y, 241);
-		width = (_vd.dpi.left + _vd.dpi.width - pt.x + 95) >> 6;
-		height = (_vd.dpi.top + _vd.dpi.height - pt.y) >> 5 << 1;
-	}
-
+	x1 = ScaleByZoomLower(_vd.vp->virtual_left + _vd.dpi.left, _vd.vp->zoom)  ;
+	y1 = ScaleByZoomLower(_vd.vp->virtual_top + _vd.dpi.top, _vd.vp->zoom)  ;
+
+	x1 = x1 / 4;
+	y1 = y1 / 2;
+
+	x = ((y1 - x1) / TILE_SIZE) * TILE_SIZE ;
+	y = ((y1 + x1) / TILE_SIZE) * TILE_SIZE - (TILE_SIZE << 1);
+
+	width  = (_vd.dpi.width / UnScaleByZoom(64, _vd.vp->zoom)) + 4;
+
+	bottom = ScaleByZoom(_vd.vp->virtual_top + _vd.dpi.top + _vd.dpi.height, _vd.vp->zoom) + 128;
+	top = ScaleByZoom(_vd.vp->virtual_top + _vd.dpi.top, _vd.vp->zoom) ;
 	assert(width > 0);
-	assert(height > 0);
 
 	direction = false;
 
@@ -1059,7 +1068,7 @@
 		int width_cur = width;
 		uint x_cur = x;
 		uint y_cur = y;
-
+		nof_sprites_drawn = 0;
 		do {
 			TileType tt = MP_VOID;
 
@@ -1088,24 +1097,17 @@
 					tt = GetTileType(tile);
 				}
 			}
-
-			_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 = GetTileSlope(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;
 		} while (--width_cur);
@@ -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 ||
@@ -1254,7 +1263,14 @@
 {
 	const TileSpriteToDraw *tsend = tstdv->End();
 	for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) {
-		DrawSprite(ts->image, ts->pal, ts->x, ts->y, ts->sub);
+		int left = UnScaleByZoom(ts->x,_vd.vp->zoom);
+		int top =  UnScaleByZoom(ts->y,_vd.vp->zoom);
+
+
+		left -= _vd.vp->virtual_left;
+		top  -= _vd.vp->virtual_top;
+
+		DrawSprite(ts->image, ts->pal, left, top, ts->sub);
 	}
 }
 
@@ -1318,16 +1334,22 @@
 
 static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv)
 {
+	int  x,y, left, top;
 	const ParentSpriteToDraw * const *psd_end = psd->End();
 	for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) {
-		const ParentSpriteToDraw *ps = *it;
-		if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSprite(ps->image, ps->pal, ps->x, ps->y, ps->sub);
+		const ParentSpriteToDraw* ps = *it;
+
+		x = UnScaleByZoom(ps->x, _cur_dpi->zoom) - _vd.vp->virtual_left;
+		y = UnScaleByZoom(ps->y, _cur_dpi->zoom) - _vd.vp->virtual_top;
+		left = UnScaleByZoom(ps->left, _cur_dpi->zoom) - _vd.vp->virtual_left;
+		top = UnScaleByZoom(ps->top, _cur_dpi->zoom) - _vd.vp->virtual_top;
+		if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSprite(ps->image, ps->pal, x, y, ps->sub);
 
 		int child_idx = ps->first_child;
 		while (child_idx >= 0) {
 			const ChildScreenSpriteToDraw *cs = csstdv->Get(child_idx);
 			child_idx = cs->next;
-			DrawSprite(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub);
+			DrawSprite(cs->image, cs->pal, left + cs->x, top + cs->y, cs->sub);
 		}
 	}
 }
@@ -1338,13 +1360,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,
@@ -1362,20 +1398,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]);
@@ -1402,7 +1435,6 @@
 				);
 			}
 		}
-
 		DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss->string, colour, SA_HOR_CENTER);
 	}
 }
@@ -1410,27 +1442,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);
@@ -1467,7 +1513,8 @@
  */
 static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
 {
-	if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000) {
+	if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom)
+	> 50000) {
 		if ((bottom - top) > (right - left)) {
 			int t = (top + bottom) >> 1;
 			ViewportDrawChk(vp, left, top, right, t);
@@ -1478,12 +1525,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);
 	}
 }
 
@@ -1595,26 +1637,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);
 }
 
 /**
@@ -1786,8 +1831,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 -r a88d0ef8a898 src/window.cpp
--- a/src/window.cpp	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/window.cpp	Tue Apr 12 16:44:09 2011 +0000
@@ -541,7 +541,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) {
@@ -553,6 +555,7 @@
 			DrawOverlappedWindow(w, left, top, right, bottom);
 		}
 	}
+	_cur_dpi = old_dpi;
 }
 
 /**
diff -r a88d0ef8a898 src/zoom_type.h
--- a/src/zoom_type.h	Thu Mar 31 21:21:50 2011 +0000
+++ b/src/zoom_type.h	Tue Apr 12 16:44:09 2011 +0000
@@ -16,8 +16,10 @@
 
 enum ZoomLevel {
 	/* Our possible zoom-levels */
-	ZOOM_LVL_BEGIN  = 0,
-	ZOOM_LVL_NORMAL = 0,
+	ZOOM_LVL_BEGIN = 0,
+	ZOOM_LVL_IN_4X = 0,
+	ZOOM_LVL_IN_2X,
+	ZOOM_LVL_NORMAL,
 	ZOOM_LVL_OUT_2X,
 	ZOOM_LVL_OUT_4X,
 	ZOOM_LVL_OUT_8X,
@@ -39,7 +41,7 @@
 
 	ZOOM_LVL_DETAIL   = ZOOM_LVL_OUT_2X, ///< All zoomlevels below or equal to this, will result in details on the screen, like road-work, ...
 
-	ZOOM_LVL_MIN      = ZOOM_LVL_NORMAL,
+	ZOOM_LVL_MIN      = ZOOM_LVL_BEGIN,
 	ZOOM_LVL_MAX      = ZOOM_LVL_OUT_8X,
 };
 DECLARE_POSTFIX_INCREMENT(ZoomLevel)
