changeset 6653:cbe12394f776 draft

(svn r9884) -Feature: 2 new zoom-out levels: 8 times and 16 times -Codechange: unified the blitter function so we have 1 function for all zoom-levels -Codechange: make most of the label functions work with zoom-level instead of magic numbers and big switches per zoom-level -Codechange: MakeXXXDirty() functions didn't take into account zoom-level, but just used the biggest possible value -Codechange: simplified blitter functions to avoid code duplication
author truelight <truelight@openttd.org>
date Sat, 19 May 2007 22:48:04 +0000
parents 57747e3d5d69
children 860f3e5f70ec
files src/gfx.cpp src/signs.cpp src/station.cpp src/texteff.cpp src/viewport.cpp src/zoom.hpp
diffstat 6 files changed, 190 insertions(+), 669 deletions(-) [+]
line wrap: on
line diff
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -738,142 +738,7 @@
 	int pitch;
 };
 
-static void GfxBlitTileZoomIn(BlitterParams *bp)
-{
-	const byte *src_o = bp->sprite;
-	const byte *src;
-	int num, skip;
-	byte done;
-	Pixel *dst;
-	const byte *ctab;
-
-	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-
-					for (; num >= 4; num -=4) {
-						dst[3] = ctab[src[3]];
-						dst[2] = ctab[src[2]];
-						dst[1] = ctab[src[1]];
-						dst[0] = ctab[src[0]];
-						dst += 4;
-						src += 4;
-					}
-					for (; num != 0; num--) *dst++ = ctab[*src++];
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-			} while (--bp->height != 0);
-			break;
-
-		case BM_TRANSPARENT:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip;
-					} else {
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					for (; num != 0; num--) {
-						*dst = ctab[*dst];
-						dst++;
-					}
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-			} while (--bp->height != 0);
-			break;
-
-		default:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-#if defined(_WIN32)
-					if (num & 1) *dst++ = *src++;
-					if (num & 2) { *(uint16*)dst = *(uint16*)src; dst += 2; src += 2; }
-					if (num >>= 2) {
-						do {
-							*(uint32*)dst = *(uint32*)src;
-							dst += 4;
-							src += 4;
-						} while (--num != 0);
-					}
-#else
-					memcpy(dst, src, num);
-#endif
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-			} while (--bp->height != 0);
-			break;
-	}
-}
-
-static void GfxBlitZoomInUncomp(BlitterParams *bp)
+static void GfxBlitZoomUncomp(BlitterParams *bp, ZoomLevel zoom)
 {
 	const byte *src = bp->sprite;
 	Pixel *dst = bp->dst;
@@ -884,62 +749,48 @@
 	assert(height > 0);
 	assert(width > 0);
 
+	height = UnScaleByZoom(height, zoom);
+
 	switch (bp->mode) {
 		case BM_COLOUR_REMAP: {
 			const byte *ctab = _color_remap_ptr;
 
-			do {
-				for (i = 0; i != width; i++) {
-					byte b = ctab[src[i]];
+			for (; height != 0; height--) {
+				for (i = 0; i != UnScaleByZoom(width, zoom); i++) {
+					byte b = ctab[src[ScaleByZoom(i, zoom)]];
 
 					if (b != 0) dst[i] = b;
 				}
-				src += bp->width_org;
+				src += ScaleByZoom(bp->width_org, zoom);
 				dst += bp->pitch;
-			} while (--height != 0);
+			}
 			break;
 		}
 
 		case BM_TRANSPARENT: {
 			const byte *ctab = _color_remap_ptr;
 
-			do {
-				for (i = 0; i != width; i++)
-					if (src[i] != 0) dst[i] = ctab[dst[i]];
-				src += bp->width_org;
+			for (; height != 0; height--) {
+				for (i = 0; i != UnScaleByZoom(width, zoom); i++)
+					if (src[ScaleByZoom(i, zoom)] != 0) dst[i] = ctab[dst[i]];
+				src += ScaleByZoom(bp->width_org, zoom);
 				dst += bp->pitch;
-			} while (--height != 0);
+			}
 			break;
 		}
 
 		default:
-			do {
-				int n = width;
-
-				for (; n >= 4; n -= 4) {
-					if (src[0] != 0) dst[0] = src[0];
-					if (src[1] != 0) dst[1] = src[1];
-					if (src[2] != 0) dst[2] = src[2];
-					if (src[3] != 0) dst[3] = src[3];
-
-					dst += 4;
-					src += 4;
-				}
-
-				for (; n != 0; n--) {
-					if (src[0] != 0) dst[0] = src[0];
-					src++;
-					dst++;
-				}
-
-				src += bp->width_org - width;
-				dst += bp->pitch - width;
-			} while (--height != 0);
+			for (; height != 0; height--) {
+				for (i = 0; i != UnScaleByZoom(width, zoom); i++)
+					if (src[ScaleByZoom(i, zoom)] != 0) dst[i] = src[ScaleByZoom(i, zoom)];
+				src += ScaleByZoom(bp->width_org, zoom);
+				dst += bp->pitch;
+			}
 			break;
 	}
 }
 
-static void GfxBlitTileZoomMedium(BlitterParams *bp)
+static void GfxBlitTileZoom(BlitterParams *bp, ZoomLevel zoom)
 {
 	const byte *src_o = bp->sprite;
 	const byte *src;
@@ -949,478 +800,105 @@
 	const byte *ctab;
 
 	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
+
+	for (;;) {
+		do {
+			done = src_o[0];
+			num = done & 0x7F;
+			skip = src_o[1];
+			src = src_o + 2;
+			src_o += num + 2;
+
+			dst = bp->dst;
 
-					dst = bp->dst;
+			if (zoom >= ZOOM_LVL_OUT_2X && (skip & 1)) {
+				skip += 1;
+				src += 1;
+				num -= 1;
+				if (num <= 0) continue;
+			}
 
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
+			if (zoom >= ZOOM_LVL_OUT_4X && (skip & 2)) {
+				skip += 2;
+				src += 2;
+				num -= 2;
+				if (num <= 0) continue;
+			}
 
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 1;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
+			if (zoom >= ZOOM_LVL_OUT_8X && (skip & 4)) {
+				skip += 4;
+				src += 4;
+				num -= 4;
+				if (num <= 0) continue;
+			}
+
+			if (zoom >= ZOOM_LVL_OUT_16X && (skip & 8)) {
+				skip += 8;
+				src += 8;
+				num -= 8;
+				if (num <= 0) continue;
+			}
 
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
+			if ( (skip -= bp->start_x) > 0) {
+				dst += UnScaleByZoom(skip, zoom);
+			} else {
+				src -= skip;
+				num += skip;
+				if (num <= 0) continue;
+				skip = 0;
+			}
 
+			skip = skip + num - bp->width;
+			if (skip > 0) {
+				num -= skip;
+				if (num <= 0) continue;
+			}
+
+			num = UnScaleByZoom(num + ScaleByZoom(1, zoom) - 1, zoom);
+
+			switch (bp->mode) {
+				case BM_COLOUR_REMAP:
 					ctab = _color_remap_ptr;
-					num = (num + 1) >> 1;
 					for (; num != 0; num--) {
 							*dst = ctab[*src];
 							dst++;
-							src += 2;
+							src += ScaleByZoom(1, zoom);
 					}
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-			} while (--bp->height != 0);
-			break;
-
-		case BM_TRANSPARENT:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src_o += num + 2;
+					break;
 
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						if (--num == 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 1;
-					} else {
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
+				case BM_TRANSPARENT:
 					ctab = _color_remap_ptr;
-					num = (num + 1) >> 1;
 					for (; num != 0; num--) {
 							*dst = ctab[*dst];
 							dst++;
 					}
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-			} while (--bp->height != 0);
-			break;
-
-		default:
-			do {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
+					break;
 
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 1;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					num = (num + 1) >> 1;
-
+				default:
 					for (; num != 0; num--) {
 							*dst = *src;
 							dst++;
-							src += 2;
+							src += ScaleByZoom(1, zoom);
 					}
-
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
+					break;
+			}
 
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-			} while (--bp->height != 0);
-			break;
-	}
-}
 
-static void GfxBlitZoomMediumUncomp(BlitterParams *bp)
-{
-	const byte *src = bp->sprite;
-	Pixel *dst = bp->dst;
-	int height = bp->height;
-	int width = bp->width;
-	int i;
-
-	assert(height > 0);
-	assert(width > 0);
-
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP: {
-			const byte *ctab = _color_remap_ptr;
+		} while (!(done & 0x80));
 
-			for (height >>= 1; height != 0; height--) {
-				for (i = 0; i != width >> 1; i++) {
-					byte b = ctab[src[i * 2]];
-
-					if (b != 0) dst[i] = b;
-				}
-				src += bp->width_org * 2;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		case BM_TRANSPARENT: {
-			const byte *ctab = _color_remap_ptr;
+		bp->dst += bp->pitch;
+		if (--bp->height == 0) return;
 
-			for (height >>= 1; height != 0; height--) {
-				for (i = 0; i != width >> 1; i++)
-					if (src[i * 2] != 0) dst[i] = ctab[dst[i]];
-				src += bp->width_org * 2;
-				dst += bp->pitch;
-			}
-			break;
+		for (int i = 0; i < ScaleByZoom(1, zoom) - 1; i++) {
+			do {
+				done = src_o[0];
+				src_o += (done & 0x7F) + 2;
+			} while (!(done & 0x80));
+			if (--bp->height == 0) return;
 		}
-
-		default:
-			for (height >>= 1; height != 0; height--) {
-				for (i = 0; i != width >> 1; i++)
-					if (src[i * 2] != 0) dst[i] = src[i * 2];
-				src += bp->width_org * 2;
-				dst += bp->pitch;
-			}
-			break;
 	}
 }
 
-static void GfxBlitTileZoomOut(BlitterParams *bp)
-{
-	const byte *src_o = bp->sprite;
-	const byte *src;
-	int num, skip;
-	byte done;
-	Pixel *dst;
-	const byte *ctab;
-
-	src_o += ReadLE16Aligned(src_o + bp->start_y * 2);
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP:
-			for (;;) {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if (skip & 2) {
-						skip += 2;
-						src += 2;
-						num -= 2;
-						if (num <= 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 2;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					num = (num + 3) >> 2;
-					for (; num != 0; num--) {
-							*dst = ctab[*src];
-							dst++;
-							src += 4;
-					}
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-			}
-			break;
-
-		case BM_TRANSPARENT:
-			for (;;) {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						if (--num == 0) continue;
-					}
-
-					if (skip & 2) {
-						skip += 2;
-						num -= 2;
-						if (num <= 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 2;
-					} else {
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					ctab = _color_remap_ptr;
-					num = (num + 3) >> 2;
-					for (; num != 0; num--) {
-							*dst = ctab[*dst];
-							dst++;
-					}
-
-				} while (!(done & 0x80));
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-			}
-			break;
-
-		default:
-			for (;;) {
-				do {
-					done = src_o[0];
-					num = done & 0x7F;
-					skip = src_o[1];
-					src = src_o + 2;
-					src_o += num + 2;
-
-					dst = bp->dst;
-
-					if (skip & 1) {
-						skip++;
-						src++;
-						if (--num == 0) continue;
-					}
-
-					if (skip & 2) {
-						skip += 2;
-						src += 2;
-						num -= 2;
-						if (num <= 0) continue;
-					}
-
-					if ( (skip -= bp->start_x) > 0) {
-						dst += skip >> 2;
-					} else {
-						src -= skip;
-						num += skip;
-						if (num <= 0) continue;
-						skip = 0;
-					}
-
-					skip = skip + num - bp->width;
-					if (skip > 0) {
-						num -= skip;
-						if (num <= 0) continue;
-					}
-
-					num = (num + 3) >> 2;
-
-					for (; num != 0; num--) {
-							*dst = *src;
-							dst++;
-							src += 4;
-					}
-				} while (!(done & 0x80));
-
-				bp->dst += bp->pitch;
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-
-				do {
-					done = src_o[0];
-					src_o += (done & 0x7F) + 2;
-				} while (!(done & 0x80));
-				if (--bp->height == 0) return;
-			}
-			break;
-	}
-}
-
-static void GfxBlitZoomOutUncomp(BlitterParams *bp)
-{
-	const byte *src = bp->sprite;
-	Pixel *dst = bp->dst;
-	int height = bp->height;
-	int width = bp->width;
-	int i;
-
-	assert(height > 0);
-	assert(width > 0);
-
-	switch (bp->mode) {
-		case BM_COLOUR_REMAP: {
-			const byte *ctab = _color_remap_ptr;
-
-			for (height >>= 2; height != 0; height--) {
-				for (i = 0; i != width >> 2; i++) {
-					byte b = ctab[src[i * 4]];
-
-					if (b != 0) dst[i] = b;
-				}
-				src += bp->width_org * 4;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		case BM_TRANSPARENT: {
-			const byte *ctab = _color_remap_ptr;
-
-			for (height >>= 2; height != 0; height--) {
-				for (i = 0; i != width >> 2; i++)
-					if (src[i * 4] != 0) dst[i] = ctab[dst[i]];
-				src += bp->width_org * 4;
-				dst += bp->pitch;
-			}
-			break;
-		}
-
-		default:
-			for (height >>= 2; height != 0; height--) {
-				for (i = 0; i != width >> 2; i++)
-					if (src[i * 4] != 0) dst[i] = src[i * 4];
-				src += bp->width_org * 4;
-				dst += bp->pitch;
-			}
-			break;
-	}
-}
-
-
 static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode)
 {
 	const DrawPixelInfo *dpi = _cur_dpi;
@@ -1483,12 +961,7 @@
 			if (bp.width <= 0) return;
 		}
 
-		switch (dpi->zoom) {
-			default: NOT_REACHED();
-			case ZOOM_LVL_NORMAL: GfxBlitTileZoomIn(&bp);     break;
-			case ZOOM_LVL_OUT_2X: GfxBlitTileZoomMedium(&bp); break;
-			case ZOOM_LVL_OUT_4X: GfxBlitTileZoomOut(&bp);    break;
-		}
+		GfxBlitTileZoom(&bp, dpi->zoom);
 	} else {
 		bp.sprite += bp.width * (bp.height & ~zoom_mask);
 		bp.height &= zoom_mask;
@@ -1525,12 +998,7 @@
 			if (bp.width <= 0) return;
 		}
 
-		switch (dpi->zoom) {
-			default: NOT_REACHED();
-			case ZOOM_LVL_NORMAL: GfxBlitZoomInUncomp(&bp);     break;
-			case ZOOM_LVL_OUT_2X: GfxBlitZoomMediumUncomp(&bp); break;
-			case ZOOM_LVL_OUT_4X: GfxBlitZoomOutUncomp(&bp);    break;
-		}
+		GfxBlitZoomUncomp(&bp, dpi->zoom);
 	}
 }
 
--- a/src/signs.cpp
+++ b/src/signs.cpp
@@ -67,8 +67,8 @@
 	MarkAllViewportsDirty(
 		si->sign.left - 6,
 		si->sign.top  - 3,
-		si->sign.left + si->sign.width_1 * 4 + 12,
-		si->sign.top  + 45);
+		si->sign.left + ScaleByZoom(si->sign.width_1 + 12, _cur_dpi->zoom),
+		si->sign.top  + ScaleByZoom(12, _cur_dpi->zoom));
 }
 
 /**
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -125,8 +125,8 @@
 		MarkAllViewportsDirty(
 			sign.left - 6,
 			sign.top,
-			sign.left + (sign.width_1 << 2) + 12,
-			sign.top + 48);
+			sign.left + ScaleByZoom(sign.width_1 + 12, _cur_dpi->zoom),
+			sign.top + ScaleByZoom(12, _cur_dpi->zoom));
 	}
 }
 
--- a/src/texteff.cpp
+++ b/src/texteff.cpp
@@ -352,6 +352,8 @@
 			break;
 
 		case ZOOM_LVL_OUT_4X:
+		case ZOOM_LVL_OUT_8X:
+		case ZOOM_LVL_OUT_16X:
 			break;
 
 		default: NOT_REACHED();
--- a/src/viewport.cpp
+++ b/src/viewport.cpp
@@ -839,21 +839,26 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			right += 4;
-			bottom += 5;
+		case ZOOM_LVL_OUT_8X:
+			right += ScaleByZoom(1, dpi->zoom);
+			bottom += ScaleByZoom(1, dpi->zoom) + 1;
 
 			FOR_ALL_TOWNS(t) {
 				if (bottom > t->sign.top &&
-						top    < t->sign.top + 24 &&
+						top    < t->sign.top + ScaleByZoom(12, dpi->zoom) &&
 						right  > t->sign.left &&
-						left   < t->sign.left + t->sign.width_2*4) {
+						left   < t->sign.left + ScaleByZoom(t->sign.width_2, dpi->zoom)) {
 					AddStringToDraw(t->sign.left + 5, t->sign.top + 1, STR_TOWN_LABEL_TINY_BLACK, t->index, 0);
 					AddStringToDraw(t->sign.left + 1, t->sign.top - 3, STR_TOWN_LABEL_TINY_WHITE, t->index, 0);
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 }
 
@@ -908,19 +913,25 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			right += 4;
-			bottom += 5;
+		case ZOOM_LVL_OUT_8X:
+			right += ScaleByZoom(1, dpi->zoom);
+			bottom += ScaleByZoom(1, dpi->zoom) + 1;
+
 			FOR_ALL_STATIONS(st) {
 				if (bottom > st->sign.top &&
-						top    < st->sign.top + 24 &&
+						top    < st->sign.top + ScaleByZoom(12, dpi->zoom) &&
 						right  > st->sign.left &&
-						left   < st->sign.left + st->sign.width_2*4) {
+						left   < st->sign.left + ScaleByZoom(st->sign.width_2, dpi->zoom)) {
 					AddStation(st, STR_STATION_SIGN_TINY, st->sign.width_2 | 0x8000);
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 }
 
@@ -975,19 +986,25 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			right += 4;
-			bottom += 5;
+		case ZOOM_LVL_OUT_8X:
+			right += ScaleByZoom(1, dpi->zoom);
+			bottom += ScaleByZoom(1, dpi->zoom) + 1;
+
 			FOR_ALL_SIGNS(si) {
 				if (bottom > si->sign.top &&
-						top    < si->sign.top + 24 &&
+						top    < si->sign.top + ScaleByZoom(12, dpi->zoom) &&
 						right  > si->sign.left &&
-						left   < si->sign.left + si->sign.width_2 * 4) {
+						left   < si->sign.left + ScaleByZoom(si->sign.width_2, dpi->zoom)) {
 					AddSign(si, STR_2002, si->sign.width_2 | 0x8000);
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 }
 
@@ -1042,19 +1059,25 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			right += 4;
-			bottom += 5;
+		case ZOOM_LVL_OUT_8X:
+			right += ScaleByZoom(1, dpi->zoom);
+			bottom += ScaleByZoom(1, dpi->zoom) + 1;
+
 			FOR_ALL_WAYPOINTS(wp) {
 				if (bottom > wp->sign.top &&
-						top    < wp->sign.top + 24 &&
+						top    < wp->sign.top + ScaleByZoom(12, dpi->zoom) &&
 						right  > wp->sign.left &&
-						left   < wp->sign.left + wp->sign.width_2*4) {
+						left   < wp->sign.left + ScaleByZoom(wp->sign.width_2, dpi->zoom)) {
 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT_TINY, wp->sign.width_2 | 0x8000);
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 }
 
@@ -1520,20 +1543,26 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+		case ZOOM_LVL_OUT_8X:
+			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
+			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
+
 			FOR_ALL_TOWNS(t) {
 				if (y >= t->sign.top &&
-						y < t->sign.top + 24 &&
+						y < t->sign.top + ScaleByZoom(12, vp->zoom) &&
 						x >= t->sign.left &&
-						x < t->sign.left + t->sign.width_2 * 4) {
+						x < t->sign.left + ScaleByZoom(t->sign.width_2, vp->zoom)) {
 					ShowTownViewWindow(t->index);
 					return true;
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 
 	return false;
@@ -1575,20 +1604,26 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+		case ZOOM_LVL_OUT_8X:
+			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
+			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
+
 			FOR_ALL_STATIONS(st) {
 				if (y >= st->sign.top &&
-						y < st->sign.top + 24 &&
+						y < st->sign.top + ScaleByZoom(12, vp->zoom) &&
 						x >= st->sign.left &&
-						x < st->sign.left + st->sign.width_2 * 4) {
+						x < st->sign.left + ScaleByZoom(st->sign.width_2, vp->zoom)) {
 					ShowStationViewWindow(st->index);
 					return true;
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 
 	return false;
@@ -1630,20 +1665,26 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+		case ZOOM_LVL_OUT_8X:
+			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
+			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
+
 			FOR_ALL_SIGNS(si) {
 				if (y >= si->sign.top &&
-						y <  si->sign.top + 24 &&
+						y <  si->sign.top + ScaleByZoom(12, vp->zoom) &&
 						x >= si->sign.left &&
-						x <  si->sign.left + si->sign.width_2 * 4) {
+						x <  si->sign.left + ScaleByZoom(si->sign.width_2, vp->zoom)) {
 					ShowRenameSignWindow(si);
 					return true;
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 
 	return false;
@@ -1685,20 +1726,26 @@
 			}
 			break;
 
-		default: NOT_REACHED();
 		case ZOOM_LVL_OUT_4X:
-			x = (x - vp->left + 3) * 4 + vp->virtual_left;
-			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
+		case ZOOM_LVL_OUT_8X:
+			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
+			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
+
 			FOR_ALL_WAYPOINTS(wp) {
 				if (y >= wp->sign.top &&
-						y < wp->sign.top + 24 &&
+						y < wp->sign.top + ScaleByZoom(12, vp->zoom) &&
 						x >= wp->sign.left &&
-						x < wp->sign.left + wp->sign.width_2 * 4) {
+						x < wp->sign.left + ScaleByZoom(wp->sign.width_2, vp->zoom)) {
 					ShowRenameWaypointWindow(wp);
 					return true;
 				}
 			}
 			break;
+
+		case ZOOM_LVL_OUT_16X:
+			break;
+
+		default: NOT_REACHED();
 	}
 
 	return false;
--- a/src/zoom.hpp
+++ b/src/zoom.hpp
@@ -10,6 +10,8 @@
 	ZOOM_LVL_NORMAL = 0,
 	ZOOM_LVL_OUT_2X,
 	ZOOM_LVL_OUT_4X,
+	ZOOM_LVL_OUT_8X,
+	ZOOM_LVL_OUT_16X,
 	ZOOM_LVL_END,
 
 	/* Here we define in which zoom viewports are */
@@ -26,19 +28,21 @@
 	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_MAX      = ZOOM_LVL_OUT_4X,
+	ZOOM_LVL_MAX      = ZOOM_LVL_OUT_16X,
 };
 
 extern ZoomLevel _saved_scrollpos_zoom;
 
 static inline int ScaleByZoom(int value, ZoomLevel zoom)
 {
+	if (zoom == ZOOM_LVL_NORMAL) return value;
 	int izoom = (int)zoom - (int)ZOOM_LVL_NORMAL;
 	return (zoom > ZOOM_LVL_NORMAL) ? value << izoom : value >> izoom;
 }
 
 static inline int UnScaleByZoom(int value, ZoomLevel zoom)
 {
+	if (zoom == ZOOM_LVL_NORMAL) return value;
 	int izoom = (int)zoom - (int)ZOOM_LVL_NORMAL;
 	return (zoom > ZOOM_LVL_NORMAL) ? value >> izoom : value << izoom;
 }