src/viewport.cpp
branchNewGRF_ports
changeset 6719 4cc327ad39d5
parent 6718 5a8b295aa345
child 6720 35756db7e577
equal deleted inserted replaced
6718:5a8b295aa345 6719:4cc327ad39d5
     9 #include "gui.h"
     9 #include "gui.h"
    10 #include "spritecache.h"
    10 #include "spritecache.h"
    11 #include "strings.h"
    11 #include "strings.h"
    12 #include "table/sprites.h"
    12 #include "table/sprites.h"
    13 #include "table/strings.h"
    13 #include "table/strings.h"
       
    14 #include "landscape.h"
    14 #include "map.h"
    15 #include "map.h"
    15 #include "viewport.h"
    16 #include "viewport.h"
    16 #include "window.h"
    17 #include "window.h"
    17 #include "vehicle.h"
    18 #include "vehicle.h"
    18 #include "station.h"
    19 #include "station.h"
    24 #include "train.h"
    25 #include "train.h"
    25 #include "table/station_air.h"
    26 #include "table/station_air.h"
    26 
    27 
    27 #define VIEWPORT_DRAW_MEM (65536 * 2)
    28 #define VIEWPORT_DRAW_MEM (65536 * 2)
    28 
    29 
    29 // XXX - maximum viewports is maximum windows - 2 (main toolbar + status bar)
    30 ZoomLevel _saved_scrollpos_zoom;
       
    31 
       
    32 /* XXX - maximum viewports is maximum windows - 2 (main toolbar + status bar) */
    30 static ViewPort _viewports[25 - 2];
    33 static ViewPort _viewports[25 - 2];
    31 static uint32 _active_viewports;    ///< bitmasked variable where each bit signifies if a viewport is in use or not
    34 static uint32 _active_viewports;    ///< bitmasked variable where each bit signifies if a viewport is in use or not
    32 assert_compile(lengthof(_viewports) < sizeof(_active_viewports) * 8);
    35 assert_compile(lengthof(_viewports) < sizeof(_active_viewports) * 8);
    33 
    36 
    34 static bool _added_tile_sprite;
    37 static bool _added_tile_sprite;
    90 	byte unk16;
    93 	byte unk16;
    91 	byte zmin;
    94 	byte zmin;
    92 	byte zmax;
    95 	byte zmax;
    93 };
    96 };
    94 
    97 
    95 // Quick hack to know how much memory to reserve when allocating from the spritelist
    98 /* Quick hack to know how much memory to reserve when allocating from the spritelist
    96 // to prevent a buffer overflow.
    99  * to prevent a buffer overflow. */
    97 #define LARGEST_SPRITELIST_STRUCT ParentSpriteToDraw
   100 #define LARGEST_SPRITELIST_STRUCT ParentSpriteToDraw
    98 
   101 
    99 struct ViewportDrawer {
   102 struct ViewportDrawer {
   100 	DrawPixelInfo dpi;
   103 	DrawPixelInfo dpi;
   101 
   104 
   141 	w->viewport->width = 0;
   144 	w->viewport->width = 0;
   142 	w->viewport = NULL;
   145 	w->viewport = NULL;
   143 }
   146 }
   144 
   147 
   145 void AssignWindowViewport(Window *w, int x, int y,
   148 void AssignWindowViewport(Window *w, int x, int y,
   146 	int width, int height, uint32 follow_flags, byte zoom)
   149 	int width, int height, uint32 follow_flags, ZoomLevel zoom)
   147 {
   150 {
   148 	ViewPort *vp;
   151 	ViewPort *vp;
   149 	Point pt;
   152 	Point pt;
   150 	uint32 bit;
   153 	uint32 bit;
   151 
   154 
   160 	vp->width = width;
   163 	vp->width = width;
   161 	vp->height = height;
   164 	vp->height = height;
   162 
   165 
   163 	vp->zoom = zoom;
   166 	vp->zoom = zoom;
   164 
   167 
   165 	vp->virtual_width = width << zoom;
   168 	vp->virtual_width = ScaleByZoom(width, zoom);
   166 	vp->virtual_height = height << zoom;
   169 	vp->virtual_height = ScaleByZoom(height, zoom);
   167 
   170 
   168 	if (follow_flags & 0x80000000) {
   171 	if (follow_flags & 0x80000000) {
   169 		const Vehicle *veh;
   172 		const Vehicle *veh;
   170 
   173 
   171 		WP(w, vp_d).follow_vehicle = (VehicleID)(follow_flags & 0xFFFF);
   174 		WP(w, vp_d).follow_vehicle = (VehicleID)(follow_flags & 0xFFFF);
   179 		pt = MapXYZToViewport(vp, x, y, GetSlopeZ(x, y));
   182 		pt = MapXYZToViewport(vp, x, y, GetSlopeZ(x, y));
   180 	}
   183 	}
   181 
   184 
   182 	WP(w, vp_d).scrollpos_x = pt.x;
   185 	WP(w, vp_d).scrollpos_x = pt.x;
   183 	WP(w, vp_d).scrollpos_y = pt.y;
   186 	WP(w, vp_d).scrollpos_y = pt.y;
       
   187 	WP(w, vp_d).dest_scrollpos_x = pt.x;
       
   188 	WP(w, vp_d).dest_scrollpos_y = pt.y;
       
   189 
   184 	w->viewport = vp;
   190 	w->viewport = vp;
   185 	vp->virtual_left = 0;//pt.x;
   191 	vp->virtual_left = 0;//pt.x;
   186 	vp->virtual_top = 0;//pt.y;
   192 	vp->virtual_top = 0;//pt.y;
   187 }
   193 }
   188 
   194 
   265 	int left, top, width, height;
   271 	int left, top, width, height;
   266 
   272 
   267 	vp->virtual_left = x;
   273 	vp->virtual_left = x;
   268 	vp->virtual_top = y;
   274 	vp->virtual_top = y;
   269 
   275 
   270 	old_left >>= vp->zoom;
   276 	old_left = UnScaleByZoom(old_left, vp->zoom);
   271 	old_top >>= vp->zoom;
   277 	old_top = UnScaleByZoom(old_top, vp->zoom);
   272 	x >>= vp->zoom;
   278 	x = UnScaleByZoom(x, vp->zoom);
   273 	y >>= vp->zoom;
   279 	y = UnScaleByZoom(y, vp->zoom);
   274 
   280 
   275 	old_left -= x;
   281 	old_left -= x;
   276 	old_top -= y;
   282 	old_top -= y;
   277 
   283 
   278 	if (old_top == 0 && old_left == 0) return;
   284 	if (old_top == 0 && old_left == 0) return;
   329 				(uint)(y -= vp->top) >= (uint)vp->height) {
   335 				(uint)(y -= vp->top) >= (uint)vp->height) {
   330 				Point pt = {-1, -1};
   336 				Point pt = {-1, -1};
   331 				return pt;
   337 				return pt;
   332 	}
   338 	}
   333 
   339 
   334 	x = ((x << vp->zoom) + vp->virtual_left) >> 2;
   340 	x = (ScaleByZoom(x, vp->zoom) + vp->virtual_left) >> 2;
   335 	y = ((y << vp->zoom) + vp->virtual_top) >> 1;
   341 	y = (ScaleByZoom(y, vp->zoom) + vp->virtual_top) >> 1;
   336 
   342 
   337 	a = y-x;
   343 	a = y-x;
   338 	b = y+x;
   344 	b = y+x;
   339 
   345 
   340 	/* we need to move variables in to the valid range, as the
   346 	/* we need to move variables in to the valid range, as the
   396 	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
   402 	return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
   397 }
   403 }
   398 
   404 
   399 /** Update the status of the zoom-buttons according to the zoom-level
   405 /** Update the status of the zoom-buttons according to the zoom-level
   400  * of the viewport. This will update their status and invalidate accordingly
   406  * of the viewport. This will update their status and invalidate accordingly
   401  * @param window pointer to the window that has the zoom buttons
   407  * @param w Window pointer to the window that has the zoom buttons
   402  * @param vp pointer to the viewport whose zoom-level the buttons represent
   408  * @param vp pointer to the viewport whose zoom-level the buttons represent
   403  * @param widget_zoom_in widget index for window with zoom-in button
   409  * @param widget_zoom_in widget index for window with zoom-in button
   404  * @param widget_zoom_out widget index for window with zoom-out button */
   410  * @param widget_zoom_out widget index for window with zoom-out button */
   405 void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
   411 void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
   406 {
   412 {
   407 	SetWindowWidgetDisabledState(w, widget_zoom_in, vp->zoom == 0);
   413 	SetWindowWidgetDisabledState(w, widget_zoom_in, vp->zoom == ZOOM_LVL_MIN);
   408 	InvalidateWidget(w, widget_zoom_in);
   414 	InvalidateWidget(w, widget_zoom_in);
   409 
   415 
   410 	SetWindowWidgetDisabledState(w, widget_zoom_out, vp->zoom == 2);
   416 	SetWindowWidgetDisabledState(w, widget_zoom_out, vp->zoom == ZOOM_LVL_MAX);
   411 	InvalidateWidget(w, widget_zoom_out);
   417 	InvalidateWidget(w, widget_zoom_out);
   412 }
   418 }
   413 
   419 
   414 void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z)
   420 void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z)
   415 {
   421 {
   437 }
   443 }
   438 
   444 
   439 void DrawGroundSprite(SpriteID image, SpriteID pal)
   445 void DrawGroundSprite(SpriteID image, SpriteID pal)
   440 {
   446 {
   441 	if (_offset_ground_sprites) {
   447 	if (_offset_ground_sprites) {
   442 		// offset ground sprite because of foundation?
   448 		/* offset ground sprite because of foundation? */
   443 		AddChildSpriteScreen(image, pal, _cur_vd->offs_x, _cur_vd->offs_y);
   449 		AddChildSpriteScreen(image, pal, _cur_vd->offs_x, _cur_vd->offs_y);
   444 	} else {
   450 	} else {
   445 		_added_tile_sprite = true;
   451 		_added_tile_sprite = true;
   446 		DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z);
   452 		DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z);
   447 	}
   453 	}
   492 		return;
   498 		return;
   493 	}
   499 	}
   494 	ps = (ParentSpriteToDraw*)vd->spritelist_mem;
   500 	ps = (ParentSpriteToDraw*)vd->spritelist_mem;
   495 
   501 
   496 	if (vd->parent_list >= vd->eof_parent_list) {
   502 	if (vd->parent_list >= vd->eof_parent_list) {
   497 		// This can happen rarely, mostly when you zoom out completely
   503 		/* This can happen rarely, mostly when you zoom out completely
   498 		//  and have a lot of stuff that moves (and is added to the
   504 		 *  and have a lot of stuff that moves (and is added to the
   499 		//  sort-list, this function). To solve it, increase
   505 		 *  sort-list, this function). To solve it, increase
   500 		//  parent_list somewhere below to a higher number.
   506 		 *  parent_list somewhere below to a higher number.
   501 		// This can not really hurt you, it just gives some black
   507 		 * This can not really hurt you, it just gives some black
   502 		//  spots on the screen ;)
   508 		 *  spots on the screen ;) */
   503 		DEBUG(sprite, 0, "Out of sprite memory (parent_list)");
   509 		DEBUG(sprite, 0, "Out of sprite memory (parent_list)");
   504 		return;
   510 		return;
   505 	}
   511 	}
   506 
   512 
   507 	pt = RemapCoords(x, y, z);
   513 	pt = RemapCoords(x, y, z);
   645 static void DrawTileSelection(const TileInfo *ti)
   651 static void DrawTileSelection(const TileInfo *ti)
   646 {
   652 {
   647 	SpriteID image;
   653 	SpriteID image;
   648 	SpriteID pal;
   654 	SpriteID pal;
   649 
   655 
   650 	// Draw a red error square?
   656 	/* Draw a red error square? */
   651 	if (_thd.redsq != 0 && _thd.redsq == ti->tile) {
   657 	if (_thd.redsq != 0 && _thd.redsq == ti->tile) {
   652 		DrawSelectionSprite(SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh], PALETTE_TILE_RED_PULSATING, ti);
   658 		DrawSelectionSprite(SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh], PALETTE_TILE_RED_PULSATING, ti);
   653 		return;
   659 		return;
   654 	}
   660 	}
   655 
   661 
   656 	// no selection active?
   662 	/* no selection active? */
   657 	if (_thd.drawstyle == 0) return;
   663 	if (_thd.drawstyle == 0) return;
   658 
   664 
   659 	// Inside the inner area?
   665 	/* Inside the inner area? */
   660 	if (IS_INSIDE_1D(ti->x, _thd.pos.x, _thd.size.x) &&
   666 	if (IS_INSIDE_1D(ti->x, _thd.pos.x, _thd.size.x) &&
   661 			IS_INSIDE_1D(ti->y, _thd.pos.y, _thd.size.y)) {
   667 			IS_INSIDE_1D(ti->y, _thd.pos.y, _thd.size.y)) {
   662 		if (_thd.drawstyle & HT_RECT) {
   668 		if (_thd.drawstyle & HT_RECT) {
   663 			if ((_thd.airport_template) &&
   669 			if ((_thd.airport_template) &&
   664 				((byte)(_airport_sections[_thd.airport][((ti->x - _thd.pos.x) / TILE_SIZE ) + ((ti->y - _thd.pos.y) / TILE_SIZE * _thd.size.x / TILE_SIZE)]) != 255)) {
   670 				((byte)(_airport_sections[_thd.airport][((ti->x - _thd.pos.x) / TILE_SIZE ) + ((ti->y - _thd.pos.y) / TILE_SIZE * _thd.size.x / TILE_SIZE)]) != 255)) {
   667 			} else if (!_thd.airport_template) {
   673 			} else if (!_thd.airport_template) {
   668 				image = SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh];
   674 				image = SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh];
   669 				DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE, ti);
   675 				DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE, ti);
   670 			}
   676 			}
   671 		} else if (_thd.drawstyle & HT_POINT) {
   677 		} else if (_thd.drawstyle & HT_POINT) {
   672 			// Figure out the Z coordinate for the single dot.
   678 			/* Figure out the Z coordinate for the single dot. */
   673 			byte z = ti->z;
   679 			byte z = ti->z;
   674 			if (ti->tileh & SLOPE_N) {
   680 			if (ti->tileh & SLOPE_N) {
   675 				z += TILE_HEIGHT;
   681 				z += TILE_HEIGHT;
   676 				if (ti->tileh == SLOPE_STEEP_N) z += TILE_HEIGHT;
   682 				if (ti->tileh == SLOPE_STEEP_N) z += TILE_HEIGHT;
   677 			}
   683 			}
   678 			DrawGroundSpriteAt(_cur_dpi->zoom != 2 ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti->x, ti->y, z);
   684 			DrawGroundSpriteAt(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti->x, ti->y, z);
   679 		} else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) {
   685 		} else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) {
   680 			// autorail highlight piece under cursor
   686 			/* autorail highlight piece under cursor */
   681 			uint type = _thd.drawstyle & 0xF;
   687 			uint type = _thd.drawstyle & 0xF;
   682 			int offset;
   688 			int offset;
   683 
   689 
   684 			assert(type <= 5);
   690 			assert(type <= 5);
   685 
   691 
   693 			}
   699 			}
   694 
   700 
   695 			DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti);
   701 			DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti);
   696 
   702 
   697 		} else if (IsPartOfAutoLine(ti->x, ti->y)) {
   703 		} else if (IsPartOfAutoLine(ti->x, ti->y)) {
   698 			// autorail highlighting long line
   704 			/* autorail highlighting long line */
   699 			int dir = _thd.drawstyle & ~0xF0;
   705 			int dir = _thd.drawstyle & ~0xF0;
   700 			int offset;
   706 			int offset;
   701 			uint side;
   707 			uint side;
   702 
   708 
   703 			if (dir < 2) {
   709 			if (dir < 2) {
   719 			DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti);
   725 			DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti);
   720 		}
   726 		}
   721 		return;
   727 		return;
   722 	}
   728 	}
   723 
   729 
   724 	// Check if it's inside the outer area?
   730 	/* Check if it's inside the outer area? */
   725 	if (_thd.outersize.x &&
   731 	if (_thd.outersize.x &&
   726 			_thd.size.x < _thd.size.x + _thd.outersize.x &&
   732 			_thd.size.x < _thd.size.x + _thd.outersize.x &&
   727 			IS_INSIDE_1D(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
   733 			IS_INSIDE_1D(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
   728 			IS_INSIDE_1D(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
   734 			IS_INSIDE_1D(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
   729 		// Draw a blue rect.
   735 		/* Draw a blue rect. */
   730 		DrawSelectionSprite(SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh], PALETTE_SEL_TILE_BLUE, ti);
   736 		DrawSelectionSprite(SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh], PALETTE_SEL_TILE_BLUE, ti);
   731 		return;
   737 		return;
   732 	}
   738 	}
   733 }
   739 }
   734 
   740 
   739 	TileInfo ti;
   745 	TileInfo ti;
   740 	bool direction;
   746 	bool direction;
   741 
   747 
   742 	_cur_ti = &ti;
   748 	_cur_ti = &ti;
   743 
   749 
   744 	// Transform into tile coordinates and round to closest full tile
   750 	/* Transform into tile coordinates and round to closest full tile */
   745 	x = ((vd->dpi.top >> 1) - (vd->dpi.left >> 2)) & ~0xF;
   751 	x = ((vd->dpi.top >> 1) - (vd->dpi.left >> 2)) & ~0xF;
   746 	y = ((vd->dpi.top >> 1) + (vd->dpi.left >> 2) - 0x10) & ~0xF;
   752 	y = ((vd->dpi.top >> 1) + (vd->dpi.left >> 2) - 0x10) & ~0xF;
   747 
   753 
   748 	// determine size of area
   754 	/* determine size of area */
   749 	{
   755 	{
   750 		Point pt = RemapCoords(x, y, 241);
   756 		Point pt = RemapCoords(x, y, 241);
   751 		width = (vd->dpi.left + vd->dpi.width - pt.x + 95) >> 6;
   757 		width = (vd->dpi.left + vd->dpi.width - pt.x + 95) >> 6;
   752 		height = (vd->dpi.top + vd->dpi.height - pt.y) >> 5 << 1;
   758 		height = (vd->dpi.top + vd->dpi.height - pt.y) >> 5 << 1;
   753 	}
   759 	}
   803 static void ViewportAddTownNames(DrawPixelInfo *dpi)
   809 static void ViewportAddTownNames(DrawPixelInfo *dpi)
   804 {
   810 {
   805 	Town *t;
   811 	Town *t;
   806 	int left, top, right, bottom;
   812 	int left, top, right, bottom;
   807 
   813 
   808 	if (!(_display_opt & DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU)
   814 	if (!HASBIT(_display_opt, DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU)
   809 		return;
   815 		return;
   810 
   816 
   811 	left = dpi->left;
   817 	left = dpi->left;
   812 	top = dpi->top;
   818 	top = dpi->top;
   813 	right = left + dpi->width;
   819 	right = left + dpi->width;
   814 	bottom = top + dpi->height;
   820 	bottom = top + dpi->height;
   815 
   821 
   816 	switch (dpi->zoom) {
   822 	switch (dpi->zoom) {
   817 		case 0:
   823 		case ZOOM_LVL_NORMAL:
   818 			FOR_ALL_TOWNS(t) {
   824 			FOR_ALL_TOWNS(t) {
   819 				if (bottom > t->sign.top &&
   825 				if (bottom > t->sign.top &&
   820 						top    < t->sign.top + 12 &&
   826 						top    < t->sign.top + 12 &&
   821 						right  > t->sign.left &&
   827 						right  > t->sign.left &&
   822 						left   < t->sign.left + t->sign.width_1) {
   828 						left   < t->sign.left + t->sign.width_1) {
   825 						t->index, t->population);
   831 						t->index, t->population);
   826 				}
   832 				}
   827 			}
   833 			}
   828 			break;
   834 			break;
   829 
   835 
   830 		case 1:
   836 		case ZOOM_LVL_OUT_2X:
   831 			right += 2;
   837 			right += 2;
   832 			bottom += 2;
   838 			bottom += 2;
   833 
   839 
   834 			FOR_ALL_TOWNS(t) {
   840 			FOR_ALL_TOWNS(t) {
   835 				if (bottom > t->sign.top &&
   841 				if (bottom > t->sign.top &&
   841 						t->index, t->population);
   847 						t->index, t->population);
   842 				}
   848 				}
   843 			}
   849 			}
   844 			break;
   850 			break;
   845 
   851 
   846 		default: NOT_REACHED();
   852 		case ZOOM_LVL_OUT_4X:
   847 		case 2:
   853 		case ZOOM_LVL_OUT_8X:
   848 			right += 4;
   854 			right += ScaleByZoom(1, dpi->zoom);
   849 			bottom += 5;
   855 			bottom += ScaleByZoom(1, dpi->zoom) + 1;
   850 
   856 
   851 			FOR_ALL_TOWNS(t) {
   857 			FOR_ALL_TOWNS(t) {
   852 				if (bottom > t->sign.top &&
   858 				if (bottom > t->sign.top &&
   853 						top    < t->sign.top + 24 &&
   859 						top    < t->sign.top + ScaleByZoom(12, dpi->zoom) &&
   854 						right  > t->sign.left &&
   860 						right  > t->sign.left &&
   855 						left   < t->sign.left + t->sign.width_2*4) {
   861 						left   < t->sign.left + ScaleByZoom(t->sign.width_2, dpi->zoom)) {
   856 					AddStringToDraw(t->sign.left + 5, t->sign.top + 1, STR_TOWN_LABEL_TINY_BLACK, t->index, 0);
   862 					AddStringToDraw(t->sign.left + 5, t->sign.top + 1, STR_TOWN_LABEL_TINY_BLACK, t->index, 0);
   857 					AddStringToDraw(t->sign.left + 1, t->sign.top - 3, STR_TOWN_LABEL_TINY_WHITE, t->index, 0);
   863 					AddStringToDraw(t->sign.left + 1, t->sign.top - 3, STR_TOWN_LABEL_TINY_WHITE, t->index, 0);
   858 				}
   864 				}
   859 			}
   865 			}
   860 			break;
   866 			break;
       
   867 
       
   868 		case ZOOM_LVL_OUT_16X:
       
   869 			break;
       
   870 
       
   871 		default: NOT_REACHED();
   861 	}
   872 	}
   862 }
   873 }
   863 
   874 
   864 
   875 
   865 static void AddStation(const Station *st, StringID str, uint16 width)
   876 static void AddStation(const Station *st, StringID str, uint16 width)
   877 static void ViewportAddStationNames(DrawPixelInfo *dpi)
   888 static void ViewportAddStationNames(DrawPixelInfo *dpi)
   878 {
   889 {
   879 	int left, top, right, bottom;
   890 	int left, top, right, bottom;
   880 	const Station *st;
   891 	const Station *st;
   881 
   892 
   882 	if (!(_display_opt & DO_SHOW_STATION_NAMES) || _game_mode == GM_MENU)
   893 	if (!HASBIT(_display_opt, DO_SHOW_STATION_NAMES) || _game_mode == GM_MENU)
   883 		return;
   894 		return;
   884 
   895 
   885 	left = dpi->left;
   896 	left = dpi->left;
   886 	top = dpi->top;
   897 	top = dpi->top;
   887 	right = left + dpi->width;
   898 	right = left + dpi->width;
   888 	bottom = top + dpi->height;
   899 	bottom = top + dpi->height;
   889 
   900 
   890 	switch (dpi->zoom) {
   901 	switch (dpi->zoom) {
   891 		case 0:
   902 		case ZOOM_LVL_NORMAL:
   892 			FOR_ALL_STATIONS(st) {
   903 			FOR_ALL_STATIONS(st) {
   893 				if (bottom > st->sign.top &&
   904 				if (bottom > st->sign.top &&
   894 						top    < st->sign.top + 12 &&
   905 						top    < st->sign.top + 12 &&
   895 						right  > st->sign.left &&
   906 						right  > st->sign.left &&
   896 						left   < st->sign.left + st->sign.width_1) {
   907 						left   < st->sign.left + st->sign.width_1) {
   897 					AddStation(st, STR_305C_0, st->sign.width_1);
   908 					AddStation(st, STR_305C_0, st->sign.width_1);
   898 				}
   909 				}
   899 			}
   910 			}
   900 			break;
   911 			break;
   901 
   912 
   902 		case 1:
   913 		case ZOOM_LVL_OUT_2X:
   903 			right += 2;
   914 			right += 2;
   904 			bottom += 2;
   915 			bottom += 2;
   905 			FOR_ALL_STATIONS(st) {
   916 			FOR_ALL_STATIONS(st) {
   906 				if (bottom > st->sign.top &&
   917 				if (bottom > st->sign.top &&
   907 						top    < st->sign.top + 24 &&
   918 						top    < st->sign.top + 24 &&
   910 					AddStation(st, STR_305C_0, st->sign.width_1);
   921 					AddStation(st, STR_305C_0, st->sign.width_1);
   911 				}
   922 				}
   912 			}
   923 			}
   913 			break;
   924 			break;
   914 
   925 
   915 		default: NOT_REACHED();
   926 		case ZOOM_LVL_OUT_4X:
   916 		case 2:
   927 		case ZOOM_LVL_OUT_8X:
   917 			right += 4;
   928 			right += ScaleByZoom(1, dpi->zoom);
   918 			bottom += 5;
   929 			bottom += ScaleByZoom(1, dpi->zoom) + 1;
       
   930 
   919 			FOR_ALL_STATIONS(st) {
   931 			FOR_ALL_STATIONS(st) {
   920 				if (bottom > st->sign.top &&
   932 				if (bottom > st->sign.top &&
   921 						top    < st->sign.top + 24 &&
   933 						top    < st->sign.top + ScaleByZoom(12, dpi->zoom) &&
   922 						right  > st->sign.left &&
   934 						right  > st->sign.left &&
   923 						left   < st->sign.left + st->sign.width_2*4) {
   935 						left   < st->sign.left + ScaleByZoom(st->sign.width_2, dpi->zoom)) {
   924 					AddStation(st, STR_STATION_SIGN_TINY, st->sign.width_2 | 0x8000);
   936 					AddStation(st, STR_STATION_SIGN_TINY, st->sign.width_2 | 0x8000);
   925 				}
   937 				}
   926 			}
   938 			}
   927 			break;
   939 			break;
       
   940 
       
   941 		case ZOOM_LVL_OUT_16X:
       
   942 			break;
       
   943 
       
   944 		default: NOT_REACHED();
   928 	}
   945 	}
   929 }
   946 }
   930 
   947 
   931 
   948 
   932 static void AddSign(const Sign *si, StringID str, uint16 width)
   949 static void AddSign(const Sign *si, StringID str, uint16 width)
   944 static void ViewportAddSigns(DrawPixelInfo *dpi)
   961 static void ViewportAddSigns(DrawPixelInfo *dpi)
   945 {
   962 {
   946 	const Sign *si;
   963 	const Sign *si;
   947 	int left, top, right, bottom;
   964 	int left, top, right, bottom;
   948 
   965 
   949 	if (!(_display_opt & DO_SHOW_SIGNS))
   966 	if (!HASBIT(_display_opt, DO_SHOW_SIGNS))
   950 		return;
   967 		return;
   951 
   968 
   952 	left = dpi->left;
   969 	left = dpi->left;
   953 	top = dpi->top;
   970 	top = dpi->top;
   954 	right = left + dpi->width;
   971 	right = left + dpi->width;
   955 	bottom = top + dpi->height;
   972 	bottom = top + dpi->height;
   956 
   973 
   957 	switch (dpi->zoom) {
   974 	switch (dpi->zoom) {
   958 		case 0:
   975 		case ZOOM_LVL_NORMAL:
   959 			FOR_ALL_SIGNS(si) {
   976 			FOR_ALL_SIGNS(si) {
   960 				if (bottom > si->sign.top &&
   977 				if (bottom > si->sign.top &&
   961 						top    < si->sign.top + 12 &&
   978 						top    < si->sign.top + 12 &&
   962 						right  > si->sign.left &&
   979 						right  > si->sign.left &&
   963 						left   < si->sign.left + si->sign.width_1) {
   980 						left   < si->sign.left + si->sign.width_1) {
   964 					AddSign(si, STR_2806, si->sign.width_1);
   981 					AddSign(si, STR_2806, si->sign.width_1);
   965 				}
   982 				}
   966 			}
   983 			}
   967 			break;
   984 			break;
   968 
   985 
   969 		case 1:
   986 		case ZOOM_LVL_OUT_2X:
   970 			right += 2;
   987 			right += 2;
   971 			bottom += 2;
   988 			bottom += 2;
   972 			FOR_ALL_SIGNS(si) {
   989 			FOR_ALL_SIGNS(si) {
   973 				if (bottom > si->sign.top &&
   990 				if (bottom > si->sign.top &&
   974 						top    < si->sign.top + 24 &&
   991 						top    < si->sign.top + 24 &&
   977 					AddSign(si, STR_2806, si->sign.width_1);
   994 					AddSign(si, STR_2806, si->sign.width_1);
   978 				}
   995 				}
   979 			}
   996 			}
   980 			break;
   997 			break;
   981 
   998 
   982 		default: NOT_REACHED();
   999 		case ZOOM_LVL_OUT_4X:
   983 		case 2:
  1000 		case ZOOM_LVL_OUT_8X:
   984 			right += 4;
  1001 			right += ScaleByZoom(1, dpi->zoom);
   985 			bottom += 5;
  1002 			bottom += ScaleByZoom(1, dpi->zoom) + 1;
       
  1003 
   986 			FOR_ALL_SIGNS(si) {
  1004 			FOR_ALL_SIGNS(si) {
   987 				if (bottom > si->sign.top &&
  1005 				if (bottom > si->sign.top &&
   988 						top    < si->sign.top + 24 &&
  1006 						top    < si->sign.top + ScaleByZoom(12, dpi->zoom) &&
   989 						right  > si->sign.left &&
  1007 						right  > si->sign.left &&
   990 						left   < si->sign.left + si->sign.width_2 * 4) {
  1008 						left   < si->sign.left + ScaleByZoom(si->sign.width_2, dpi->zoom)) {
   991 					AddSign(si, STR_2002, si->sign.width_2 | 0x8000);
  1009 					AddSign(si, STR_2002, si->sign.width_2 | 0x8000);
   992 				}
  1010 				}
   993 			}
  1011 			}
   994 			break;
  1012 			break;
       
  1013 
       
  1014 		case ZOOM_LVL_OUT_16X:
       
  1015 			break;
       
  1016 
       
  1017 		default: NOT_REACHED();
   995 	}
  1018 	}
   996 }
  1019 }
   997 
  1020 
   998 
  1021 
   999 static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width)
  1022 static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width)
  1011 static void ViewportAddWaypoints(DrawPixelInfo *dpi)
  1034 static void ViewportAddWaypoints(DrawPixelInfo *dpi)
  1012 {
  1035 {
  1013 	const Waypoint *wp;
  1036 	const Waypoint *wp;
  1014 	int left, top, right, bottom;
  1037 	int left, top, right, bottom;
  1015 
  1038 
  1016 	if (!(_display_opt & DO_WAYPOINTS))
  1039 	if (!HASBIT(_display_opt, DO_WAYPOINTS))
  1017 		return;
  1040 		return;
  1018 
  1041 
  1019 	left = dpi->left;
  1042 	left = dpi->left;
  1020 	top = dpi->top;
  1043 	top = dpi->top;
  1021 	right = left + dpi->width;
  1044 	right = left + dpi->width;
  1022 	bottom = top + dpi->height;
  1045 	bottom = top + dpi->height;
  1023 
  1046 
  1024 	switch (dpi->zoom) {
  1047 	switch (dpi->zoom) {
  1025 		case 0:
  1048 		case ZOOM_LVL_NORMAL:
  1026 			FOR_ALL_WAYPOINTS(wp) {
  1049 			FOR_ALL_WAYPOINTS(wp) {
  1027 				if (bottom > wp->sign.top &&
  1050 				if (bottom > wp->sign.top &&
  1028 						top    < wp->sign.top + 12 &&
  1051 						top    < wp->sign.top + 12 &&
  1029 						right  > wp->sign.left &&
  1052 						right  > wp->sign.left &&
  1030 						left   < wp->sign.left + wp->sign.width_1) {
  1053 						left   < wp->sign.left + wp->sign.width_1) {
  1031 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
  1054 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
  1032 				}
  1055 				}
  1033 			}
  1056 			}
  1034 			break;
  1057 			break;
  1035 
  1058 
  1036 		case 1:
  1059 		case ZOOM_LVL_OUT_2X:
  1037 			right += 2;
  1060 			right += 2;
  1038 			bottom += 2;
  1061 			bottom += 2;
  1039 			FOR_ALL_WAYPOINTS(wp) {
  1062 			FOR_ALL_WAYPOINTS(wp) {
  1040 				if (bottom > wp->sign.top &&
  1063 				if (bottom > wp->sign.top &&
  1041 						top    < wp->sign.top + 24 &&
  1064 						top    < wp->sign.top + 24 &&
  1044 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
  1067 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT, wp->sign.width_1);
  1045 				}
  1068 				}
  1046 			}
  1069 			}
  1047 			break;
  1070 			break;
  1048 
  1071 
  1049 		default: NOT_REACHED();
  1072 		case ZOOM_LVL_OUT_4X:
  1050 		case 2:
  1073 		case ZOOM_LVL_OUT_8X:
  1051 			right += 4;
  1074 			right += ScaleByZoom(1, dpi->zoom);
  1052 			bottom += 5;
  1075 			bottom += ScaleByZoom(1, dpi->zoom) + 1;
       
  1076 
  1053 			FOR_ALL_WAYPOINTS(wp) {
  1077 			FOR_ALL_WAYPOINTS(wp) {
  1054 				if (bottom > wp->sign.top &&
  1078 				if (bottom > wp->sign.top &&
  1055 						top    < wp->sign.top + 24 &&
  1079 						top    < wp->sign.top + ScaleByZoom(12, dpi->zoom) &&
  1056 						right  > wp->sign.left &&
  1080 						right  > wp->sign.left &&
  1057 						left   < wp->sign.left + wp->sign.width_2*4) {
  1081 						left   < wp->sign.left + ScaleByZoom(wp->sign.width_2, dpi->zoom)) {
  1058 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT_TINY, wp->sign.width_2 | 0x8000);
  1082 					AddWaypoint(wp, STR_WAYPOINT_VIEWPORT_TINY, wp->sign.width_2 | 0x8000);
  1059 				}
  1083 				}
  1060 			}
  1084 			}
  1061 			break;
  1085 			break;
       
  1086 
       
  1087 		case ZOOM_LVL_OUT_16X:
       
  1088 			break;
       
  1089 
       
  1090 		default: NOT_REACHED();
  1062 	}
  1091 	}
  1063 }
  1092 }
  1064 
  1093 
  1065 void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str)
  1094 void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str)
  1066 {
  1095 {
  1133 							)) {
  1162 							)) {
  1134 						continue;
  1163 						continue;
  1135 					}
  1164 					}
  1136 				}
  1165 				}
  1137 
  1166 
  1138 				// Swap the two sprites ps and ps2 using bubble-sort algorithm.
  1167 				/* Swap the two sprites ps and ps2 using bubble-sort algorithm. */
  1139 				psd3 = psd;
  1168 				psd3 = psd;
  1140 				do {
  1169 				do {
  1141 					ParentSpriteToDraw* temp = *psd3;
  1170 					ParentSpriteToDraw* temp = *psd3;
  1142 					*psd3 = ps2;
  1171 					*psd3 = ps2;
  1143 					ps2 = temp;
  1172 					ps2 = temp;
  1167 }
  1196 }
  1168 
  1197 
  1169 static void ViewportDrawStrings(DrawPixelInfo *dpi, const StringSpriteToDraw *ss)
  1198 static void ViewportDrawStrings(DrawPixelInfo *dpi, const StringSpriteToDraw *ss)
  1170 {
  1199 {
  1171 	DrawPixelInfo dp;
  1200 	DrawPixelInfo dp;
  1172 	byte zoom;
  1201 	ZoomLevel zoom;
  1173 
  1202 
  1174 	_cur_dpi = &dp;
  1203 	_cur_dpi = &dp;
  1175 	dp = *dpi;
  1204 	dp = *dpi;
  1176 
  1205 
  1177 	zoom = dp.zoom;
  1206 	zoom = dp.zoom;
  1178 	dp.zoom = 0;
  1207 	dp.zoom = ZOOM_LVL_NORMAL;
  1179 
  1208 
  1180 	dp.left >>= zoom;
  1209 	dp.left   = UnScaleByZoom(dp.left,   zoom);
  1181 	dp.top >>= zoom;
  1210 	dp.top    = UnScaleByZoom(dp.top,    zoom);
  1182 	dp.width >>= zoom;
  1211 	dp.width  = UnScaleByZoom(dp.width,  zoom);
  1183 	dp.height >>= zoom;
  1212 	dp.height = UnScaleByZoom(dp.height, zoom);
  1184 
  1213 
  1185 	do {
  1214 	do {
  1186 		uint16 colour;
  1215 		uint16 colour;
  1187 
  1216 
  1188 		if (ss->width != 0) {
  1217 		if (ss->width != 0) {
  1189 			int x = (ss->x >> zoom) - 1;
  1218 			int x = UnScaleByZoom(ss->x, zoom) - 1;
  1190 			int y = (ss->y >> zoom) - 1;
  1219 			int y = UnScaleByZoom(ss->y, zoom) - 1;
  1191 			int bottom = y + 11;
  1220 			int bottom = y + 11;
  1192 			int w = ss->width;
  1221 			int w = ss->width;
  1193 
  1222 
  1194 			if (w & 0x8000) {
  1223 			if (w & 0x8000) {
  1195 				w &= ~0x8000;
  1224 				w &= ~0x8000;
  1198 				w -= 3;
  1227 				w -= 3;
  1199 			}
  1228 			}
  1200 
  1229 
  1201 		/* Draw the rectangle if 'tranparent station signs' is off,
  1230 		/* Draw the rectangle if 'tranparent station signs' is off,
  1202 		 * or if we are drawing a general text sign (STR_2806) */
  1231 		 * or if we are drawing a general text sign (STR_2806) */
  1203 			if (!(_display_opt & DO_TRANS_SIGNS) || ss->string == STR_2806)
  1232 			if (!HASBIT(_transparent_opt, TO_SIGNS) || ss->string == STR_2806) {
  1204 				DrawFrameRect(
  1233 				DrawFrameRect(
  1205 					x, y, x + w, bottom, ss->color,
  1234 					x, y, x + w, bottom, ss->color,
  1206 					(_display_opt & DO_TRANS_BUILDINGS) ? FR_TRANSPARENT : FR_NONE
  1235 					HASBIT(_transparent_opt, TO_SIGNS) ? FR_TRANSPARENT : FR_NONE
  1207 				);
  1236 				);
       
  1237 			}
  1208 		}
  1238 		}
  1209 
  1239 
  1210 		SetDParam(0, ss->params[0]);
  1240 		SetDParam(0, ss->params[0]);
  1211 		SetDParam(1, ss->params[1]);
  1241 		SetDParam(1, ss->params[1]);
  1212 		/* if we didn't draw a rectangle, or if transparant building is on,
  1242 		/* if we didn't draw a rectangle, or if transparant building is on,
  1213 		 * draw the text in the color the rectangle would have */
  1243 		 * draw the text in the color the rectangle would have */
  1214 		if ((
  1244 		if (HASBIT(_transparent_opt, TO_SIGNS) && ss->string != STR_2806 && ss->width != 0) {
  1215 					(_display_opt & DO_TRANS_BUILDINGS) ||
       
  1216 					(_display_opt & DO_TRANS_SIGNS && ss->string != STR_2806)
       
  1217 				) && ss->width != 0) {
       
  1218 			/* Real colors need the IS_PALETTE_COLOR flag
  1245 			/* Real colors need the IS_PALETTE_COLOR flag
  1219 			 * otherwise colors from _string_colormap are assumed. */
  1246 			 * otherwise colors from _string_colormap are assumed. */
  1220 			colour = _colour_gradient[ss->color][6] | IS_PALETTE_COLOR;
  1247 			colour = _colour_gradient[ss->color][6] | IS_PALETTE_COLOR;
  1221 		} else {
  1248 		} else {
  1222 			colour = 16;
  1249 			colour = 16;
  1223 		}
  1250 		}
  1224 		DrawString(
  1251 		DrawString(
  1225 			ss->x >> zoom, (ss->y >> zoom) - (ss->width & 0x8000 ? 2 : 0),
  1252 			UnScaleByZoom(ss->x, zoom), UnScaleByZoom(ss->y, zoom) - (ss->width & 0x8000 ? 2 : 0),
  1226 			ss->string, colour
  1253 			ss->string, colour
  1227 		);
  1254 		);
  1228 
  1255 
  1229 		ss = ss->next;
  1256 		ss = ss->next;
  1230 	} while (ss != NULL);
  1257 	} while (ss != NULL);
  1245 
  1272 
  1246 	old_dpi = _cur_dpi;
  1273 	old_dpi = _cur_dpi;
  1247 	_cur_dpi = &vd.dpi;
  1274 	_cur_dpi = &vd.dpi;
  1248 
  1275 
  1249 	vd.dpi.zoom = vp->zoom;
  1276 	vd.dpi.zoom = vp->zoom;
  1250 	mask = (-1) << vp->zoom;
  1277 	mask = ScaleByZoom(-1, vp->zoom);
  1251 
  1278 
  1252 	vd.combine_sprites = 0;
  1279 	vd.combine_sprites = 0;
  1253 
  1280 
  1254 	vd.dpi.width = (right - left) & mask;
  1281 	vd.dpi.width = (right - left) & mask;
  1255 	vd.dpi.height = (bottom - top) & mask;
  1282 	vd.dpi.height = (bottom - top) & mask;
  1256 	vd.dpi.left = left & mask;
  1283 	vd.dpi.left = left & mask;
  1257 	vd.dpi.top = top & mask;
  1284 	vd.dpi.top = top & mask;
  1258 	vd.dpi.pitch = old_dpi->pitch;
  1285 	vd.dpi.pitch = old_dpi->pitch;
  1259 
  1286 
  1260 	x = ((vd.dpi.left - (vp->virtual_left&mask)) >> vp->zoom) + vp->left;
  1287 	x = UnScaleByZoom(vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
  1261 	y = ((vd.dpi.top - (vp->virtual_top&mask)) >> vp->zoom) + vp->top;
  1288 	y = UnScaleByZoom(vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
  1262 
  1289 
  1263 	vd.dpi.dst_ptr = old_dpi->dst_ptr + x - old_dpi->left + (y - old_dpi->top) * old_dpi->pitch;
  1290 	vd.dpi.dst_ptr = old_dpi->dst_ptr + x - old_dpi->left + (y - old_dpi->top) * old_dpi->pitch;
  1264 
  1291 
  1265 	vd.parent_list = parent_list;
  1292 	vd.parent_list = parent_list;
  1266 	vd.eof_parent_list = endof(parent_list);
  1293 	vd.eof_parent_list = endof(parent_list);
  1278 	ViewportAddTownNames(&vd.dpi);
  1305 	ViewportAddTownNames(&vd.dpi);
  1279 	ViewportAddStationNames(&vd.dpi);
  1306 	ViewportAddStationNames(&vd.dpi);
  1280 	ViewportAddSigns(&vd.dpi);
  1307 	ViewportAddSigns(&vd.dpi);
  1281 	ViewportAddWaypoints(&vd.dpi);
  1308 	ViewportAddWaypoints(&vd.dpi);
  1282 
  1309 
  1283 	// This assert should never happen (because the length of the parent_list
  1310 	/* This assert should never happen (because the length of the parent_list
  1284 	//  is checked)
  1311 	 *  is checked) */
  1285 	assert(vd.parent_list <= endof(parent_list));
  1312 	assert(vd.parent_list <= endof(parent_list));
  1286 
  1313 
  1287 	if (vd.first_tile != NULL) ViewportDrawTileSprites(vd.first_tile);
  1314 	if (vd.first_tile != NULL) ViewportDrawTileSprites(vd.first_tile);
  1288 
  1315 
  1289 	/* null terminate parent sprite list */
  1316 	/* null terminate parent sprite list */
  1295 	if (vd.first_string != NULL) ViewportDrawStrings(&vd.dpi, vd.first_string);
  1322 	if (vd.first_string != NULL) ViewportDrawStrings(&vd.dpi, vd.first_string);
  1296 
  1323 
  1297 	_cur_dpi = old_dpi;
  1324 	_cur_dpi = old_dpi;
  1298 }
  1325 }
  1299 
  1326 
  1300 // Make sure we don't draw a too big area at a time.
  1327 /** Make sure we don't draw a too big area at a time.
  1301 // If we do, the sprite memory will overflow.
  1328  * If we do, the sprite memory will overflow. */
  1302 static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
  1329 static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
  1303 {
  1330 {
  1304 	if (((bottom - top) * (right - left) << (2 * vp->zoom)) > 180000) {
  1331 	if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000) {
  1305 		if ((bottom - top) > (right - left)) {
  1332 		if ((bottom - top) > (right - left)) {
  1306 			int t = (top + bottom) >> 1;
  1333 			int t = (top + bottom) >> 1;
  1307 			ViewportDrawChk(vp, left, top, right, t);
  1334 			ViewportDrawChk(vp, left, top, right, t);
  1308 			ViewportDrawChk(vp, left, t, right, bottom);
  1335 			ViewportDrawChk(vp, left, t, right, bottom);
  1309 		} else {
  1336 		} else {
  1311 			ViewportDrawChk(vp, left, top, t, bottom);
  1338 			ViewportDrawChk(vp, left, top, t, bottom);
  1312 			ViewportDrawChk(vp, t, top, right, bottom);
  1339 			ViewportDrawChk(vp, t, top, right, bottom);
  1313 		}
  1340 		}
  1314 	} else {
  1341 	} else {
  1315 		ViewportDoDraw(vp,
  1342 		ViewportDoDraw(vp,
  1316 			((left - vp->left) << vp->zoom) + vp->virtual_left,
  1343 			ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
  1317 			((top - vp->top) << vp->zoom) + vp->virtual_top,
  1344 			ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top,
  1318 			((right - vp->left) << vp->zoom) + vp->virtual_left,
  1345 			ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left,
  1319 			((bottom - vp->top) << vp->zoom) + vp->virtual_top
  1346 			ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top
  1320 		);
  1347 		);
  1321 	}
  1348 	}
  1322 }
  1349 }
  1323 
  1350 
  1324 static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
  1351 static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
  1364 		int x;
  1391 		int x;
  1365 		int y;
  1392 		int y;
  1366 		int vx;
  1393 		int vx;
  1367 		int vy;
  1394 		int vy;
  1368 
  1395 
  1369 		// Center of the viewport is hot spot
  1396 		/* Center of the viewport is hot spot */
  1370 		x = WP(w,vp_d).scrollpos_x + vp->virtual_width / 2;
  1397 		x = WP(w,vp_d).scrollpos_x + vp->virtual_width / 2;
  1371 		y = WP(w,vp_d).scrollpos_y + vp->virtual_height / 2;
  1398 		y = WP(w,vp_d).scrollpos_y + vp->virtual_height / 2;
  1372 		// Convert viewport coordinates to map coordinates
  1399 
  1373 		// Calculation is scaled by 4 to avoid rounding errors
  1400 		int dest_x = WP(w,vp_d).dest_scrollpos_x + vp->virtual_width / 2;
       
  1401 		int dest_y = WP(w,vp_d).dest_scrollpos_y + vp->virtual_height / 2;
       
  1402 
       
  1403 		int delta_x = dest_x - x;
       
  1404 		int delta_y = dest_y - y;
       
  1405 
       
  1406 		if (delta_x != 0 || delta_y != 0) {
       
  1407 			if (_patches.smooth_scroll) {
       
  1408 				int max_scroll = ScaleByMapSize1D(512);
       
  1409 				/* Not at our desired positon yet... */
       
  1410 				x += clamp(delta_x / 8, -max_scroll, max_scroll);
       
  1411 				y += clamp(delta_y / 8, -max_scroll, max_scroll);
       
  1412 			} else {
       
  1413 				x = dest_x;
       
  1414 				y = dest_y;
       
  1415 			}
       
  1416 		}
       
  1417 
       
  1418 		/* Convert viewport coordinates to map coordinates
       
  1419 		 * Calculation is scaled by 4 to avoid rounding errors */
  1374 		vx = -x + y * 2;
  1420 		vx = -x + y * 2;
  1375 		vy =  x + y * 2;
  1421 		vy =  x + y * 2;
  1376 		// clamp to size of map
  1422 		/* clamp to size of map */
  1377 		vx = clamp(vx, 0 * 4, MapMaxX() * TILE_SIZE * 4);
  1423 		vx = clamp(vx, 0 * 4, MapMaxX() * TILE_SIZE * 4);
  1378 		vy = clamp(vy, 0 * 4, MapMaxY() * TILE_SIZE * 4);
  1424 		vy = clamp(vy, 0 * 4, MapMaxY() * TILE_SIZE * 4);
  1379 		// Convert map coordinates to viewport coordinates
  1425 		/* Convert map coordinates to viewport coordinates */
  1380 		x = (-vx + vy) / 2;
  1426 		x = (-vx + vy) / 2;
  1381 		y = ( vx + vy) / 4;
  1427 		y = ( vx + vy) / 4;
  1382 		// Set position
  1428 		/* Set position */
  1383 		WP(w, vp_d).scrollpos_x = x - vp->virtual_width / 2;
  1429 		WP(w, vp_d).scrollpos_x = x - vp->virtual_width / 2;
  1384 		WP(w, vp_d).scrollpos_y = y - vp->virtual_height / 2;
  1430 		WP(w, vp_d).scrollpos_y = y - vp->virtual_height / 2;
  1385 
  1431 
  1386 		SetViewportPosition(w, WP(w, vp_d).scrollpos_x, WP(w, vp_d).scrollpos_y);
  1432 		SetViewportPosition(w, WP(w, vp_d).scrollpos_x, WP(w, vp_d).scrollpos_y);
  1387 	}
  1433 	}
  1402 	top = max(0, top - vp->virtual_top);
  1448 	top = max(0, top - vp->virtual_top);
  1403 
  1449 
  1404 	if (top >= vp->virtual_height) return;
  1450 	if (top >= vp->virtual_height) return;
  1405 
  1451 
  1406 	SetDirtyBlocks(
  1452 	SetDirtyBlocks(
  1407 		(left >> vp->zoom) + vp->left,
  1453 		UnScaleByZoom(left, vp->zoom) + vp->left,
  1408 		(top >> vp->zoom) + vp->top,
  1454 		UnScaleByZoom(top, vp->zoom) + vp->top,
  1409 		(right >> vp->zoom) + vp->left,
  1455 		UnScaleByZoom(right, vp->zoom) + vp->left,
  1410 		(bottom >> vp->zoom) + vp->top
  1456 		UnScaleByZoom(bottom, vp->zoom) + vp->top
  1411 	);
  1457 	);
  1412 }
  1458 }
  1413 
  1459 
  1414 void MarkAllViewportsDirty(int left, int top, int right, int bottom)
  1460 void MarkAllViewportsDirty(int left, int top, int right, int bottom)
  1415 {
  1461 {
  1493 
  1539 
  1494 static bool CheckClickOnTown(const ViewPort *vp, int x, int y)
  1540 static bool CheckClickOnTown(const ViewPort *vp, int x, int y)
  1495 {
  1541 {
  1496 	const Town *t;
  1542 	const Town *t;
  1497 
  1543 
  1498 	if (!(_display_opt & DO_SHOW_TOWN_NAMES)) return false;
  1544 	if (!HASBIT(_display_opt, DO_SHOW_TOWN_NAMES)) return false;
  1499 
  1545 
  1500 	switch (vp->zoom) {
  1546 	switch (vp->zoom) {
  1501 		case 0:
  1547 		case ZOOM_LVL_NORMAL:
  1502 			x = x - vp->left + vp->virtual_left;
  1548 			x = x - vp->left + vp->virtual_left;
  1503 			y = y - vp->top  + vp->virtual_top;
  1549 			y = y - vp->top  + vp->virtual_top;
  1504 			FOR_ALL_TOWNS(t) {
  1550 			FOR_ALL_TOWNS(t) {
  1505 				if (y >= t->sign.top &&
  1551 				if (y >= t->sign.top &&
  1506 						y < t->sign.top + 12 &&
  1552 						y < t->sign.top + 12 &&
  1510 					return true;
  1556 					return true;
  1511 				}
  1557 				}
  1512 			}
  1558 			}
  1513 			break;
  1559 			break;
  1514 
  1560 
  1515 		case 1:
  1561 		case ZOOM_LVL_OUT_2X:
  1516 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1562 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1517 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1563 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1518 			FOR_ALL_TOWNS(t) {
  1564 			FOR_ALL_TOWNS(t) {
  1519 				if (y >= t->sign.top &&
  1565 				if (y >= t->sign.top &&
  1520 						y < t->sign.top + 24 &&
  1566 						y < t->sign.top + 24 &&
  1524 					return true;
  1570 					return true;
  1525 				}
  1571 				}
  1526 			}
  1572 			}
  1527 			break;
  1573 			break;
  1528 
  1574 
  1529 		default:
  1575 		case ZOOM_LVL_OUT_4X:
  1530 			x = (x - vp->left + 3) * 4 + vp->virtual_left;
  1576 		case ZOOM_LVL_OUT_8X:
  1531 			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
  1577 			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
       
  1578 			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
       
  1579 
  1532 			FOR_ALL_TOWNS(t) {
  1580 			FOR_ALL_TOWNS(t) {
  1533 				if (y >= t->sign.top &&
  1581 				if (y >= t->sign.top &&
  1534 						y < t->sign.top + 24 &&
  1582 						y < t->sign.top + ScaleByZoom(12, vp->zoom) &&
  1535 						x >= t->sign.left &&
  1583 						x >= t->sign.left &&
  1536 						x < t->sign.left + t->sign.width_2 * 4) {
  1584 						x < t->sign.left + ScaleByZoom(t->sign.width_2, vp->zoom)) {
  1537 					ShowTownViewWindow(t->index);
  1585 					ShowTownViewWindow(t->index);
  1538 					return true;
  1586 					return true;
  1539 				}
  1587 				}
  1540 			}
  1588 			}
  1541 			break;
  1589 			break;
       
  1590 
       
  1591 		case ZOOM_LVL_OUT_16X:
       
  1592 			break;
       
  1593 
       
  1594 		default: NOT_REACHED();
  1542 	}
  1595 	}
  1543 
  1596 
  1544 	return false;
  1597 	return false;
  1545 }
  1598 }
  1546 
  1599 
  1547 
  1600 
  1548 static bool CheckClickOnStation(const ViewPort *vp, int x, int y)
  1601 static bool CheckClickOnStation(const ViewPort *vp, int x, int y)
  1549 {
  1602 {
  1550 	const Station *st;
  1603 	const Station *st;
  1551 
  1604 
  1552 	if (!(_display_opt & DO_SHOW_STATION_NAMES)) return false;
  1605 	if (!HASBIT(_display_opt, DO_SHOW_STATION_NAMES)) return false;
  1553 
  1606 
  1554 	switch (vp->zoom) {
  1607 	switch (vp->zoom) {
  1555 		case 0:
  1608 		case ZOOM_LVL_NORMAL:
  1556 			x = x - vp->left + vp->virtual_left;
  1609 			x = x - vp->left + vp->virtual_left;
  1557 			y = y - vp->top  + vp->virtual_top;
  1610 			y = y - vp->top  + vp->virtual_top;
  1558 			FOR_ALL_STATIONS(st) {
  1611 			FOR_ALL_STATIONS(st) {
  1559 				if (y >= st->sign.top &&
  1612 				if (y >= st->sign.top &&
  1560 						y < st->sign.top + 12 &&
  1613 						y < st->sign.top + 12 &&
  1564 					return true;
  1617 					return true;
  1565 				}
  1618 				}
  1566 			}
  1619 			}
  1567 			break;
  1620 			break;
  1568 
  1621 
  1569 		case 1:
  1622 		case ZOOM_LVL_OUT_2X:
  1570 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1623 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1571 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1624 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1572 			FOR_ALL_STATIONS(st) {
  1625 			FOR_ALL_STATIONS(st) {
  1573 				if (y >= st->sign.top &&
  1626 				if (y >= st->sign.top &&
  1574 						y < st->sign.top + 24 &&
  1627 						y < st->sign.top + 24 &&
  1578 					return true;
  1631 					return true;
  1579 				}
  1632 				}
  1580 			}
  1633 			}
  1581 			break;
  1634 			break;
  1582 
  1635 
  1583 		default:
  1636 		case ZOOM_LVL_OUT_4X:
  1584 			x = (x - vp->left + 3) * 4 + vp->virtual_left;
  1637 		case ZOOM_LVL_OUT_8X:
  1585 			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
  1638 			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
       
  1639 			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
       
  1640 
  1586 			FOR_ALL_STATIONS(st) {
  1641 			FOR_ALL_STATIONS(st) {
  1587 				if (y >= st->sign.top &&
  1642 				if (y >= st->sign.top &&
  1588 						y < st->sign.top + 24 &&
  1643 						y < st->sign.top + ScaleByZoom(12, vp->zoom) &&
  1589 						x >= st->sign.left &&
  1644 						x >= st->sign.left &&
  1590 						x < st->sign.left + st->sign.width_2 * 4) {
  1645 						x < st->sign.left + ScaleByZoom(st->sign.width_2, vp->zoom)) {
  1591 					ShowStationViewWindow(st->index);
  1646 					ShowStationViewWindow(st->index);
  1592 					return true;
  1647 					return true;
  1593 				}
  1648 				}
  1594 			}
  1649 			}
  1595 			break;
  1650 			break;
       
  1651 
       
  1652 		case ZOOM_LVL_OUT_16X:
       
  1653 			break;
       
  1654 
       
  1655 		default: NOT_REACHED();
  1596 	}
  1656 	}
  1597 
  1657 
  1598 	return false;
  1658 	return false;
  1599 }
  1659 }
  1600 
  1660 
  1601 
  1661 
  1602 static bool CheckClickOnSign(const ViewPort *vp, int x, int y)
  1662 static bool CheckClickOnSign(const ViewPort *vp, int x, int y)
  1603 {
  1663 {
  1604 	const Sign *si;
  1664 	const Sign *si;
  1605 
  1665 
  1606 	if (!(_display_opt & DO_SHOW_SIGNS) || _current_player == PLAYER_SPECTATOR) return false;
  1666 	if (!HASBIT(_display_opt, DO_SHOW_SIGNS) || _current_player == PLAYER_SPECTATOR) return false;
  1607 
  1667 
  1608 	switch (vp->zoom) {
  1668 	switch (vp->zoom) {
  1609 		case 0:
  1669 		case ZOOM_LVL_NORMAL:
  1610 			x = x - vp->left + vp->virtual_left;
  1670 			x = x - vp->left + vp->virtual_left;
  1611 			y = y - vp->top  + vp->virtual_top;
  1671 			y = y - vp->top  + vp->virtual_top;
  1612 			FOR_ALL_SIGNS(si) {
  1672 			FOR_ALL_SIGNS(si) {
  1613 				if (y >= si->sign.top &&
  1673 				if (y >= si->sign.top &&
  1614 						y <  si->sign.top + 12 &&
  1674 						y <  si->sign.top + 12 &&
  1618 					return true;
  1678 					return true;
  1619 				}
  1679 				}
  1620 			}
  1680 			}
  1621 			break;
  1681 			break;
  1622 
  1682 
  1623 		case 1:
  1683 		case ZOOM_LVL_OUT_2X:
  1624 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1684 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1625 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1685 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1626 			FOR_ALL_SIGNS(si) {
  1686 			FOR_ALL_SIGNS(si) {
  1627 				if (y >= si->sign.top &&
  1687 				if (y >= si->sign.top &&
  1628 						y <  si->sign.top + 24 &&
  1688 						y <  si->sign.top + 24 &&
  1632 					return true;
  1692 					return true;
  1633 				}
  1693 				}
  1634 			}
  1694 			}
  1635 			break;
  1695 			break;
  1636 
  1696 
  1637 		default:
  1697 		case ZOOM_LVL_OUT_4X:
  1638 			x = (x - vp->left + 3) * 4 + vp->virtual_left;
  1698 		case ZOOM_LVL_OUT_8X:
  1639 			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
  1699 			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
       
  1700 			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
       
  1701 
  1640 			FOR_ALL_SIGNS(si) {
  1702 			FOR_ALL_SIGNS(si) {
  1641 				if (y >= si->sign.top &&
  1703 				if (y >= si->sign.top &&
  1642 						y <  si->sign.top + 24 &&
  1704 						y <  si->sign.top + ScaleByZoom(12, vp->zoom) &&
  1643 						x >= si->sign.left &&
  1705 						x >= si->sign.left &&
  1644 						x <  si->sign.left + si->sign.width_2 * 4) {
  1706 						x <  si->sign.left + ScaleByZoom(si->sign.width_2, vp->zoom)) {
  1645 					ShowRenameSignWindow(si);
  1707 					ShowRenameSignWindow(si);
  1646 					return true;
  1708 					return true;
  1647 				}
  1709 				}
  1648 			}
  1710 			}
  1649 			break;
  1711 			break;
       
  1712 
       
  1713 		case ZOOM_LVL_OUT_16X:
       
  1714 			break;
       
  1715 
       
  1716 		default: NOT_REACHED();
  1650 	}
  1717 	}
  1651 
  1718 
  1652 	return false;
  1719 	return false;
  1653 }
  1720 }
  1654 
  1721 
  1655 
  1722 
  1656 static bool CheckClickOnWaypoint(const ViewPort *vp, int x, int y)
  1723 static bool CheckClickOnWaypoint(const ViewPort *vp, int x, int y)
  1657 {
  1724 {
  1658 	const Waypoint *wp;
  1725 	const Waypoint *wp;
  1659 
  1726 
  1660 	if (!(_display_opt & DO_WAYPOINTS)) return false;
  1727 	if (!HASBIT(_display_opt, DO_WAYPOINTS)) return false;
  1661 
  1728 
  1662 	switch (vp->zoom) {
  1729 	switch (vp->zoom) {
  1663 		case 0:
  1730 		case ZOOM_LVL_NORMAL:
  1664 			x = x - vp->left + vp->virtual_left;
  1731 			x = x - vp->left + vp->virtual_left;
  1665 			y = y - vp->top  + vp->virtual_top;
  1732 			y = y - vp->top  + vp->virtual_top;
  1666 			FOR_ALL_WAYPOINTS(wp) {
  1733 			FOR_ALL_WAYPOINTS(wp) {
  1667 				if (y >= wp->sign.top &&
  1734 				if (y >= wp->sign.top &&
  1668 						y < wp->sign.top + 12 &&
  1735 						y < wp->sign.top + 12 &&
  1672 					return true;
  1739 					return true;
  1673 				}
  1740 				}
  1674 			}
  1741 			}
  1675 			break;
  1742 			break;
  1676 
  1743 
  1677 		case 1:
  1744 		case ZOOM_LVL_OUT_2X:
  1678 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1745 			x = (x - vp->left + 1) * 2 + vp->virtual_left;
  1679 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1746 			y = (y - vp->top  + 1) * 2 + vp->virtual_top;
  1680 			FOR_ALL_WAYPOINTS(wp) {
  1747 			FOR_ALL_WAYPOINTS(wp) {
  1681 				if (y >= wp->sign.top &&
  1748 				if (y >= wp->sign.top &&
  1682 						y < wp->sign.top + 24 &&
  1749 						y < wp->sign.top + 24 &&
  1686 					return true;
  1753 					return true;
  1687 				}
  1754 				}
  1688 			}
  1755 			}
  1689 			break;
  1756 			break;
  1690 
  1757 
  1691 		default:
  1758 		case ZOOM_LVL_OUT_4X:
  1692 			x = (x - vp->left + 3) * 4 + vp->virtual_left;
  1759 		case ZOOM_LVL_OUT_8X:
  1693 			y = (y - vp->top  + 3) * 4 + vp->virtual_top;
  1760 			x = ScaleByZoom(x - vp->left + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_left;
       
  1761 			y = ScaleByZoom(y - vp->top  + ScaleByZoom(1, vp->zoom) - 1, vp->zoom) + vp->virtual_top;
       
  1762 
  1694 			FOR_ALL_WAYPOINTS(wp) {
  1763 			FOR_ALL_WAYPOINTS(wp) {
  1695 				if (y >= wp->sign.top &&
  1764 				if (y >= wp->sign.top &&
  1696 						y < wp->sign.top + 24 &&
  1765 						y < wp->sign.top + ScaleByZoom(12, vp->zoom) &&
  1697 						x >= wp->sign.left &&
  1766 						x >= wp->sign.left &&
  1698 						x < wp->sign.left + wp->sign.width_2 * 4) {
  1767 						x < wp->sign.left + ScaleByZoom(wp->sign.width_2, vp->zoom)) {
  1699 					ShowRenameWaypointWindow(wp);
  1768 					ShowRenameWaypointWindow(wp);
  1700 					return true;
  1769 					return true;
  1701 				}
  1770 				}
  1702 			}
  1771 			}
  1703 			break;
  1772 			break;
       
  1773 
       
  1774 		case ZOOM_LVL_OUT_16X:
       
  1775 			break;
       
  1776 
       
  1777 		default: NOT_REACHED();
  1704 	}
  1778 	}
  1705 
  1779 
  1706 	return false;
  1780 	return false;
  1707 }
  1781 }
  1708 
  1782 
  1794 	}
  1868 	}
  1795 }
  1869 }
  1796 
  1870 
  1797 
  1871 
  1798 /* scrolls the viewport in a window to a given location */
  1872 /* scrolls the viewport in a window to a given location */
  1799 bool ScrollWindowTo(int x , int y, Window *w)
  1873 bool ScrollWindowTo(int x , int y, Window *w, bool instant)
  1800 {
  1874 {
  1801 	Point pt;
  1875 	Point pt;
  1802 
  1876 
  1803 	pt = MapXYZToViewport(w->viewport, x, y, GetSlopeZ(x, y));
  1877 	pt = MapXYZToViewport(w->viewport, x, y, GetSlopeZ(x, y));
  1804 	WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
  1878 	WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
  1805 
  1879 
  1806 	if (WP(w, vp_d).scrollpos_x == pt.x && WP(w, vp_d).scrollpos_y == pt.y)
  1880 	if (WP(w, vp_d).dest_scrollpos_x == pt.x && WP(w, vp_d).dest_scrollpos_y == pt.y)
  1807 		return false;
  1881 		return false;
  1808 
  1882 
  1809 	WP(w, vp_d).scrollpos_x = pt.x;
  1883 	if (instant) {
  1810 	WP(w, vp_d).scrollpos_y = pt.y;
  1884 		WP(w, vp_d).scrollpos_x = pt.x;
       
  1885 		WP(w, vp_d).scrollpos_y = pt.y;
       
  1886 	}
       
  1887 
       
  1888 	WP(w, vp_d).dest_scrollpos_x = pt.x;
       
  1889 	WP(w, vp_d).dest_scrollpos_y = pt.y;
  1811 	return true;
  1890 	return true;
  1812 }
  1891 }
  1813 
  1892 
  1814 
  1893 
  1815 bool ScrollMainWindowTo(int x, int y)
  1894 bool ScrollMainWindowTo(int x, int y, bool instant)
  1816 {
  1895 {
  1817 	Window *w;
  1896 	Window *w;
  1818 	bool res = ScrollWindowTo(x, y, FindWindowById(WC_MAIN_WINDOW, 0));
  1897 	bool res = ScrollWindowTo(x, y, FindWindowById(WC_MAIN_WINDOW, 0), instant);
  1819 
  1898 
  1820 	/* If a user scrolls to a tile (via what way what so ever) and already is on
  1899 	/* If a user scrolls to a tile (via what way what so ever) and already is on
  1821 	 *  that tile (e.g.: pressed twice), move the smallmap to that location,
  1900 	 *  that tile (e.g.: pressed twice), move the smallmap to that location,
  1822 	 *  so you directly see where you are on the smallmap. */
  1901 	 *  so you directly see where you are on the smallmap. */
  1823 
  1902 
  1830 
  1909 
  1831 	return res;
  1910 	return res;
  1832 }
  1911 }
  1833 
  1912 
  1834 
  1913 
  1835 bool ScrollMainWindowToTile(TileIndex tile)
  1914 bool ScrollMainWindowToTile(TileIndex tile, bool instant)
  1836 {
  1915 {
  1837 	return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2);
  1916 	return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, instant);
  1838 }
  1917 }
  1839 
  1918 
  1840 void SetRedErrorSquare(TileIndex tile)
  1919 void SetRedErrorSquare(TileIndex tile)
  1841 {
  1920 {
  1842 	TileIndex old;
  1921 	TileIndex old;
  1864 	_thd.offs.y = oy * TILE_SIZE;
  1943 	_thd.offs.y = oy * TILE_SIZE;
  1865 	_thd.new_outersize.x = sx * TILE_SIZE;
  1944 	_thd.new_outersize.x = sx * TILE_SIZE;
  1866 	_thd.new_outersize.y = sy * TILE_SIZE;
  1945 	_thd.new_outersize.y = sy * TILE_SIZE;
  1867 }
  1946 }
  1868 
  1947 
  1869 /* returns the best autorail highlight type from map coordinates */
  1948 /** returns the best autorail highlight type from map coordinates */
  1870 static byte GetAutorailHT(int x, int y)
  1949 static byte GetAutorailHT(int x, int y)
  1871 {
  1950 {
  1872 	return HT_RAIL | _AutorailPiece[x & 0xF][y & 0xF];
  1951 	return HT_RAIL | _AutorailPiece[x & 0xF][y & 0xF];
  1873 }
  1952 }
  1874 
  1953 
  1875 // called regular to update tile highlighting in all cases
  1954 /** called regular to update tile highlighting in all cases */
  1876 void UpdateTileSelection()
  1955 void UpdateTileSelection()
  1877 {
  1956 {
  1878 	int x1;
  1957 	int x1;
  1879 	int y1;
  1958 	int y1;
  1880 
  1959 
  1917 			_thd.new_pos.x = x1 & ~0xF;
  1996 			_thd.new_pos.x = x1 & ~0xF;
  1918 			_thd.new_pos.y = y1 & ~0xF;
  1997 			_thd.new_pos.y = y1 & ~0xF;
  1919 		}
  1998 		}
  1920 	}
  1999 	}
  1921 
  2000 
  1922 	// redraw selection
  2001 	/* redraw selection */
  1923 	if (_thd.drawstyle != _thd.new_drawstyle ||
  2002 	if (_thd.drawstyle != _thd.new_drawstyle ||
  1924 			_thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
  2003 			_thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
  1925 			_thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
  2004 			_thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
  1926 	    _thd.outersize.x != _thd.new_outersize.x ||
  2005 	    _thd.outersize.x != _thd.new_outersize.x ||
  1927 	    _thd.outersize.y != _thd.new_outersize.y) {
  2006 	    _thd.outersize.y != _thd.new_outersize.y) {
  1928 		// clear the old selection?
  2007 		/* clear the old selection? */
  1929 		if (_thd.drawstyle) SetSelectionTilesDirty();
  2008 		if (_thd.drawstyle) SetSelectionTilesDirty();
  1930 
  2009 
  1931 		_thd.drawstyle = _thd.new_drawstyle;
  2010 		_thd.drawstyle = _thd.new_drawstyle;
  1932 		_thd.pos = _thd.new_pos;
  2011 		_thd.pos = _thd.new_pos;
  1933 		_thd.size = _thd.new_size;
  2012 		_thd.size = _thd.new_size;
  1934 		_thd.outersize = _thd.new_outersize;
  2013 		_thd.outersize = _thd.new_outersize;
  1935 		_thd.dirty = 0xff;
  2014 		_thd.dirty = 0xff;
  1936 
  2015 
  1937 		// draw the new selection?
  2016 		/* draw the new selection? */
  1938 		if (_thd.new_drawstyle) SetSelectionTilesDirty();
  2017 		if (_thd.new_drawstyle) SetSelectionTilesDirty();
  1939 	}
  2018 	}
  1940 }
  2019 }
  1941 
  2020 
  1942 // highlighting tiles while only going over them with the mouse
  2021 /** highlighting tiles while only going over them with the mouse */
  1943 void VpStartPlaceSizing(TileIndex tile, int user)
  2022 void VpStartPlaceSizing(TileIndex tile, byte method, byte process)
  1944 {
  2023 {
  1945 	_thd.userdata = user;
  2024 	_thd.select_method = method;
       
  2025 	_thd.select_proc   = process;
  1946 	_thd.selend.x = TileX(tile) * TILE_SIZE;
  2026 	_thd.selend.x = TileX(tile) * TILE_SIZE;
  1947 	_thd.selstart.x = TileX(tile) * TILE_SIZE;
  2027 	_thd.selstart.x = TileX(tile) * TILE_SIZE;
  1948 	_thd.selend.y = TileY(tile) * TILE_SIZE;
  2028 	_thd.selend.y = TileY(tile) * TILE_SIZE;
  1949 	_thd.selstart.y = TileY(tile) * TILE_SIZE;
  2029 	_thd.selstart.y = TileY(tile) * TILE_SIZE;
  1950 	if (_thd.place_mode == VHM_RECT) {
  2030 	if (_thd.place_mode == VHM_RECT) {
  1987 {
  2067 {
  1988 	_thd.selend.x = -1;
  2068 	_thd.selend.x = -1;
  1989 	_special_mouse_mode = WSM_PRESIZE;
  2069 	_special_mouse_mode = WSM_PRESIZE;
  1990 }
  2070 }
  1991 
  2071 
  1992 /* returns information about the 2x1 piece to be build.
  2072 /** returns information about the 2x1 piece to be build.
  1993  * The lower bits (0-3) are the track type. */
  2073  * The lower bits (0-3) are the track type. */
  1994 static byte Check2x1AutoRail(int mode)
  2074 static byte Check2x1AutoRail(int mode)
  1995 {
  2075 {
  1996 	int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
  2076 	int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
  1997 	int sxpy = (_thd.selend.x & 0xF) + (_thd.selend.y & 0xF);
  2077 	int sxpy = (_thd.selend.x & 0xF) + (_thd.selend.y & 0xF);
  2029  * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E
  2109  * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E
  2030  * For example dragging a rectangle area from south to north should be swapped to
  2110  * For example dragging a rectangle area from south to north should be swapped to
  2031  * north-south (DIR_S) to obtain the same results with less code. This is what
  2111  * north-south (DIR_S) to obtain the same results with less code. This is what
  2032  * the return value signifies.
  2112  * the return value signifies.
  2033  * @param style HighLightStyle dragging style
  2113  * @param style HighLightStyle dragging style
  2034  * @param start_tile, end_tile start and end tile of drag
  2114  * @param start_tile start tile of drag
  2035  * @param boolean value which when true means start/end should be swapped */
  2115  * @param end_tile end tile of drag
       
  2116  * @return boolean value which when true means start/end should be swapped */
  2036 static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
  2117 static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
  2037 {
  2118 {
  2038 	uint start_x = TileX(start_tile);
  2119 	uint start_x = TileX(start_tile);
  2039 	uint start_y = TileY(start_tile);
  2120 	uint start_y = TileY(start_tile);
  2040 	uint end_x = TileX(end_tile);
  2121 	uint end_x = TileX(end_tile);
  2055 /** Calculates height difference between one tile and another
  2136 /** Calculates height difference between one tile and another
  2056 * Multiplies the result to suit the standard given by minimap - 50 meters high
  2137 * Multiplies the result to suit the standard given by minimap - 50 meters high
  2057 * To correctly get the height difference we need the direction we are dragging
  2138 * To correctly get the height difference we need the direction we are dragging
  2058 * in, as well as with what kind of tool we are dragging. For example a horizontal
  2139 * in, as well as with what kind of tool we are dragging. For example a horizontal
  2059 * autorail tool that starts in bottom and ends at the top of a tile will need the
  2140 * autorail tool that starts in bottom and ends at the top of a tile will need the
  2060 * maximum of SW,S and SE,N corners respectively. This is handled by the lookup table below
  2141 * maximum of SW, S and SE, N corners respectively. This is handled by the lookup table below
  2061 * See _tileoffs_by_dir in map.c for the direction enums if you can't figure out
  2142 * See _tileoffs_by_dir in map.c for the direction enums if you can't figure out
  2062 * the values yourself.
  2143 * the values yourself.
  2063 * @param style HightlightStyle of drag. This includes direction and style (autorail, rect, etc.)
  2144 * @param style HightlightStyle of drag. This includes direction and style (autorail, rect, etc.)
  2064 * @param distance amount of tiles dragged, important for horizontal/vertical drags
  2145 * @param distance amount of tiles dragged, important for horizontal/vertical drags
  2065 *        ignored for others
  2146 *        ignored for others
  2138 	return (int)(h1 - h0) * 50;
  2219 	return (int)(h1 - h0) * 50;
  2139 }
  2220 }
  2140 
  2221 
  2141 static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
  2222 static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
  2142 
  2223 
  2143 // while dragging
  2224 /** while dragging */
  2144 static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method)
  2225 static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method)
  2145 {
  2226 {
  2146 	HighLightStyle b;
  2227 	HighLightStyle b;
  2147 	uint w, h;
  2228 	uint w, h;
  2148 
  2229 
  2389 
  2470 
  2390 	_thd.selend.x = x;
  2471 	_thd.selend.x = x;
  2391 	_thd.selend.y = y;
  2472 	_thd.selend.y = y;
  2392 }
  2473 }
  2393 
  2474 
  2394 // while dragging
  2475 /** while dragging */
  2395 bool VpHandlePlaceSizingDrag()
  2476 bool VpHandlePlaceSizingDrag()
  2396 {
  2477 {
  2397 	Window *w;
  2478 	Window *w;
  2398 	WindowEvent e;
  2479 	WindowEvent e;
  2399 
  2480 
  2400 	if (_special_mouse_mode != WSM_SIZING) return true;
  2481 	if (_special_mouse_mode != WSM_SIZING) return true;
  2401 
  2482 
  2402 	e.we.place.userdata = _thd.userdata;
  2483 	e.we.place.select_method = _thd.select_method;
  2403 
  2484 	e.we.place.select_proc   = _thd.select_proc;
  2404 	// stop drag mode if the window has been closed
  2485 
  2405 	w = FindWindowById(_thd.window_class,_thd.window_number);
  2486 	/* stop drag mode if the window has been closed */
       
  2487 	w = FindWindowById(_thd.window_class, _thd.window_number);
  2406 	if (w == NULL) {
  2488 	if (w == NULL) {
  2407 		ResetObjectToPlace();
  2489 		ResetObjectToPlace();
  2408 		return false;
  2490 		return false;
  2409 	}
  2491 	}
  2410 
  2492 
  2411 	// while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() )
  2493 	/* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
  2412 	if (_left_button_down) {
  2494 	if (_left_button_down) {
  2413 		e.event = WE_PLACE_DRAG;
  2495 		e.event = WE_PLACE_DRAG;
  2414 		e.we.place.pt = GetTileBelowCursor();
  2496 		e.we.place.pt = GetTileBelowCursor();
  2415 		w->wndproc(w, &e);
  2497 		w->wndproc(w, &e);
  2416 		return false;
  2498 		return false;
  2417 	}
  2499 	}
  2418 
  2500 
  2419 	// mouse button released..
  2501 	/* mouse button released..
  2420 	// keep the selected tool, but reset it to the original mode.
  2502 	 * keep the selected tool, but reset it to the original mode. */
  2421 	_special_mouse_mode = WSM_NONE;
  2503 	_special_mouse_mode = WSM_NONE;
  2422 	if (_thd.next_drawstyle == HT_RECT) {
  2504 	if (_thd.next_drawstyle == HT_RECT) {
  2423 		_thd.place_mode = VHM_RECT;
  2505 		_thd.place_mode = VHM_RECT;
  2424 	} else if ((e.we.place.userdata & 0xF) == VPM_SIGNALDIRS) { // some might call this a hack... -- Dominik
  2506 	} else if (e.we.place.select_method == VPM_SIGNALDIRS) { // some might call this a hack... -- Dominik
  2425 		_thd.place_mode = VHM_RECT;
  2507 		_thd.place_mode = VHM_RECT;
  2426 	} else if (_thd.next_drawstyle & HT_LINE) {
  2508 	} else if (_thd.next_drawstyle & HT_LINE) {
  2427 		_thd.place_mode = VHM_RAIL;
  2509 		_thd.place_mode = VHM_RAIL;
  2428 	} else if (_thd.next_drawstyle & HT_RAIL) {
  2510 	} else if (_thd.next_drawstyle & HT_RAIL) {
  2429 		_thd.place_mode = VHM_RAIL;
  2511 		_thd.place_mode = VHM_RAIL;
  2430 	} else {
  2512 	} else {
  2431 		_thd.place_mode = VHM_POINT;
  2513 		_thd.place_mode = VHM_POINT;
  2432 	}
  2514 	}
  2433 	SetTileSelectSize(1, 1);
  2515 	SetTileSelectSize(1, 1);
  2434 
  2516 
  2435 	// and call the mouseup event.
  2517 	/* and call the mouseup event. */
  2436 	e.event = WE_PLACE_MOUSEUP;
  2518 	e.event = WE_PLACE_MOUSEUP;
  2437 	e.we.place.pt = _thd.selend;
  2519 	e.we.place.pt = _thd.selend;
  2438 	e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y);
  2520 	e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y);
  2439 	e.we.place.starttile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
  2521 	e.we.place.starttile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
  2440 	w->wndproc(w, &e);
  2522 	w->wndproc(w, &e);
  2451 
  2533 
  2452 void SetObjectToPlace(CursorID icon, SpriteID pal, byte mode, WindowClass window_class, WindowNumber window_num)
  2534 void SetObjectToPlace(CursorID icon, SpriteID pal, byte mode, WindowClass window_class, WindowNumber window_num)
  2453 {
  2535 {
  2454 	Window *w;
  2536 	Window *w;
  2455 
  2537 
  2456 	// undo clicking on button
  2538 	/* undo clicking on button */
  2457 	if (_thd.place_mode != 0) {
  2539 	if (_thd.place_mode != 0) {
  2458 		_thd.place_mode = 0;
  2540 		_thd.place_mode = 0;
  2459 		w = FindWindowById(_thd.window_class, _thd.window_number);
  2541 		w = FindWindowById(_thd.window_class, _thd.window_number);
  2460 		if (w != NULL) CallWindowEventNP(w, WE_ABORT_PLACE_OBJ);
  2542 		if (w != NULL) CallWindowEventNP(w, WE_ABORT_PLACE_OBJ);
  2461 	}
  2543 	}