OpenTTD
viewport.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
63 #include "stdafx.h"
64 #include "landscape.h"
65 #include "viewport_func.h"
66 #include "station_base.h"
67 #include "waypoint_base.h"
68 #include "town.h"
69 #include "signs_base.h"
70 #include "signs_func.h"
71 #include "vehicle_base.h"
72 #include "vehicle_gui.h"
73 #include "blitter/factory.hpp"
74 #include "strings_func.h"
75 #include "zoom_func.h"
76 #include "vehicle_func.h"
77 #include "company_func.h"
78 #include "waypoint_func.h"
79 #include "window_func.h"
80 #include "tilehighlight_func.h"
81 #include "window_gui.h"
83 #include "viewport_kdtree.h"
84 #include "town_kdtree.h"
85 #include "viewport_sprite_sorter.h"
86 #include "bridge_map.h"
87 #include "company_base.h"
88 #include "command_func.h"
89 #include "network/network_func.h"
90 #include "framerate_type.h"
91 
92 #include <map>
93 
94 #include "table/strings.h"
95 #include "table/string_colours.h"
96 
97 #include "safeguards.h"
98 
99 Point _tile_fract_coords;
100 
101 
102 ViewportSignKdtree _viewport_sign_kdtree(&Kdtree_ViewportSignXYFunc);
103 static int _viewport_sign_maxwidth = 0;
104 
105 
106 static const int MAX_TILE_EXTENT_LEFT = ZOOM_LVL_BASE * TILE_PIXELS;
107 static const int MAX_TILE_EXTENT_RIGHT = ZOOM_LVL_BASE * TILE_PIXELS;
108 static const int MAX_TILE_EXTENT_TOP = ZOOM_LVL_BASE * MAX_BUILDING_PIXELS;
109 static const int MAX_TILE_EXTENT_BOTTOM = ZOOM_LVL_BASE * (TILE_PIXELS + 2 * TILE_HEIGHT);
110 
112  StringID string;
113  Colours colour;
114  int32 x;
115  int32 y;
116  uint64 params[2];
117  uint16 width;
118 };
119 
121  SpriteID image;
122  PaletteID pal;
123  const SubSprite *sub;
124  int32 x;
125  int32 y;
126 };
127 
129  SpriteID image;
130  PaletteID pal;
131  const SubSprite *sub;
132  int32 x;
133  int32 y;
134  int next;
135 };
136 
142  FOUNDATION_PART_END
143 };
144 
153 };
154 
155 typedef std::vector<TileSpriteToDraw> TileSpriteToDrawVector;
156 typedef std::vector<StringSpriteToDraw> StringSpriteToDrawVector;
157 typedef std::vector<ParentSpriteToDraw> ParentSpriteToDrawVector;
158 typedef std::vector<ChildScreenSpriteToDraw> ChildScreenSpriteToDrawVector;
159 
162  DrawPixelInfo dpi;
163 
164  StringSpriteToDrawVector string_sprites_to_draw;
165  TileSpriteToDrawVector tile_sprites_to_draw;
166  ParentSpriteToDrawVector parent_sprites_to_draw;
167  ParentSpriteToSortVector parent_sprites_to_sort;
168  ChildScreenSpriteToDrawVector child_screen_sprites_to_draw;
169 
170  int *last_child;
171 
173 
174  int foundation[FOUNDATION_PART_END];
176  int *last_foundation_child[FOUNDATION_PART_END];
177  Point foundation_offset[FOUNDATION_PART_END];
178 };
179 
180 static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom);
181 
182 static ViewportDrawer _vd;
183 
184 TileHighlightData _thd;
185 static TileInfo *_cur_ti;
186 bool _draw_bounding_boxes = false;
187 bool _draw_dirty_blocks = false;
188 uint _dirty_block_colour = 0;
189 static VpSpriteSorter _vp_sprite_sorter = nullptr;
190 
191 static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z)
192 {
193  Point p = RemapCoords(x, y, z);
194  p.x -= vp->virtual_width / 2;
195  p.y -= vp->virtual_height / 2;
196  return p;
197 }
198 
199 void DeleteWindowViewport(Window *w)
200 {
201  if (w->viewport == nullptr) return;
202 
203  delete w->viewport->overlay;
204  free(w->viewport);
205  w->viewport = nullptr;
206 }
207 
220 void InitializeWindowViewport(Window *w, int x, int y,
221  int width, int height, uint32 follow_flags, ZoomLevel zoom)
222 {
223  assert(w->viewport == nullptr);
224 
225  ViewportData *vp = CallocT<ViewportData>(1);
226 
227  vp->left = x + w->left;
228  vp->top = y + w->top;
229  vp->width = width;
230  vp->height = height;
231 
233 
234  vp->virtual_width = ScaleByZoom(width, zoom);
235  vp->virtual_height = ScaleByZoom(height, zoom);
236 
237  Point pt;
238 
239  if (follow_flags & 0x80000000) {
240  const Vehicle *veh;
241 
242  vp->follow_vehicle = (VehicleID)(follow_flags & 0xFFFFF);
243  veh = Vehicle::Get(vp->follow_vehicle);
244  pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
245  } else {
246  uint x = TileX(follow_flags) * TILE_SIZE;
247  uint y = TileY(follow_flags) * TILE_SIZE;
248 
250  pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y));
251  }
252 
253  vp->scrollpos_x = pt.x;
254  vp->scrollpos_y = pt.y;
255  vp->dest_scrollpos_x = pt.x;
256  vp->dest_scrollpos_y = pt.y;
257 
258  vp->overlay = nullptr;
259 
260  w->viewport = vp;
261  vp->virtual_left = 0; // pt.x;
262  vp->virtual_top = 0; // pt.y;
263 }
264 
265 static Point _vp_move_offs;
266 
267 static void DoSetViewportPosition(const Window *w, int left, int top, int width, int height)
268 {
270  if (left + width > w->left &&
271  w->left + w->width > left &&
272  top + height > w->top &&
273  w->top + w->height > top) {
274 
275  if (left < w->left) {
276  DoSetViewportPosition(w, left, top, w->left - left, height);
277  DoSetViewportPosition(w, left + (w->left - left), top, width - (w->left - left), height);
278  return;
279  }
280 
281  if (left + width > w->left + w->width) {
282  DoSetViewportPosition(w, left, top, (w->left + w->width - left), height);
283  DoSetViewportPosition(w, left + (w->left + w->width - left), top, width - (w->left + w->width - left), height);
284  return;
285  }
286 
287  if (top < w->top) {
288  DoSetViewportPosition(w, left, top, width, (w->top - top));
289  DoSetViewportPosition(w, left, top + (w->top - top), width, height - (w->top - top));
290  return;
291  }
292 
293  if (top + height > w->top + w->height) {
294  DoSetViewportPosition(w, left, top, width, (w->top + w->height - top));
295  DoSetViewportPosition(w, left, top + (w->top + w->height - top), width, height - (w->top + w->height - top));
296  return;
297  }
298 
299  return;
300  }
301  }
302 
303  {
304  int xo = _vp_move_offs.x;
305  int yo = _vp_move_offs.y;
306 
307  if (abs(xo) >= width || abs(yo) >= height) {
308  /* fully_outside */
309  RedrawScreenRect(left, top, left + width, top + height);
310  return;
311  }
312 
313  GfxScroll(left, top, width, height, xo, yo);
314 
315  if (xo > 0) {
316  RedrawScreenRect(left, top, xo + left, top + height);
317  left += xo;
318  width -= xo;
319  } else if (xo < 0) {
320  RedrawScreenRect(left + width + xo, top, left + width, top + height);
321  width += xo;
322  }
323 
324  if (yo > 0) {
325  RedrawScreenRect(left, top, width + left, top + yo);
326  } else if (yo < 0) {
327  RedrawScreenRect(left, top + height + yo, width + left, top + height);
328  }
329  }
330 }
331 
332 static void SetViewportPosition(Window *w, int x, int y)
333 {
334  ViewPort *vp = w->viewport;
335  int old_left = vp->virtual_left;
336  int old_top = vp->virtual_top;
337  int i;
338  int left, top, width, height;
339 
340  vp->virtual_left = x;
341  vp->virtual_top = y;
342 
343  /* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower)
344  * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL)
345  */
346  old_left = UnScaleByZoomLower(old_left, vp->zoom);
347  old_top = UnScaleByZoomLower(old_top, vp->zoom);
348  x = UnScaleByZoomLower(x, vp->zoom);
349  y = UnScaleByZoomLower(y, vp->zoom);
350 
351  old_left -= x;
352  old_top -= y;
353 
354  if (old_top == 0 && old_left == 0) return;
355 
356  _vp_move_offs.x = old_left;
357  _vp_move_offs.y = old_top;
358 
359  left = vp->left;
360  top = vp->top;
361  width = vp->width;
362  height = vp->height;
363 
364  if (left < 0) {
365  width += left;
366  left = 0;
367  }
368 
369  i = left + width - _screen.width;
370  if (i >= 0) width -= i;
371 
372  if (width > 0) {
373  if (top < 0) {
374  height += top;
375  top = 0;
376  }
377 
378  i = top + height - _screen.height;
379  if (i >= 0) height -= i;
380 
381  if (height > 0) DoSetViewportPosition(w->z_front, left, top, width, height);
382  }
383 }
384 
393 ViewPort *IsPtInWindowViewport(const Window *w, int x, int y)
394 {
395  ViewPort *vp = w->viewport;
396 
397  if (vp != nullptr &&
398  IsInsideMM(x, vp->left, vp->left + vp->width) &&
399  IsInsideMM(y, vp->top, vp->top + vp->height))
400  return vp;
401 
402  return nullptr;
403 }
404 
417 Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y, bool clamp_to_map)
418 {
419  if (!IsInsideBS(x, vp->left, vp->width) || !IsInsideBS(y, vp->top, vp->height)) {
420  Point pt = { -1, -1 };
421  return pt;
422  }
423 
424  return InverseRemapCoords2(
425  ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left,
426  ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top, clamp_to_map);
427 }
428 
429 /* When used for zooming, check area below current coordinates (x,y)
430  * and return the tile of the zoomed out/in position (zoom_x, zoom_y)
431  * when you just want the tile, make x = zoom_x and y = zoom_y */
432 static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y)
433 {
434  Window *w;
435  ViewPort *vp;
436  Point pt;
437 
438  if ( (w = FindWindowFromPt(x, y)) != nullptr &&
439  (vp = IsPtInWindowViewport(w, x, y)) != nullptr)
440  return TranslateXYToTileCoord(vp, zoom_x, zoom_y);
441 
442  pt.y = pt.x = -1;
443  return pt;
444 }
445 
446 Point GetTileBelowCursor()
447 {
448  return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
449 }
450 
451 
452 Point GetTileZoomCenterWindow(bool in, Window * w)
453 {
454  int x, y;
455  ViewPort *vp = w->viewport;
456 
457  if (in) {
458  x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2);
459  y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2);
460  } else {
461  x = vp->width - (_cursor.pos.x - vp->left);
462  y = vp->height - (_cursor.pos.y - vp->top);
463  }
464  /* Get the tile below the cursor and center on the zoomed-out center */
465  return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
466 }
467 
476 void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
477 {
478  w->SetWidgetDisabledState(widget_zoom_in, vp->zoom <= _settings_client.gui.zoom_min);
479  w->SetWidgetDirty(widget_zoom_in);
480 
481  w->SetWidgetDisabledState(widget_zoom_out, vp->zoom >= _settings_client.gui.zoom_max);
482  w->SetWidgetDirty(widget_zoom_out);
483 }
484 
497 static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0)
498 {
499  assert((image & SPRITE_MASK) < MAX_SPRITES);
500 
501  /*C++17: TileSpriteToDraw &ts = */ _vd.tile_sprites_to_draw.emplace_back();
502  TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.back();
503  ts.image = image;
504  ts.pal = pal;
505  ts.sub = sub;
506  Point pt = RemapCoords(x, y, z);
507  ts.x = pt.x + extra_offs_x;
508  ts.y = pt.y + extra_offs_y;
509 }
510 
523 static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
524 {
525  assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END));
526  assert(_vd.foundation[foundation_part] != -1);
527  Point offs = _vd.foundation_offset[foundation_part];
528 
529  /* Change the active ChildSprite list to the one of the foundation */
530  int *old_child = _vd.last_child;
531  _vd.last_child = _vd.last_foundation_child[foundation_part];
532 
533  AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub, false);
534 
535  /* Switch back to last ChildSprite list */
536  _vd.last_child = old_child;
537 }
538 
552 void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
553 {
554  /* Switch to first foundation part, if no foundation was drawn */
556 
557  if (_vd.foundation[_vd.foundation_part] != -1) {
558  Point pt = RemapCoords(x, y, z);
559  AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, pt.x + extra_offs_x * ZOOM_LVL_BASE, pt.y + extra_offs_y * ZOOM_LVL_BASE);
560  } else {
561  AddTileSpriteToDraw(image, pal, _cur_ti->x + x, _cur_ti->y + y, _cur_ti->z + z, sub, extra_offs_x * ZOOM_LVL_BASE, extra_offs_y * ZOOM_LVL_BASE);
562  }
563 }
564 
575 void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
576 {
577  DrawGroundSpriteAt(image, pal, 0, 0, 0, sub, extra_offs_x, extra_offs_y);
578 }
579 
587 void OffsetGroundSprite(int x, int y)
588 {
589  /* Switch to next foundation part */
590  switch (_vd.foundation_part) {
593  break;
596  break;
597  default: NOT_REACHED();
598  }
599 
600  /* _vd.last_child == nullptr if foundation sprite was clipped by the viewport bounds */
601  if (_vd.last_child != nullptr) _vd.foundation[_vd.foundation_part] = (uint)_vd.parent_sprites_to_draw.size() - 1;
602 
603  _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_LVL_BASE;
604  _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_LVL_BASE;
605  _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child;
606 }
607 
619 static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub)
620 {
621  Point pt = RemapCoords(x, y, z);
622  const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL);
623 
624  if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width ||
625  pt.x + spr->x_offs + spr->width <= _vd.dpi.left ||
626  pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height ||
627  pt.y + spr->y_offs + spr->height <= _vd.dpi.top)
628  return;
629 
630  const ParentSpriteToDraw &pstd = _vd.parent_sprites_to_draw.back();
631  AddChildSpriteScreen(image, pal, pt.x - pstd.left, pt.y - pstd.top, false, sub, false);
632 }
633 
659 void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
660 {
661  int32 left, right, top, bottom;
662 
663  assert((image & SPRITE_MASK) < MAX_SPRITES);
664 
665  /* make the sprites transparent with the right palette */
666  if (transparent) {
669  }
670 
672  AddCombinedSprite(image, pal, x, y, z, sub);
673  return;
674  }
675 
676  _vd.last_child = nullptr;
677 
678  Point pt = RemapCoords(x, y, z);
679  int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
680 
681  /* Compute screen extents of sprite */
682  if (image == SPR_EMPTY_BOUNDING_BOX) {
683  left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
684  right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1;
685  top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
686  bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1;
687  } else {
688  const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL);
689  left = tmp_left = (pt.x += spr->x_offs);
690  right = (pt.x + spr->width );
691  top = tmp_top = (pt.y += spr->y_offs);
692  bottom = (pt.y + spr->height);
693  }
694 
695  if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
696  /* Compute maximal extents of sprite and its bounding box */
697  left = min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
698  right = max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
699  top = min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
700  bottom = max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
701  }
702 
703  /* Do not add the sprite to the viewport, if it is outside */
704  if (left >= _vd.dpi.left + _vd.dpi.width ||
705  right <= _vd.dpi.left ||
706  top >= _vd.dpi.top + _vd.dpi.height ||
707  bottom <= _vd.dpi.top) {
708  return;
709  }
710 
711  /*C++17: ParentSpriteToDraw &ps = */ _vd.parent_sprites_to_draw.emplace_back();
712  ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.back();
713  ps.x = tmp_x;
714  ps.y = tmp_y;
715 
716  ps.left = tmp_left;
717  ps.top = tmp_top;
718 
719  ps.image = image;
720  ps.pal = pal;
721  ps.sub = sub;
722  ps.xmin = x + bb_offset_x;
723  ps.xmax = x + max(bb_offset_x, w) - 1;
724 
725  ps.ymin = y + bb_offset_y;
726  ps.ymax = y + max(bb_offset_y, h) - 1;
727 
728  ps.zmin = z + bb_offset_z;
729  ps.zmax = z + max(bb_offset_z, dz) - 1;
730 
731  ps.comparison_done = false;
732  ps.first_child = -1;
733 
734  _vd.last_child = &ps.first_child;
735 
737 }
738 
758 {
759  assert(_vd.combine_sprites == SPRITE_COMBINE_NONE);
761 }
762 
768 {
769  assert(_vd.combine_sprites != SPRITE_COMBINE_NONE);
771 }
772 
782 static bool IsInRangeInclusive(int begin, int end, int check)
783 {
784  if (begin > end) Swap(begin, end);
785  return begin <= check && check <= end;
786 }
787 
794 bool IsInsideRotatedRectangle(int x, int y)
795 {
796  int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle.
797  int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative!
798  int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny.
799  int b = ((x - _thd.pos.x) - (y - _thd.pos.y));
800 
801  /* Check if a and b are between 0 and dist_a or dist_b respectively. */
802  return IsInRangeInclusive(dist_a, 0, a) && IsInRangeInclusive(dist_b, 0, b);
803 }
804 
815 void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale)
816 {
817  assert((image & SPRITE_MASK) < MAX_SPRITES);
818 
819  /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */
820  if (_vd.last_child == nullptr) return;
821 
822  /* make the sprites transparent with the right palette */
823  if (transparent) {
826  }
827 
828  *_vd.last_child = (uint)_vd.child_screen_sprites_to_draw.size();
829 
830  /*C++17: ChildScreenSpriteToDraw &cs = */ _vd.child_screen_sprites_to_draw.emplace_back();
831  ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.back();
832  cs.image = image;
833  cs.pal = pal;
834  cs.sub = sub;
835  cs.x = scale ? x * ZOOM_LVL_BASE : x;
836  cs.y = scale ? y * ZOOM_LVL_BASE : y;
837  cs.next = -1;
838 
839  /* Append the sprite to the active ChildSprite list.
840  * If the active ParentSprite is a foundation, update last_foundation_child as well.
841  * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */
842  if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = &cs.next;
843  if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = &cs.next;
844  _vd.last_child = &cs.next;
845 }
846 
847 static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width)
848 {
849  assert(width != 0);
850  /*C++17: StringSpriteToDraw &ss = */ _vd.string_sprites_to_draw.emplace_back();
851  StringSpriteToDraw &ss = _vd.string_sprites_to_draw.back();
852  ss.string = string;
853  ss.x = x;
854  ss.y = y;
855  ss.params[0] = params_1;
856  ss.params[1] = params_2;
857  ss.width = width;
858  ss.colour = colour;
859 }
860 
861 
873 static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part)
874 {
875  /* FIXME: This is not totally valid for some autorail highlights that extend over the edges of the tile. */
876  if (_vd.foundation[foundation_part] == -1) {
877  /* draw on real ground */
878  AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset);
879  } else {
880  /* draw on top of foundation */
881  AddChildSpriteToFoundation(image, pal, nullptr, foundation_part, 0, -z_offset * ZOOM_LVL_BASE);
882  }
883 }
884 
891 static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal)
892 {
893  if (!IsValidTile(ti->tile)) return;
894 
895  SpriteID sel;
896  if (IsHalftileSlope(ti->tileh)) {
897  Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
898  SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner;
900 
901  Corner opposite_corner = OppositeCorner(halftile_corner);
902  if (IsSteepSlope(ti->tileh)) {
903  sel = SPR_HALFTILE_SELECTION_DOWN;
904  } else {
905  sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT);
906  }
907  sel += opposite_corner;
908  } else {
909  sel = SPR_SELECT_TILE + SlopeToSpriteOffset(ti->tileh);
910  }
912 }
913 
914 static bool IsPartOfAutoLine(int px, int py)
915 {
916  px -= _thd.selstart.x;
917  py -= _thd.selstart.y;
918 
919  if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false;
920 
921  switch (_thd.drawstyle & HT_DIR_MASK) {
922  case HT_DIR_X: return py == 0; // x direction
923  case HT_DIR_Y: return px == 0; // y direction
924  case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
925  case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
926  case HT_DIR_VL: return px == py || px == py + 16; // vertical left
927  case HT_DIR_VR: return px == py || px == py - 16; // vertical right
928  default:
929  NOT_REACHED();
930  }
931 }
932 
933 /* [direction][side] */
934 static const HighLightStyle _autorail_type[6][2] = {
935  { HT_DIR_X, HT_DIR_X },
936  { HT_DIR_Y, HT_DIR_Y },
937  { HT_DIR_HU, HT_DIR_HL },
938  { HT_DIR_HL, HT_DIR_HU },
939  { HT_DIR_VL, HT_DIR_VR },
940  { HT_DIR_VR, HT_DIR_VL }
941 };
942 
943 #include "table/autorail.h"
944 
951 static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
952 {
953  SpriteID image;
954  PaletteID pal;
955  int offset;
956 
957  FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
958  Slope autorail_tileh = RemoveHalftileSlope(ti->tileh);
959  if (IsHalftileSlope(ti->tileh)) {
960  static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
961  Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
962  if (autorail_type != _lower_rail[halftile_corner]) {
963  foundation_part = FOUNDATION_PART_HALFTILE;
964  /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */
965  autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
966  }
967  }
968 
969  offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
970  if (offset >= 0) {
971  image = SPR_AUTORAIL_BASE + offset;
972  pal = PAL_NONE;
973  } else {
974  image = SPR_AUTORAIL_BASE - offset;
975  pal = PALETTE_SEL_TILE_RED;
976  }
977 
978  DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
979 }
980 
981 enum TileHighlightType {
982  THT_NONE,
983  THT_WHITE,
984  THT_BLUE,
985  THT_RED,
986 };
987 
990 
996 static TileHighlightType GetTileHighlightType(TileIndex t)
997 {
998  if (_viewport_highlight_station != nullptr) {
999  if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_WHITE;
1000  if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE;
1001  }
1002 
1003  if (_viewport_highlight_town != nullptr) {
1004  if (IsTileType(t, MP_HOUSE)) {
1005  if (GetTownIndex(t) == _viewport_highlight_town->index) {
1006  TileHighlightType type = THT_RED;
1007  for (const Station *st : _viewport_highlight_town->stations_near) {
1008  if (st->owner != _current_company) continue;
1009  if (st->TileIsInCatchment(t)) return THT_BLUE;
1010  }
1011  return type;
1012  }
1013  } else if (IsTileType(t, MP_STATION)) {
1014  for (const Station *st : _viewport_highlight_town->stations_near) {
1015  if (st->owner != _current_company) continue;
1016  if (GetStationIndex(t) == st->index) return THT_WHITE;
1017  }
1018  }
1019  }
1020 
1021  return THT_NONE;
1022 }
1023 
1029 static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht)
1030 {
1031  switch (tht) {
1032  default:
1033  case THT_NONE: break;
1034  case THT_WHITE: DrawTileSelectionRect(ti, PAL_NONE); break;
1035  case THT_BLUE: DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); break;
1036  case THT_RED: DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); break;
1037  }
1038 }
1039 
1045 {
1046  /* Going through cases in order of computational time. */
1047 
1048  if (_town_local_authority_kdtree.Count() == 0) return;
1049 
1050  /* Tile belongs to town regardless of distance from town. */
1051  if (GetTileType(ti->tile) == MP_HOUSE) {
1052  if (!Town::GetByTile(ti->tile)->show_zone) return;
1053 
1055  return;
1056  }
1057 
1058  /* If the closest town in the highlighted list is far, we can stop searching. */
1059  TownID tid = _town_local_authority_kdtree.FindNearest(TileX(ti->tile), TileY(ti->tile));
1060  Town *closest_highlighted_town = Town::Get(tid);
1061 
1062  if (DistanceManhattan(ti->tile, closest_highlighted_town->xy) >= _settings_game.economy.dist_local_authority) return;
1063 
1064  /* Tile is inside of the local autrhority distance of a highlighted town,
1065  but it is possible that a non-highlighted town is even closer. */
1067 
1068  if (closest_town->show_zone) {
1070  }
1071 
1072 }
1073 
1078 static void DrawTileSelection(const TileInfo *ti)
1079 {
1080  /* Highlight tiles insede local authority of selected towns. */
1082 
1083  /* Draw a red error square? */
1084  bool is_redsq = _thd.redsq == ti->tile;
1086 
1087  TileHighlightType tht = GetTileHighlightType(ti->tile);
1088  DrawTileHighlightType(ti, tht);
1089 
1090  /* No tile selection active? */
1091  if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return;
1092 
1093  if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle
1094  if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner;
1095  return;
1096  }
1097 
1098  /* Inside the inner area? */
1099  if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) &&
1100  IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) {
1101 draw_inner:
1102  if (_thd.drawstyle & HT_RECT) {
1103  if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE);
1104  } else if (_thd.drawstyle & HT_POINT) {
1105  /* Figure out the Z coordinate for the single dot. */
1106  int z = 0;
1107  FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
1108  if (ti->tileh & SLOPE_N) {
1109  z += TILE_HEIGHT;
1111  }
1112  if (IsHalftileSlope(ti->tileh)) {
1113  Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
1114  if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
1115  if (halftile_corner != CORNER_S) {
1116  foundation_part = FOUNDATION_PART_HALFTILE;
1117  if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
1118  }
1119  }
1120  DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part);
1121  } else if (_thd.drawstyle & HT_RAIL) {
1122  /* autorail highlight piece under cursor */
1123  HighLightStyle type = _thd.drawstyle & HT_DIR_MASK;
1124  assert(type < HT_DIR_END);
1125  DrawAutorailSelection(ti, _autorail_type[type][0]);
1126  } else if (IsPartOfAutoLine(ti->x, ti->y)) {
1127  /* autorail highlighting long line */
1128  HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK;
1129  uint side;
1130 
1131  if (dir == HT_DIR_X || dir == HT_DIR_Y) {
1132  side = 0;
1133  } else {
1134  TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
1135  side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile)));
1136  }
1137 
1138  DrawAutorailSelection(ti, _autorail_type[dir][side]);
1139  }
1140  return;
1141  }
1142 
1143  /* Check if it's inside the outer area? */
1144  if (!is_redsq && (tht == THT_NONE || tht == THT_RED) && _thd.outersize.x > 0 &&
1145  IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
1146  IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
1147  /* Draw a blue rect. */
1149  return;
1150  }
1151 }
1152 
1159 static int GetViewportY(Point tile)
1160 {
1161  /* Each increment in X or Y direction moves down by half a tile, i.e. TILE_PIXELS / 2. */
1162  return (tile.y * (int)(TILE_PIXELS / 2) + tile.x * (int)(TILE_PIXELS / 2) - TilePixelHeightOutsideMap(tile.x, tile.y)) << ZOOM_LVL_SHIFT;
1163 }
1164 
1169 {
1170  assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height);
1171  assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width);
1172 
1173  Point upper_left = InverseRemapCoords(_vd.dpi.left, _vd.dpi.top);
1174  Point upper_right = InverseRemapCoords(_vd.dpi.left + _vd.dpi.width, _vd.dpi.top);
1175 
1176  /* Transformations between tile coordinates and viewport rows/columns: See vp_column_row
1177  * column = y - x
1178  * row = x + y
1179  * x = (row - column) / 2
1180  * y = (row + column) / 2
1181  * Note: (row, columns) pairs are only valid, if they are both even or both odd.
1182  */
1183 
1184  /* Columns overlap with neighbouring columns by a half tile.
1185  * - Left column is column of upper_left (rounded down) and one column to the left.
1186  * - Right column is column of upper_right (rounded up) and one column to the right.
1187  * Note: Integer-division does not round down for negative numbers, so ensure rounding with another increment/decrement.
1188  */
1189  int left_column = (upper_left.y - upper_left.x) / (int)TILE_SIZE - 2;
1190  int right_column = (upper_right.y - upper_right.x) / (int)TILE_SIZE + 2;
1191 
1192  int potential_bridge_height = ZOOM_LVL_BASE * TILE_HEIGHT * _settings_game.construction.max_bridge_height;
1193 
1194  /* Rows overlap with neighbouring rows by a half tile.
1195  * The first row that could possibly be visible is the row above upper_left (if it is at height 0).
1196  * Due to integer-division not rounding down for negative numbers, we need another decrement.
1197  */
1198  int row = (upper_left.x + upper_left.y) / (int)TILE_SIZE - 2;
1199  bool last_row = false;
1200  for (; !last_row; row++) {
1201  last_row = true;
1202  for (int column = left_column; column <= right_column; column++) {
1203  /* Valid row/column? */
1204  if ((row + column) % 2 != 0) continue;
1205 
1206  Point tilecoord;
1207  tilecoord.x = (row - column) / 2;
1208  tilecoord.y = (row + column) / 2;
1209  assert(column == tilecoord.y - tilecoord.x);
1210  assert(row == tilecoord.y + tilecoord.x);
1211 
1212  TileType tile_type;
1213  TileInfo tile_info;
1214  _cur_ti = &tile_info;
1215  tile_info.x = tilecoord.x * TILE_SIZE; // FIXME tile_info should use signed integers
1216  tile_info.y = tilecoord.y * TILE_SIZE;
1217 
1218  if (IsInsideBS(tilecoord.x, 0, MapSizeX()) && IsInsideBS(tilecoord.y, 0, MapSizeY())) {
1219  /* This includes the south border at MapMaxX / MapMaxY. When terraforming we still draw tile selections there. */
1220  tile_info.tile = TileXY(tilecoord.x, tilecoord.y);
1221  tile_type = GetTileType(tile_info.tile);
1222  } else {
1223  tile_info.tile = INVALID_TILE;
1224  tile_type = MP_VOID;
1225  }
1226 
1227  if (tile_type != MP_VOID) {
1228  /* We are inside the map => paint landscape. */
1229  tile_info.tileh = GetTilePixelSlope(tile_info.tile, &tile_info.z);
1230  } else {
1231  /* We are outside the map => paint black. */
1232  tile_info.tileh = GetTilePixelSlopeOutsideMap(tilecoord.x, tilecoord.y, &tile_info.z);
1233  }
1234 
1235  int viewport_y = GetViewportY(tilecoord);
1236 
1237  if (viewport_y + MAX_TILE_EXTENT_BOTTOM < _vd.dpi.top) {
1238  /* The tile in this column is not visible yet.
1239  * Tiles in other columns may be visible, but we need more rows in any case. */
1240  last_row = false;
1241  continue;
1242  }
1243 
1244  int min_visible_height = viewport_y - (_vd.dpi.top + _vd.dpi.height);
1245  bool tile_visible = min_visible_height <= 0;
1246 
1247  if (tile_type != MP_VOID) {
1248  /* Is tile with buildings visible? */
1249  if (min_visible_height < MAX_TILE_EXTENT_TOP) tile_visible = true;
1250 
1251  if (IsBridgeAbove(tile_info.tile)) {
1252  /* Is the bridge visible? */
1253  TileIndex bridge_tile = GetNorthernBridgeEnd(tile_info.tile);
1254  int bridge_height = ZOOM_LVL_BASE * (GetBridgePixelHeight(bridge_tile) - TilePixelHeight(tile_info.tile));
1255  if (min_visible_height < bridge_height + MAX_TILE_EXTENT_TOP) tile_visible = true;
1256  }
1257 
1258  /* Would a higher bridge on a more southern tile be visible?
1259  * If yes, we need to loop over more rows to possibly find one. */
1260  if (min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
1261  } else {
1262  /* Outside of map. If we are on the north border of the map, there may still be a bridge visible,
1263  * so we need to loop over more rows to possibly find one. */
1264  if ((tilecoord.x <= 0 || tilecoord.y <= 0) && min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
1265  }
1266 
1267  if (tile_visible) {
1268  last_row = false;
1270  _vd.foundation[0] = -1;
1271  _vd.foundation[1] = -1;
1272  _vd.last_foundation_child[0] = nullptr;
1273  _vd.last_foundation_child[1] = nullptr;
1274 
1275  _tile_type_procs[tile_type]->draw_tile_proc(&tile_info);
1276  if (tile_info.tile != INVALID_TILE) DrawTileSelection(&tile_info);
1277  }
1278  }
1279  }
1280 }
1281 
1292 void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2, Colours colour)
1293 {
1294  bool small = dpi->zoom >= small_from;
1295 
1296  int left = dpi->left;
1297  int top = dpi->top;
1298  int right = left + dpi->width;
1299  int bottom = top + dpi->height;
1300 
1301  int sign_height = ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM, dpi->zoom);
1302  int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom);
1303 
1304  if (bottom < sign->top ||
1305  top > sign->top + sign_height ||
1306  right < sign->center - sign_half_width ||
1307  left > sign->center + sign_half_width) {
1308  return;
1309  }
1310 
1311  if (!small) {
1312  AddStringToDraw(sign->center - sign_half_width, sign->top, string_normal, params_1, params_2, colour, sign->width_normal);
1313  } else {
1314  int shadow_offset = 0;
1315  if (string_small_shadow != STR_NULL) {
1316  shadow_offset = 4;
1317  AddStringToDraw(sign->center - sign_half_width + shadow_offset, sign->top, string_small_shadow, params_1, params_2, INVALID_COLOUR, sign->width_small);
1318  }
1319  AddStringToDraw(sign->center - sign_half_width, sign->top - shadow_offset, string_small, params_1, params_2,
1320  colour, sign->width_small | 0x8000);
1321  }
1322 }
1323 
1324 static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom)
1325 {
1326  /* Pessimistically always use normal font, but also assume small font is never larger in either dimension */
1327  const int fh = FONT_HEIGHT_NORMAL;
1328  const int max_tw = _viewport_sign_maxwidth / 2 + 1;
1329  const int expand_y = ScaleByZoom(VPSM_TOP + fh + VPSM_BOTTOM, zoom);
1330  const int expand_x = ScaleByZoom(VPSM_LEFT + max_tw + VPSM_RIGHT, zoom);
1331 
1332  r.left -= expand_x;
1333  r.right += expand_x;
1334  r.top -= expand_y;
1335  r.bottom += expand_y;
1336 
1337  return r;
1338 }
1339 
1340 static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi)
1341 {
1342  Rect search_rect{ dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height };
1343  search_rect = ExpandRectWithViewportSignMargins(search_rect, dpi->zoom);
1344 
1345  bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && _game_mode != GM_MENU;
1346  bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && _game_mode != GM_MENU;
1347  bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES) && _game_mode != GM_MENU;
1348  bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS);
1349  bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
1350 
1351  const BaseStation *st;
1352  const Sign *si;
1353 
1354  /* Collect all the items first and draw afterwards, to ensure layering */
1355  std::vector<const BaseStation *> stations;
1356  std::vector<const Town *> towns;
1357  std::vector<const Sign *> signs;
1358 
1359  _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) {
1360  switch (item.type) {
1361  case ViewportSignKdtreeItem::VKI_STATION:
1362  if (!show_stations) break;
1363  st = BaseStation::Get(item.id.station);
1364 
1365  /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */
1366  if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
1367 
1368  stations.push_back(st);
1369  break;
1370 
1371  case ViewportSignKdtreeItem::VKI_WAYPOINT:
1372  if (!show_waypoints) break;
1373  st = BaseStation::Get(item.id.station);
1374 
1375  /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */
1376  if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
1377 
1378  stations.push_back(st);
1379  break;
1380 
1381  case ViewportSignKdtreeItem::VKI_TOWN:
1382  if (!show_towns) break;
1383  towns.push_back(Town::Get(item.id.town));
1384  break;
1385 
1386  case ViewportSignKdtreeItem::VKI_SIGN:
1387  if (!show_signs) break;
1388  si = Sign::Get(item.id.sign);
1389 
1390  /* Don't draw if sign is owned by another company and competitor signs should be hidden.
1391  * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt
1392  * companies can leave OWNER_NONE signs after them. */
1393  if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break;
1394 
1395  signs.push_back(si);
1396  break;
1397 
1398  default:
1399  NOT_REACHED();
1400  }
1401  });
1402 
1403  /* Layering order (bottom to top): Town names, signs, stations */
1404 
1405  for (const auto *t : towns) {
1406  ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign,
1407  _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN,
1408  STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK,
1409  t->index, t->cache.population);
1410  }
1411 
1412  for (const auto *si : signs) {
1413  ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &si->sign,
1414  STR_WHITE_SIGN,
1415  (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL,
1416  si->index, 0, (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner]));
1417  }
1418 
1419  for (const auto *st : stations) {
1420  if (Station::IsExpected(st)) {
1421  /* Station */
1422  ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign,
1423  STR_VIEWPORT_STATION, STR_VIEWPORT_STATION + 1, STR_NULL,
1424  st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]);
1425  } else {
1426  /* Waypoint */
1427  ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign,
1428  STR_VIEWPORT_WAYPOINT, STR_VIEWPORT_WAYPOINT + 1, STR_NULL,
1429  st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]);
1430  }
1431  }
1432 }
1433 
1434 
1442 void ViewportSign::UpdatePosition(int center, int top, StringID str, StringID str_small)
1443 {
1444  if (this->width_normal != 0) this->MarkDirty();
1445 
1446  this->top = top;
1447 
1448  char buffer[DRAW_STRING_BUFFER];
1449 
1450  GetString(buffer, str, lastof(buffer));
1451  this->width_normal = VPSM_LEFT + Align(GetStringBoundingBox(buffer).width, 2) + VPSM_RIGHT;
1452  this->center = center;
1453 
1454  /* zoomed out version */
1455  if (str_small != STR_NULL) {
1456  GetString(buffer, str_small, lastof(buffer));
1457  }
1458  this->width_small = VPSM_LEFT + Align(GetStringBoundingBox(buffer, FS_SMALL).width, 2) + VPSM_RIGHT;
1459 
1460  this->MarkDirty();
1461 }
1462 
1470 {
1471  Rect zoomlevels[ZOOM_LVL_COUNT];
1472 
1473  for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) {
1474  /* FIXME: This doesn't switch to width_small when appropriate. */
1475  zoomlevels[zoom].left = this->center - ScaleByZoom(this->width_normal / 2 + 1, zoom);
1476  zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom);
1477  zoomlevels[zoom].right = this->center + ScaleByZoom(this->width_normal / 2 + 1, zoom);
1478  zoomlevels[zoom].bottom = this->top + ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM + 1, zoom);
1479  }
1480 
1481  Window *w;
1482  FOR_ALL_WINDOWS_FROM_BACK(w) {
1483  ViewPort *vp = w->viewport;
1484  if (vp != nullptr && vp->zoom <= maxzoom) {
1485  assert(vp->width != 0);
1486  Rect &zl = zoomlevels[vp->zoom];
1487  MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom);
1488  }
1489  }
1490 }
1491 
1492 static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv)
1493 {
1494  for (const TileSpriteToDraw &ts : *tstdv) {
1495  DrawSpriteViewport(ts.image, ts.pal, ts.x, ts.y, ts.sub);
1496  }
1497 }
1498 
1501 {
1502  return true;
1503 }
1504 
1506 static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
1507 {
1508  auto psdvend = psdv->end();
1509  auto psd = psdv->begin();
1510  while (psd != psdvend) {
1511  ParentSpriteToDraw *ps = *psd;
1512 
1513  if (ps->comparison_done) {
1514  psd++;
1515  continue;
1516  }
1517 
1518  ps->comparison_done = true;
1519 
1520  for (auto psd2 = psd + 1; psd2 != psdvend; psd2++) {
1521  ParentSpriteToDraw *ps2 = *psd2;
1522 
1523  if (ps2->comparison_done) continue;
1524 
1525  /* Decide which comparator to use, based on whether the bounding
1526  * boxes overlap
1527  */
1528  if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X?
1529  ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y?
1530  ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z?
1531  /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of
1532  * the screen and with higher Z elevation, are drawn in front.
1533  * Here X,Y,Z are the coordinates of the "center of mass" of the sprite,
1534  * i.e. X=(left+right)/2, etc.
1535  * However, since we only care about order, don't actually divide / 2
1536  */
1537  if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <=
1538  ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) {
1539  continue;
1540  }
1541  } else {
1542  /* We only change the order, if it is definite.
1543  * I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap.
1544  * That is: If one partial order says ps behind ps2, do not change the order.
1545  */
1546  if (ps->xmax < ps2->xmin ||
1547  ps->ymax < ps2->ymin ||
1548  ps->zmax < ps2->zmin) {
1549  continue;
1550  }
1551  }
1552 
1553  /* Move ps2 in front of ps */
1554  ParentSpriteToDraw *temp = ps2;
1555  for (auto psd3 = psd2; psd3 > psd; psd3--) {
1556  *psd3 = *(psd3 - 1);
1557  }
1558  *psd = temp;
1559  }
1560  }
1561 }
1562 
1563 static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv)
1564 {
1565  for (const ParentSpriteToDraw *ps : *psd) {
1566  if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub);
1567 
1568  int child_idx = ps->first_child;
1569  while (child_idx >= 0) {
1570  const ChildScreenSpriteToDraw *cs = csstdv->data() + child_idx;
1571  child_idx = cs->next;
1572  DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub);
1573  }
1574  }
1575 }
1576 
1581 static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
1582 {
1583  for (const ParentSpriteToDraw *ps : *psd) {
1584  Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner
1585  Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner
1586  Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner
1587  Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin ); // bottom front corner
1588 
1589  DrawBox( pt1.x, pt1.y,
1590  pt2.x - pt1.x, pt2.y - pt1.y,
1591  pt3.x - pt1.x, pt3.y - pt1.y,
1592  pt4.x - pt1.x, pt4.y - pt1.y);
1593  }
1594 }
1595 
1600 {
1602  const DrawPixelInfo *dpi = _cur_dpi;
1603  void *dst;
1604  int right = UnScaleByZoom(dpi->width, dpi->zoom);
1605  int bottom = UnScaleByZoom(dpi->height, dpi->zoom);
1606 
1607  int colour = _string_colourmap[_dirty_block_colour & 0xF];
1608 
1609  dst = dpi->dst_ptr;
1610 
1611  byte bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
1612  do {
1613  for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour);
1614  dst = blitter->MoveTo(dst, 0, 1);
1615  } while (--bottom > 0);
1616 }
1617 
1618 static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv)
1619 {
1620  for (const StringSpriteToDraw &ss : *sstdv) {
1621  TextColour colour = TC_BLACK;
1622  bool small = HasBit(ss.width, 15);
1623  int w = GB(ss.width, 0, 15);
1624  int x = UnScaleByZoom(ss.x, zoom);
1625  int y = UnScaleByZoom(ss.y, zoom);
1626  int h = VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM;
1627 
1628  SetDParam(0, ss.params[0]);
1629  SetDParam(1, ss.params[1]);
1630 
1631  if (ss.colour != INVALID_COLOUR) {
1632  /* Do not draw signs nor station names if they are set invisible */
1633  if (IsInvisibilitySet(TO_SIGNS) && ss.string != STR_WHITE_SIGN) continue;
1634 
1635  if (IsTransparencySet(TO_SIGNS) && ss.string != STR_WHITE_SIGN) {
1636  /* Don't draw the rectangle.
1637  * Real colours need the TC_IS_PALETTE_COLOUR flag.
1638  * Otherwise colours from _string_colourmap are assumed. */
1639  colour = (TextColour)_colour_gradient[ss.colour][6] | TC_IS_PALETTE_COLOUR;
1640  } else {
1641  /* Draw the rectangle if 'transparent station signs' is off,
1642  * or if we are drawing a general text sign (STR_WHITE_SIGN). */
1643  DrawFrameRect(
1644  x, y, x + w, y + h, ss.colour,
1646  );
1647  }
1648  }
1649 
1650  DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss.string, colour, SA_HOR_CENTER);
1651  }
1652 }
1653 
1654 void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom)
1655 {
1656  DrawPixelInfo *old_dpi = _cur_dpi;
1657  _cur_dpi = &_vd.dpi;
1658 
1659  _vd.dpi.zoom = vp->zoom;
1660  int mask = ScaleByZoom(-1, vp->zoom);
1661 
1663 
1664  _vd.dpi.width = (right - left) & mask;
1665  _vd.dpi.height = (bottom - top) & mask;
1666  _vd.dpi.left = left & mask;
1667  _vd.dpi.top = top & mask;
1668  _vd.dpi.pitch = old_dpi->pitch;
1669  _vd.last_child = nullptr;
1670 
1671  int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
1672  int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
1673 
1674  _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
1675 
1677  ViewportAddVehicles(&_vd.dpi);
1678 
1679  ViewportAddKdtreeSigns(&_vd.dpi);
1680 
1681  DrawTextEffects(&_vd.dpi);
1682 
1683  if (_vd.tile_sprites_to_draw.size() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw);
1684 
1685  for (auto &psd : _vd.parent_sprites_to_draw) {
1686  _vd.parent_sprites_to_sort.push_back(&psd);
1687  }
1688 
1689  _vp_sprite_sorter(&_vd.parent_sprites_to_sort);
1690  ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw);
1691 
1692  if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort);
1693  if (_draw_dirty_blocks) ViewportDrawDirtyBlocks();
1694 
1695  DrawPixelInfo dp = _vd.dpi;
1696  ZoomLevel zoom = _vd.dpi.zoom;
1697  dp.zoom = ZOOM_LVL_NORMAL;
1698  dp.width = UnScaleByZoom(dp.width, zoom);
1699  dp.height = UnScaleByZoom(dp.height, zoom);
1700  _cur_dpi = &dp;
1701 
1702  if (vp->overlay != nullptr && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) {
1703  /* translate to window coordinates */
1704  dp.left = x;
1705  dp.top = y;
1706  vp->overlay->Draw(&dp);
1707  }
1708 
1709  if (_vd.string_sprites_to_draw.size() != 0) {
1710  /* translate to world coordinates */
1711  dp.left = UnScaleByZoom(_vd.dpi.left, zoom);
1712  dp.top = UnScaleByZoom(_vd.dpi.top, zoom);
1713  ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw);
1714  }
1715 
1716  _cur_dpi = old_dpi;
1717 
1718  _vd.string_sprites_to_draw.clear();
1719  _vd.tile_sprites_to_draw.clear();
1720  _vd.parent_sprites_to_draw.clear();
1721  _vd.parent_sprites_to_sort.clear();
1722  _vd.child_screen_sprites_to_draw.clear();
1723 }
1724 
1729 static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
1730 {
1731  if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > (int)(180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE)) {
1732  if ((bottom - top) > (right - left)) {
1733  int t = (top + bottom) >> 1;
1734  ViewportDrawChk(vp, left, top, right, t);
1735  ViewportDrawChk(vp, left, t, right, bottom);
1736  } else {
1737  int t = (left + right) >> 1;
1738  ViewportDrawChk(vp, left, top, t, bottom);
1739  ViewportDrawChk(vp, t, top, right, bottom);
1740  }
1741  } else {
1742  ViewportDoDraw(vp,
1743  ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
1744  ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top,
1745  ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left,
1746  ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top
1747  );
1748  }
1749 }
1750 
1751 static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
1752 {
1753  if (right <= vp->left || bottom <= vp->top) return;
1754 
1755  if (left >= vp->left + vp->width) return;
1756 
1757  if (left < vp->left) left = vp->left;
1758  if (right > vp->left + vp->width) right = vp->left + vp->width;
1759 
1760  if (top >= vp->top + vp->height) return;
1761 
1762  if (top < vp->top) top = vp->top;
1763  if (bottom > vp->top + vp->height) bottom = vp->top + vp->height;
1764 
1765  ViewportDrawChk(vp, left, top, right, bottom);
1766 }
1767 
1772 {
1774 
1775  DrawPixelInfo *dpi = _cur_dpi;
1776 
1777  dpi->left += this->left;
1778  dpi->top += this->top;
1779 
1780  ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
1781 
1782  dpi->left -= this->left;
1783  dpi->top -= this->top;
1784 }
1785 
1796 static inline void ClampViewportToMap(const ViewPort *vp, int *scroll_x, int *scroll_y)
1797 {
1798  /* Centre of the viewport is hot spot. */
1799  Point pt = {
1800  *scroll_x + vp->virtual_width / 2,
1801  *scroll_y + vp->virtual_height / 2
1802  };
1803 
1804  /* Find nearest tile that is within borders of the map. */
1805  bool clamped;
1806  pt = InverseRemapCoords2(pt.x, pt.y, true, &clamped);
1807 
1808  if (clamped) {
1809  /* Convert back to viewport coordinates and remove centering. */
1810  pt = RemapCoords2(pt.x, pt.y);
1811  *scroll_x = pt.x - vp->virtual_width / 2;
1812  *scroll_y = pt.y - vp->virtual_height / 2;
1813  }
1814 }
1815 
1821 {
1822  const ViewPort *vp = w->viewport;
1823 
1825  const Vehicle *veh = Vehicle::Get(w->viewport->follow_vehicle);
1826  Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
1827 
1828  w->viewport->scrollpos_x = pt.x;
1829  w->viewport->scrollpos_y = pt.y;
1830  SetViewportPosition(w, pt.x, pt.y);
1831  } else {
1832  /* Ensure the destination location is within the map */
1834 
1835  int delta_x = w->viewport->dest_scrollpos_x - w->viewport->scrollpos_x;
1836  int delta_y = w->viewport->dest_scrollpos_y - w->viewport->scrollpos_y;
1837 
1838  bool update_overlay = false;
1839  if (delta_x != 0 || delta_y != 0) {
1841  int max_scroll = ScaleByMapSize1D(512 * ZOOM_LVL_BASE);
1842  /* Not at our desired position yet... */
1843  w->viewport->scrollpos_x += Clamp(DivAwayFromZero(delta_x, 4), -max_scroll, max_scroll);
1844  w->viewport->scrollpos_y += Clamp(DivAwayFromZero(delta_y, 4), -max_scroll, max_scroll);
1845  } else {
1848  }
1849  update_overlay = (w->viewport->scrollpos_x == w->viewport->dest_scrollpos_x &&
1851  }
1852 
1854 
1855  SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y);
1856  if (update_overlay) RebuildViewportOverlay(w);
1857  }
1858 }
1859 
1869 static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
1870 {
1871  /* Rounding wrt. zoom-out level */
1872  right += (1 << vp->zoom) - 1;
1873  bottom += (1 << vp->zoom) - 1;
1874 
1875  right -= vp->virtual_left;
1876  if (right <= 0) return;
1877 
1878  bottom -= vp->virtual_top;
1879  if (bottom <= 0) return;
1880 
1881  left = max(0, left - vp->virtual_left);
1882 
1883  if (left >= vp->virtual_width) return;
1884 
1885  top = max(0, top - vp->virtual_top);
1886 
1887  if (top >= vp->virtual_height) return;
1888 
1890  UnScaleByZoomLower(left, vp->zoom) + vp->left,
1891  UnScaleByZoomLower(top, vp->zoom) + vp->top,
1892  UnScaleByZoom(right, vp->zoom) + vp->left + 1,
1893  UnScaleByZoom(bottom, vp->zoom) + vp->top + 1
1894  );
1895 }
1896 
1905 void MarkAllViewportsDirty(int left, int top, int right, int bottom)
1906 {
1907  Window *w;
1908  FOR_ALL_WINDOWS_FROM_BACK(w) {
1909  ViewPort *vp = w->viewport;
1910  if (vp != nullptr) {
1911  assert(vp->width != 0);
1912  MarkViewportDirty(vp, left, top, right, bottom);
1913  }
1914  }
1915 }
1916 
1917 void ConstrainAllViewportsZoom()
1918 {
1919  Window *w;
1920  FOR_ALL_WINDOWS_FROM_FRONT(w) {
1921  if (w->viewport == nullptr) continue;
1922 
1924  if (zoom != w->viewport->zoom) {
1925  while (w->viewport->zoom < zoom) DoZoomInOutWindow(ZOOM_OUT, w);
1926  while (w->viewport->zoom > zoom) DoZoomInOutWindow(ZOOM_IN, w);
1927  }
1928  }
1929 }
1930 
1938 void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
1939 {
1940  Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, tile_height_override * TILE_HEIGHT);
1942  pt.x - MAX_TILE_EXTENT_LEFT,
1943  pt.y - MAX_TILE_EXTENT_TOP - ZOOM_LVL_BASE * TILE_HEIGHT * bridge_level_offset,
1944  pt.x + MAX_TILE_EXTENT_RIGHT,
1945  pt.y + MAX_TILE_EXTENT_BOTTOM);
1946 }
1947 
1956 {
1957  int x_size = _thd.size.x;
1958  int y_size = _thd.size.y;
1959 
1960  if (!_thd.diagonal) { // Selecting in a straight rectangle (or a single square)
1961  int x_start = _thd.pos.x;
1962  int y_start = _thd.pos.y;
1963 
1964  if (_thd.outersize.x != 0) {
1965  x_size += _thd.outersize.x;
1966  x_start += _thd.offs.x;
1967  y_size += _thd.outersize.y;
1968  y_start += _thd.offs.y;
1969  }
1970 
1971  x_size -= TILE_SIZE;
1972  y_size -= TILE_SIZE;
1973 
1974  assert(x_size >= 0);
1975  assert(y_size >= 0);
1976 
1977  int x_end = Clamp(x_start + x_size, 0, MapSizeX() * TILE_SIZE - TILE_SIZE);
1978  int y_end = Clamp(y_start + y_size, 0, MapSizeY() * TILE_SIZE - TILE_SIZE);
1979 
1980  x_start = Clamp(x_start, 0, MapSizeX() * TILE_SIZE - TILE_SIZE);
1981  y_start = Clamp(y_start, 0, MapSizeY() * TILE_SIZE - TILE_SIZE);
1982 
1983  /* make sure everything is multiple of TILE_SIZE */
1984  assert((x_end | y_end | x_start | y_start) % TILE_SIZE == 0);
1985 
1986  /* How it works:
1987  * Suppose we have to mark dirty rectangle of 3x4 tiles:
1988  * x
1989  * xxx
1990  * xxxxx
1991  * xxxxx
1992  * xxx
1993  * x
1994  * This algorithm marks dirty columns of tiles, so it is done in 3+4-1 steps:
1995  * 1) x 2) x
1996  * xxx Oxx
1997  * Oxxxx xOxxx
1998  * xxxxx Oxxxx
1999  * xxx xxx
2000  * x x
2001  * And so forth...
2002  */
2003 
2004  int top_x = x_end; // coordinates of top dirty tile
2005  int top_y = y_start;
2006  int bot_x = top_x; // coordinates of bottom dirty tile
2007  int bot_y = top_y;
2008 
2009  do {
2010  /* topmost dirty point */
2011  TileIndex top_tile = TileVirtXY(top_x, top_y);
2012  Point top = RemapCoords(top_x, top_y, GetTileMaxPixelZ(top_tile));
2013 
2014  /* bottommost point */
2015  TileIndex bottom_tile = TileVirtXY(bot_x, bot_y);
2016  Point bot = RemapCoords(bot_x + TILE_SIZE, bot_y + TILE_SIZE, GetTilePixelZ(bottom_tile)); // bottommost point
2017 
2018  /* the 'x' coordinate of 'top' and 'bot' is the same (and always in the same distance from tile middle),
2019  * tile height/slope affects only the 'y' on-screen coordinate! */
2020 
2021  int l = top.x - TILE_PIXELS * ZOOM_LVL_BASE; // 'x' coordinate of left side of the dirty rectangle
2022  int t = top.y; // 'y' coordinate of top side of the dirty rectangle
2023  int r = top.x + TILE_PIXELS * ZOOM_LVL_BASE; // 'x' coordinate of right side of the dirty rectangle
2024  int b = bot.y; // 'y' coordinate of bottom side of the dirty rectangle
2025 
2026  static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE; // part of selection sprites is drawn outside the selected area (in particular: terraforming)
2027 
2028  /* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */
2029  MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_LVL_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH);
2030 
2031  /* haven't we reached the topmost tile yet? */
2032  if (top_x != x_start) {
2033  top_x -= TILE_SIZE;
2034  } else {
2035  top_y += TILE_SIZE;
2036  }
2037 
2038  /* the way the bottom tile changes is different when we reach the bottommost tile */
2039  if (bot_y != y_end) {
2040  bot_y += TILE_SIZE;
2041  } else {
2042  bot_x -= TILE_SIZE;
2043  }
2044  } while (bot_x >= top_x);
2045  } else { // Selecting in a 45 degrees rotated (diagonal) rectangle.
2046  /* a_size, b_size describe a rectangle with rotated coordinates */
2047  int a_size = x_size + y_size, b_size = x_size - y_size;
2048 
2049  int interval_a = a_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE;
2050  int interval_b = b_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE;
2051 
2052  for (int a = -interval_a; a != a_size + interval_a; a += interval_a) {
2053  for (int b = -interval_b; b != b_size + interval_b; b += interval_b) {
2054  uint x = (_thd.pos.x + (a + b) / 2) / TILE_SIZE;
2055  uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE;
2056 
2057  if (x < MapMaxX() && y < MapMaxY()) {
2058  MarkTileDirtyByTile(TileXY(x, y));
2059  }
2060  }
2061  }
2062  }
2063 }
2064 
2065 
2066 void SetSelectionRed(bool b)
2067 {
2068  _thd.make_square_red = b;
2070 }
2071 
2080 static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign)
2081 {
2082  bool small = (vp->zoom >= ZOOM_LVL_OUT_16X);
2083  int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom);
2084  int sign_height = ScaleByZoom(VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM, vp->zoom);
2085 
2086  return y >= sign->top && y < sign->top + sign_height &&
2087  x >= sign->center - sign_half_width && x < sign->center + sign_half_width;
2088 }
2089 
2090 
2098 static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y)
2099 {
2100  if (_game_mode == GM_MENU) return false;
2101 
2102  x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left;
2103  y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top;
2104 
2105  Rect search_rect{ x - 1, y - 1, x + 1, y + 1 };
2106  search_rect = ExpandRectWithViewportSignMargins(search_rect, vp->zoom);
2107 
2110  bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES);
2111  bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS);
2112  bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
2113 
2114  /* Topmost of each type that was hit */
2115  BaseStation *st = nullptr, *last_st = nullptr;
2116  Town *t = nullptr, *last_t = nullptr;
2117  Sign *si = nullptr, *last_si = nullptr;
2118 
2119  /* See ViewportAddKdtreeSigns() for details on the search logic */
2120  _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) {
2121  switch (item.type) {
2122  case ViewportSignKdtreeItem::VKI_STATION:
2123  if (!show_stations) break;
2124  st = BaseStation::Get(item.id.station);
2125  if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
2126  if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st;
2127  break;
2128 
2129  case ViewportSignKdtreeItem::VKI_WAYPOINT:
2130  if (!show_waypoints) break;
2131  st = BaseStation::Get(item.id.station);
2132  if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
2133  if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st;
2134  break;
2135 
2136  case ViewportSignKdtreeItem::VKI_TOWN:
2137  if (!show_towns) break;
2138  t = Town::Get(item.id.town);
2139  if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) last_t = t;
2140  break;
2141 
2142  case ViewportSignKdtreeItem::VKI_SIGN:
2143  if (!show_signs) break;
2144  si = Sign::Get(item.id.sign);
2145  if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break;
2146  if (CheckClickOnViewportSign(vp, x, y, &si->sign)) last_si = si;
2147  break;
2148 
2149  default:
2150  NOT_REACHED();
2151  }
2152  });
2153 
2154  /* Select which hit to handle based on priority */
2155  if (last_st != nullptr) {
2156  if (Station::IsExpected(last_st)) {
2157  ShowStationViewWindow(last_st->index);
2158  } else {
2160  }
2161  return true;
2162  } else if (last_t != nullptr) {
2163  ShowTownViewWindow(last_t->index);
2164  return true;
2165  } else if (last_si != nullptr) {
2166  HandleClickOnSign(last_si);
2167  return true;
2168  } else {
2169  return false;
2170  }
2171 }
2172 
2173 
2174 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id)
2175 {
2177  item.type = VKI_STATION;
2178  item.id.station = id;
2179 
2180  const Station *st = Station::Get(id);
2181  assert(st->sign.kdtree_valid);
2182  item.center = st->sign.center;
2183  item.top = st->sign.top;
2184 
2185  /* Assume the sign can be a candidate for drawing, so measure its width */
2186  _viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, st->sign.width_normal);
2187 
2188  return item;
2189 }
2190 
2191 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id)
2192 {
2194  item.type = VKI_WAYPOINT;
2195  item.id.station = id;
2196 
2197  const Waypoint *st = Waypoint::Get(id);
2198  assert(st->sign.kdtree_valid);
2199  item.center = st->sign.center;
2200  item.top = st->sign.top;
2201 
2202  /* Assume the sign can be a candidate for drawing, so measure its width */
2203  _viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, st->sign.width_normal);
2204 
2205  return item;
2206 }
2207 
2208 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id)
2209 {
2211  item.type = VKI_TOWN;
2212  item.id.town = id;
2213 
2214  const Town *town = Town::Get(id);
2215  assert(town->cache.sign.kdtree_valid);
2216  item.center = town->cache.sign.center;
2217  item.top = town->cache.sign.top;
2218 
2219  /* Assume the sign can be a candidate for drawing, so measure its width */
2220  _viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, town->cache.sign.width_normal);
2221 
2222  return item;
2223 }
2224 
2225 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id)
2226 {
2228  item.type = VKI_SIGN;
2229  item.id.sign = id;
2230 
2231  const Sign *sign = Sign::Get(id);
2232  assert(sign->sign.kdtree_valid);
2233  item.center = sign->sign.center;
2234  item.top = sign->sign.top;
2235 
2236  /* Assume the sign can be a candidate for drawing, so measure its width */
2237  _viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, sign->sign.width_normal);
2238 
2239  return item;
2240 }
2241 
2242 void RebuildViewportKdtree()
2243 {
2244  /* Reset biggest size sign seen */
2245  _viewport_sign_maxwidth = 0;
2246 
2247  std::vector<ViewportSignKdtreeItem> items;
2249 
2250  for (const Station *st : Station::Iterate()) {
2251  if (st->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeStation(st->index));
2252  }
2253 
2254  for (const Waypoint *wp : Waypoint::Iterate()) {
2255  if (wp->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeWaypoint(wp->index));
2256  }
2257 
2258  for (const Town *town : Town::Iterate()) {
2259  if (town->cache.sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeTown(town->index));
2260  }
2261 
2262  for (const Sign *sign : Sign::Iterate()) {
2263  if (sign->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeSign(sign->index));
2264  }
2265 
2266  _viewport_sign_kdtree.Build(items.begin(), items.end());
2267 }
2268 
2269 
2270 static bool CheckClickOnLandscape(const ViewPort *vp, int x, int y)
2271 {
2272  Point pt = TranslateXYToTileCoord(vp, x, y);
2273 
2274  if (pt.x != -1) return ClickTile(TileVirtXY(pt.x, pt.y));
2275  return true;
2276 }
2277 
2278 static void PlaceObject()
2279 {
2280  Point pt;
2281  Window *w;
2282 
2283  pt = GetTileBelowCursor();
2284  if (pt.x == -1) return;
2285 
2286  if ((_thd.place_mode & HT_DRAG_MASK) == HT_POINT) {
2287  pt.x += TILE_SIZE / 2;
2288  pt.y += TILE_SIZE / 2;
2289  }
2290 
2291  _tile_fract_coords.x = pt.x & TILE_UNIT_MASK;
2292  _tile_fract_coords.y = pt.y & TILE_UNIT_MASK;
2293 
2294  w = _thd.GetCallbackWnd();
2295  if (w != nullptr) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y));
2296 }
2297 
2298 
2299 bool HandleViewportClicked(const ViewPort *vp, int x, int y)
2300 {
2301  const Vehicle *v = CheckClickOnVehicle(vp, x, y);
2302 
2303  if (_thd.place_mode & HT_VEHICLE) {
2304  if (v != nullptr && VehicleClicked(v)) return true;
2305  }
2306 
2307  /* Vehicle placement mode already handled above. */
2308  if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
2309  PlaceObject();
2310  return true;
2311  }
2312 
2313  if (CheckClickOnViewportSign(vp, x, y)) return true;
2314  bool result = CheckClickOnLandscape(vp, x, y);
2315 
2316  if (v != nullptr) {
2317  DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v);
2319  v = v->First();
2320  if (_ctrl_pressed && v->owner == _local_company) {
2321  StartStopVehicle(v, true);
2322  } else {
2324  }
2325  }
2326  return true;
2327  }
2328  return result;
2329 }
2330 
2331 void RebuildViewportOverlay(Window *w)
2332 {
2333  if (w->viewport->overlay != nullptr &&
2334  w->viewport->overlay->GetCompanyMask() != 0 &&
2335  w->viewport->overlay->GetCargoMask() != 0) {
2336  w->viewport->overlay->SetDirty();
2337  w->SetDirty();
2338  }
2339 }
2340 
2350 bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant)
2351 {
2352  /* The slope cannot be acquired outside of the map, so make sure we are always within the map. */
2353  if (z == -1) {
2354  if ( x >= 0 && x <= (int)MapSizeX() * (int)TILE_SIZE - 1
2355  && y >= 0 && y <= (int)MapSizeY() * (int)TILE_SIZE - 1) {
2356  z = GetSlopePixelZ(x, y);
2357  } else {
2358  z = TileHeightOutsideMap(x / (int)TILE_SIZE, y / (int)TILE_SIZE);
2359  }
2360  }
2361 
2362  Point pt = MapXYZToViewport(w->viewport, x, y, z);
2364 
2365  if (w->viewport->dest_scrollpos_x == pt.x && w->viewport->dest_scrollpos_y == pt.y) return false;
2366 
2367  if (instant) {
2368  w->viewport->scrollpos_x = pt.x;
2369  w->viewport->scrollpos_y = pt.y;
2370  RebuildViewportOverlay(w);
2371  }
2372 
2373  w->viewport->dest_scrollpos_x = pt.x;
2374  w->viewport->dest_scrollpos_y = pt.y;
2375  return true;
2376 }
2377 
2385 bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
2386 {
2387  return ScrollWindowTo(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, -1, w, instant);
2388 }
2389 
2396 bool ScrollMainWindowToTile(TileIndex tile, bool instant)
2397 {
2398  return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, instant);
2399 }
2400 
2406 {
2407  TileIndex old;
2408 
2409  old = _thd.redsq;
2410  _thd.redsq = tile;
2411 
2412  if (tile != old) {
2413  if (tile != INVALID_TILE) MarkTileDirtyByTile(tile);
2414  if (old != INVALID_TILE) MarkTileDirtyByTile(old);
2415  }
2416 }
2417 
2423 void SetTileSelectSize(int w, int h)
2424 {
2425  _thd.new_size.x = w * TILE_SIZE;
2426  _thd.new_size.y = h * TILE_SIZE;
2427  _thd.new_outersize.x = 0;
2428  _thd.new_outersize.y = 0;
2429 }
2430 
2431 void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
2432 {
2433  _thd.offs.x = ox * TILE_SIZE;
2434  _thd.offs.y = oy * TILE_SIZE;
2435  _thd.new_outersize.x = sx * TILE_SIZE;
2436  _thd.new_outersize.y = sy * TILE_SIZE;
2437 }
2438 
2440 static HighLightStyle GetAutorailHT(int x, int y)
2441 {
2442  return HT_RAIL | _autorail_piece[x & TILE_UNIT_MASK][y & TILE_UNIT_MASK];
2443 }
2444 
2449 {
2450  this->pos.x = 0;
2451  this->pos.y = 0;
2452  this->new_pos.x = 0;
2453  this->new_pos.y = 0;
2454 }
2455 
2461 {
2462  return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down;
2463 }
2464 
2470 {
2471  return FindWindowById(this->window_class, this->window_number);
2472 }
2473 
2474 
2475 
2484 {
2485  int x1;
2486  int y1;
2487 
2488  if (_thd.freeze) return;
2489 
2490  HighLightStyle new_drawstyle = HT_NONE;
2491  bool new_diagonal = false;
2492 
2493  if ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL) {
2494  x1 = _thd.selend.x;
2495  y1 = _thd.selend.y;
2496  if (x1 != -1) {
2497  int x2 = _thd.selstart.x & ~TILE_UNIT_MASK;
2498  int y2 = _thd.selstart.y & ~TILE_UNIT_MASK;
2499  x1 &= ~TILE_UNIT_MASK;
2500  y1 &= ~TILE_UNIT_MASK;
2501 
2502  if (_thd.IsDraggingDiagonal()) {
2503  new_diagonal = true;
2504  } else {
2505  if (x1 >= x2) Swap(x1, x2);
2506  if (y1 >= y2) Swap(y1, y2);
2507  }
2508  _thd.new_pos.x = x1;
2509  _thd.new_pos.y = y1;
2510  _thd.new_size.x = x2 - x1;
2511  _thd.new_size.y = y2 - y1;
2512  if (!new_diagonal) {
2513  _thd.new_size.x += TILE_SIZE;
2514  _thd.new_size.y += TILE_SIZE;
2515  }
2516  new_drawstyle = _thd.next_drawstyle;
2517  }
2518  } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
2519  Point pt = GetTileBelowCursor();
2520  x1 = pt.x;
2521  y1 = pt.y;
2522  if (x1 != -1) {
2523  switch (_thd.place_mode & HT_DRAG_MASK) {
2524  case HT_RECT:
2525  new_drawstyle = HT_RECT;
2526  break;
2527  case HT_POINT:
2528  new_drawstyle = HT_POINT;
2529  x1 += TILE_SIZE / 2;
2530  y1 += TILE_SIZE / 2;
2531  break;
2532  case HT_RAIL:
2533  /* Draw one highlighted tile in any direction */
2534  new_drawstyle = GetAutorailHT(pt.x, pt.y);
2535  break;
2536  case HT_LINE:
2537  switch (_thd.place_mode & HT_DIR_MASK) {
2538  case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break;
2539  case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break;
2540 
2541  case HT_DIR_HU:
2542  case HT_DIR_HL:
2543  new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL;
2544  break;
2545 
2546  case HT_DIR_VL:
2547  case HT_DIR_VR:
2548  new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
2549  break;
2550 
2551  default: NOT_REACHED();
2552  }
2553  _thd.selstart.x = x1 & ~TILE_UNIT_MASK;
2554  _thd.selstart.y = y1 & ~TILE_UNIT_MASK;
2555  break;
2556  default:
2557  NOT_REACHED();
2558  }
2559  _thd.new_pos.x = x1 & ~TILE_UNIT_MASK;
2560  _thd.new_pos.y = y1 & ~TILE_UNIT_MASK;
2561  }
2562  }
2563 
2564  /* redraw selection */
2565  if (_thd.drawstyle != new_drawstyle ||
2566  _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
2567  _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
2568  _thd.outersize.x != _thd.new_outersize.x ||
2569  _thd.outersize.y != _thd.new_outersize.y ||
2570  _thd.diagonal != new_diagonal) {
2571  /* Clear the old tile selection? */
2573 
2574  _thd.drawstyle = new_drawstyle;
2575  _thd.pos = _thd.new_pos;
2576  _thd.size = _thd.new_size;
2577  _thd.outersize = _thd.new_outersize;
2578  _thd.diagonal = new_diagonal;
2579  _thd.dirty = 0xff;
2580 
2581  /* Draw the new tile selection? */
2582  if ((new_drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
2583  }
2584 }
2585 
2593 static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_NONE)
2594 {
2595  if (!_settings_client.gui.measure_tooltip) return;
2596  GuiShowTooltips(_thd.GetCallbackWnd(), str, paramcount, params, close_cond);
2597 }
2598 
2599 static void HideMeasurementTooltips()
2600 {
2602 }
2603 
2606 {
2607  _thd.select_method = method;
2608  _thd.select_proc = process;
2609  _thd.selend.x = TileX(tile) * TILE_SIZE;
2610  _thd.selstart.x = TileX(tile) * TILE_SIZE;
2611  _thd.selend.y = TileY(tile) * TILE_SIZE;
2612  _thd.selstart.y = TileY(tile) * TILE_SIZE;
2613 
2614  /* Needed so several things (road, autoroad, bridges, ...) are placed correctly.
2615  * In effect, placement starts from the centre of a tile
2616  */
2617  if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) {
2618  _thd.selend.x += TILE_SIZE / 2;
2619  _thd.selend.y += TILE_SIZE / 2;
2620  _thd.selstart.x += TILE_SIZE / 2;
2621  _thd.selstart.y += TILE_SIZE / 2;
2622  }
2623 
2624  HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
2625  if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) {
2626  _thd.place_mode = HT_SPECIAL | others;
2627  _thd.next_drawstyle = HT_RECT | others;
2628  } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) {
2629  _thd.place_mode = HT_SPECIAL | others;
2630  _thd.next_drawstyle = _thd.drawstyle | others;
2631  } else {
2632  _thd.place_mode = HT_SPECIAL | others;
2633  _thd.next_drawstyle = HT_POINT | others;
2634  }
2636 }
2637 
2638 void VpSetPlaceSizingLimit(int limit)
2639 {
2640  _thd.sizelimit = limit;
2641 }
2642 
2649 {
2650  uint64 distance = DistanceManhattan(from, to) + 1;
2651 
2652  _thd.selend.x = TileX(to) * TILE_SIZE;
2653  _thd.selend.y = TileY(to) * TILE_SIZE;
2654  _thd.selstart.x = TileX(from) * TILE_SIZE;
2655  _thd.selstart.y = TileY(from) * TILE_SIZE;
2656  _thd.next_drawstyle = HT_RECT;
2657 
2658  /* show measurement only if there is any length to speak of */
2659  if (distance > 1) {
2660  ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance);
2661  } else {
2662  HideMeasurementTooltips();
2663  }
2664 }
2665 
2666 static void VpStartPreSizing()
2667 {
2668  _thd.selend.x = -1;
2670 }
2671 
2677 {
2678  int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
2679  int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK);
2680  int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
2681  int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK);
2682 
2683  switch (mode) {
2684  default: NOT_REACHED();
2685  case 0: // end piece is lower right
2686  if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
2687  if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
2688  return HT_DIR_Y;
2689 
2690  case 1:
2691  if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
2692  if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
2693  return HT_DIR_Y;
2694 
2695  case 2:
2696  if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
2697  if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
2698  return HT_DIR_X;
2699 
2700  case 3:
2701  if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
2702  if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
2703  return HT_DIR_X;
2704  }
2705 }
2706 
2720 static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
2721 {
2722  uint start_x = TileX(start_tile);
2723  uint start_y = TileY(start_tile);
2724  uint end_x = TileX(end_tile);
2725  uint end_y = TileY(end_tile);
2726 
2727  switch (style & HT_DRAG_MASK) {
2728  case HT_RAIL:
2729  case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y));
2730 
2731  case HT_RECT:
2732  case HT_POINT: return (end_x != start_x && end_y < start_y);
2733  default: NOT_REACHED();
2734  }
2735 
2736  return false;
2737 }
2738 
2754 static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
2755 {
2756  bool swap = SwapDirection(style, start_tile, end_tile);
2757  uint h0, h1; // Start height and end height.
2758 
2759  if (start_tile == end_tile) return 0;
2760  if (swap) Swap(start_tile, end_tile);
2761 
2762  switch (style & HT_DRAG_MASK) {
2763  case HT_RECT: {
2764  static const TileIndexDiffC heightdiff_area_by_dir[] = {
2765  /* Start */ {1, 0}, /* Dragging east */ {0, 0}, // Dragging south
2766  /* End */ {0, 1}, /* Dragging east */ {1, 1} // Dragging south
2767  };
2768 
2769  /* In the case of an area we can determine whether we were dragging south or
2770  * east by checking the X-coordinates of the tiles */
2771  byte style_t = (byte)(TileX(end_tile) > TileX(start_tile));
2772  start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t]));
2773  end_tile = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t]));
2774  FALLTHROUGH;
2775  }
2776 
2777  case HT_POINT:
2778  h0 = TileHeight(start_tile);
2779  h1 = TileHeight(end_tile);
2780  break;
2781  default: { // All other types, this is mostly only line/autorail
2782  static const HighLightStyle flip_style_direction[] = {
2784  };
2785  static const TileIndexDiffC heightdiff_line_by_dir[] = {
2786  /* Start */ {1, 0}, {1, 1}, /* HT_DIR_X */ {0, 1}, {1, 1}, // HT_DIR_Y
2787  /* Start */ {1, 0}, {0, 0}, /* HT_DIR_HU */ {1, 0}, {1, 1}, // HT_DIR_HL
2788  /* Start */ {1, 0}, {1, 1}, /* HT_DIR_VL */ {0, 1}, {1, 1}, // HT_DIR_VR
2789 
2790  /* Start */ {0, 1}, {0, 0}, /* HT_DIR_X */ {1, 0}, {0, 0}, // HT_DIR_Y
2791  /* End */ {0, 1}, {0, 0}, /* HT_DIR_HU */ {1, 1}, {0, 1}, // HT_DIR_HL
2792  /* End */ {1, 0}, {0, 0}, /* HT_DIR_VL */ {0, 0}, {0, 1}, // HT_DIR_VR
2793  };
2794 
2795  distance %= 2; // we're only interested if the distance is even or uneven
2796  style &= HT_DIR_MASK;
2797 
2798  /* To handle autorail, we do some magic to be able to use a lookup table.
2799  * Firstly if we drag the other way around, we switch start&end, and if needed
2800  * also flip the drag-position. Eg if it was on the left, and the distance is even
2801  * that means the end, which is now the start is on the right */
2802  if (swap && distance == 0) style = flip_style_direction[style];
2803 
2804  /* Use lookup table for start-tile based on HighLightStyle direction */
2805  byte style_t = style * 2;
2806  assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
2807  h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t])));
2808  uint ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1])));
2809  h0 = max(h0, ht);
2810 
2811  /* Use lookup table for end-tile based on HighLightStyle direction
2812  * flip around side (lower/upper, left/right) based on distance */
2813  if (distance == 0) style_t = flip_style_direction[style] * 2;
2814  assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
2815  h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t])));
2816  ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1])));
2817  h1 = max(h1, ht);
2818  break;
2819  }
2820  }
2821 
2822  if (swap) Swap(h0, h1);
2823  return (int)(h1 - h0) * TILE_HEIGHT_STEP;
2824 }
2825 
2826 static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
2827 
2834 static void CheckUnderflow(int &test, int &other, int mult)
2835 {
2836  if (test >= 0) return;
2837 
2838  other += mult * test;
2839  test = 0;
2840 }
2841 
2849 static void CheckOverflow(int &test, int &other, int max, int mult)
2850 {
2851  if (test <= max) return;
2852 
2853  other += mult * (test - max);
2854  test = max;
2855 }
2856 
2858 static void CalcRaildirsDrawstyle(int x, int y, int method)
2859 {
2860  HighLightStyle b;
2861 
2862  int dx = _thd.selstart.x - (_thd.selend.x & ~TILE_UNIT_MASK);
2863  int dy = _thd.selstart.y - (_thd.selend.y & ~TILE_UNIT_MASK);
2864  uint w = abs(dx) + TILE_SIZE;
2865  uint h = abs(dy) + TILE_SIZE;
2866 
2867  if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) {
2868  /* We 'force' a selection direction; first four rail buttons. */
2869  method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS);
2870  int raw_dx = _thd.selstart.x - _thd.selend.x;
2871  int raw_dy = _thd.selstart.y - _thd.selend.y;
2872  switch (method) {
2873  case VPM_FIX_X:
2874  b = HT_LINE | HT_DIR_Y;
2875  x = _thd.selstart.x;
2876  break;
2877 
2878  case VPM_FIX_Y:
2879  b = HT_LINE | HT_DIR_X;
2880  y = _thd.selstart.y;
2881  break;
2882 
2883  case VPM_FIX_HORIZONTAL:
2884  if (dx == -dy) {
2885  /* We are on a straight horizontal line. Determine the 'rail'
2886  * to build based the sub tile location. */
2888  } else {
2889  /* We are not on a straight line. Determine the rail to build
2890  * based on whether we are above or below it. */
2891  b = dx + dy >= (int)TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL;
2892 
2893  /* Calculate where a horizontal line through the start point and
2894  * a vertical line from the selected end point intersect and
2895  * use that point as the end point. */
2896  int offset = (raw_dx - raw_dy) / 2;
2897  x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK);
2898  y = _thd.selstart.y + (offset & ~TILE_UNIT_MASK);
2899 
2900  /* 'Build' the last half rail tile if needed */
2901  if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) {
2902  if (dx + dy >= (int)TILE_SIZE) {
2903  x += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE;
2904  } else {
2905  y += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE;
2906  }
2907  }
2908 
2909  /* Make sure we do not overflow the map! */
2910  CheckUnderflow(x, y, 1);
2911  CheckUnderflow(y, x, 1);
2912  CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, 1);
2913  CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, 1);
2914  assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE));
2915  }
2916  break;
2917 
2918  case VPM_FIX_VERTICAL:
2919  if (dx == dy) {
2920  /* We are on a straight vertical line. Determine the 'rail'
2921  * to build based the sub tile location. */
2922  b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
2923  } else {
2924  /* We are not on a straight line. Determine the rail to build
2925  * based on whether we are left or right from it. */
2926  b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
2927 
2928  /* Calculate where a vertical line through the start point and
2929  * a horizontal line from the selected end point intersect and
2930  * use that point as the end point. */
2931  int offset = (raw_dx + raw_dy + (int)TILE_SIZE) / 2;
2932  x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK);
2933  y = _thd.selstart.y - (offset & ~TILE_UNIT_MASK);
2934 
2935  /* 'Build' the last half rail tile if needed */
2936  if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) {
2937  if (dx - dy < 0) {
2938  y += (dx > dy) ? (int)TILE_SIZE : -(int)TILE_SIZE;
2939  } else {
2940  x += (dx < dy) ? (int)TILE_SIZE : -(int)TILE_SIZE;
2941  }
2942  }
2943 
2944  /* Make sure we do not overflow the map! */
2945  CheckUnderflow(x, y, -1);
2946  CheckUnderflow(y, x, -1);
2947  CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, -1);
2948  CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, -1);
2949  assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE));
2950  }
2951  break;
2952 
2953  default:
2954  NOT_REACHED();
2955  }
2956  } else if (TileVirtXY(_thd.selstart.x, _thd.selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile
2957  if (method & VPM_RAILDIRS) {
2958  b = GetAutorailHT(x, y);
2959  } else { // rect for autosignals on one tile
2960  b = HT_RECT;
2961  }
2962  } else if (h == TILE_SIZE) { // Is this in X direction?
2963  if (dx == (int)TILE_SIZE) { // 2x1 special handling
2964  b = (Check2x1AutoRail(3)) | HT_LINE;
2965  } else if (dx == -(int)TILE_SIZE) {
2966  b = (Check2x1AutoRail(2)) | HT_LINE;
2967  } else {
2968  b = HT_LINE | HT_DIR_X;
2969  }
2970  y = _thd.selstart.y;
2971  } else if (w == TILE_SIZE) { // Or Y direction?
2972  if (dy == (int)TILE_SIZE) { // 2x1 special handling
2973  b = (Check2x1AutoRail(1)) | HT_LINE;
2974  } else if (dy == -(int)TILE_SIZE) { // 2x1 other direction
2975  b = (Check2x1AutoRail(0)) | HT_LINE;
2976  } else {
2977  b = HT_LINE | HT_DIR_Y;
2978  }
2979  x = _thd.selstart.x;
2980  } else if (w > h * 2) { // still count as x dir?
2981  b = HT_LINE | HT_DIR_X;
2982  y = _thd.selstart.y;
2983  } else if (h > w * 2) { // still count as y dir?
2984  b = HT_LINE | HT_DIR_Y;
2985  x = _thd.selstart.x;
2986  } else { // complicated direction
2987  int d = w - h;
2988  _thd.selend.x = _thd.selend.x & ~TILE_UNIT_MASK;
2989  _thd.selend.y = _thd.selend.y & ~TILE_UNIT_MASK;
2990 
2991  /* four cases. */
2992  if (x > _thd.selstart.x) {
2993  if (y > _thd.selstart.y) {
2994  /* south */
2995  if (d == 0) {
2996  b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
2997  } else if (d >= 0) {
2998  x = _thd.selstart.x + h;
2999  b = HT_LINE | HT_DIR_VL;
3000  } else {
3001  y = _thd.selstart.y + w;
3002  b = HT_LINE | HT_DIR_VR;
3003  }
3004  } else {
3005  /* west */
3006  if (d == 0) {
3008  } else if (d >= 0) {
3009  x = _thd.selstart.x + h;
3010  b = HT_LINE | HT_DIR_HL;
3011  } else {
3012  y = _thd.selstart.y - w;
3013  b = HT_LINE | HT_DIR_HU;
3014  }
3015  }
3016  } else {
3017  if (y > _thd.selstart.y) {
3018  /* east */
3019  if (d == 0) {
3021  } else if (d >= 0) {
3022  x = _thd.selstart.x - h;
3023  b = HT_LINE | HT_DIR_HU;
3024  } else {
3025  y = _thd.selstart.y + w;
3026  b = HT_LINE | HT_DIR_HL;
3027  }
3028  } else {
3029  /* north */
3030  if (d == 0) {
3031  b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3032  } else if (d >= 0) {
3033  x = _thd.selstart.x - h;
3034  b = HT_LINE | HT_DIR_VR;
3035  } else {
3036  y = _thd.selstart.y - w;
3037  b = HT_LINE | HT_DIR_VL;
3038  }
3039  }
3040  }
3041  }
3042 
3044  TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
3045  TileIndex t1 = TileVirtXY(x, y);
3046  uint distance = DistanceManhattan(t0, t1) + 1;
3047  byte index = 0;
3048  uint64 params[2];
3049 
3050  if (distance != 1) {
3051  int heightdiff = CalcHeightdiff(b, distance, t0, t1);
3052  /* If we are showing a tooltip for horizontal or vertical drags,
3053  * 2 tiles have a length of 1. To bias towards the ceiling we add
3054  * one before division. It feels more natural to count 3 lengths as 2 */
3055  if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) {
3056  distance = CeilDiv(distance, 2);
3057  }
3058 
3059  params[index++] = distance;
3060  if (heightdiff != 0) params[index++] = heightdiff;
3061  }
3062 
3063  ShowMeasurementTooltips(measure_strings_length[index], index, params);
3064  }
3065 
3066  _thd.selend.x = x;
3067  _thd.selend.y = y;
3068  _thd.next_drawstyle = b;
3069 }
3070 
3079 {
3080  int sx, sy;
3081  HighLightStyle style;
3082 
3083  if (x == -1) {
3084  _thd.selend.x = -1;
3085  return;
3086  }
3087 
3088  /* Special handling of drag in any (8-way) direction */
3089  if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) {
3090  _thd.selend.x = x;
3091  _thd.selend.y = y;
3092  CalcRaildirsDrawstyle(x, y, method);
3093  return;
3094  }
3095 
3096  /* Needed so level-land is placed correctly */
3097  if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_POINT) {
3098  x += TILE_SIZE / 2;
3099  y += TILE_SIZE / 2;
3100  }
3101 
3102  sx = _thd.selstart.x;
3103  sy = _thd.selstart.y;
3104 
3105  int limit = 0;
3106 
3107  switch (method) {
3108  case VPM_X_OR_Y: // drag in X or Y direction
3109  if (abs(sy - y) < abs(sx - x)) {
3110  y = sy;
3111  style = HT_DIR_X;
3112  } else {
3113  x = sx;
3114  style = HT_DIR_Y;
3115  }
3116  goto calc_heightdiff_single_direction;
3117 
3118  case VPM_X_LIMITED: // Drag in X direction (limited size).
3119  limit = (_thd.sizelimit - 1) * TILE_SIZE;
3120  FALLTHROUGH;
3121 
3122  case VPM_FIX_X: // drag in Y direction
3123  x = sx;
3124  style = HT_DIR_Y;
3125  goto calc_heightdiff_single_direction;
3126 
3127  case VPM_Y_LIMITED: // Drag in Y direction (limited size).
3128  limit = (_thd.sizelimit - 1) * TILE_SIZE;
3129  FALLTHROUGH;
3130 
3131  case VPM_FIX_Y: // drag in X direction
3132  y = sy;
3133  style = HT_DIR_X;
3134 
3135 calc_heightdiff_single_direction:;
3136  if (limit > 0) {
3137  x = sx + Clamp(x - sx, -limit, limit);
3138  y = sy + Clamp(y - sy, -limit, limit);
3139  }
3141  TileIndex t0 = TileVirtXY(sx, sy);
3142  TileIndex t1 = TileVirtXY(x, y);
3143  uint distance = DistanceManhattan(t0, t1) + 1;
3144  byte index = 0;
3145  uint64 params[2];
3146 
3147  if (distance != 1) {
3148  /* With current code passing a HT_LINE style to calculate the height
3149  * difference is enough. However if/when a point-tool is created
3150  * with this method, function should be called with new_style (below)
3151  * instead of HT_LINE | style case HT_POINT is handled specially
3152  * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
3153  int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1);
3154 
3155  params[index++] = distance;
3156  if (heightdiff != 0) params[index++] = heightdiff;
3157  }
3158 
3159  ShowMeasurementTooltips(measure_strings_length[index], index, params);
3160  }
3161  break;
3162 
3163  case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area.
3164  limit = (_thd.sizelimit - 1) * TILE_SIZE;
3165  x = sx + Clamp(x - sx, -limit, limit);
3166  y = sy + Clamp(y - sy, -limit, limit);
3167  FALLTHROUGH;
3168 
3169  case VPM_X_AND_Y: // drag an X by Y area
3171  static const StringID measure_strings_area[] = {
3172  STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
3173  };
3174 
3175  TileIndex t0 = TileVirtXY(sx, sy);
3176  TileIndex t1 = TileVirtXY(x, y);
3177  uint dx = Delta(TileX(t0), TileX(t1)) + 1;
3178  uint dy = Delta(TileY(t0), TileY(t1)) + 1;
3179  byte index = 0;
3180  uint64 params[3];
3181 
3182  /* If dragging an area (eg dynamite tool) and it is actually a single
3183  * row/column, change the type to 'line' to get proper calculation for height */
3184  style = (HighLightStyle)_thd.next_drawstyle;
3185  if (_thd.IsDraggingDiagonal()) {
3186  /* Determine the "area" of the diagonal dragged selection.
3187  * We assume the area is the number of tiles along the X
3188  * edge and the number of tiles along the Y edge. However,
3189  * multiplying these two numbers does not give the exact
3190  * number of tiles; basically we are counting the black
3191  * squares on a chess board and ignore the white ones to
3192  * make the tile counts at the edges match up. There is no
3193  * other way to make a proper count though.
3194  *
3195  * First convert to the rotated coordinate system. */
3196  int dist_x = TileX(t0) - TileX(t1);
3197  int dist_y = TileY(t0) - TileY(t1);
3198  int a_max = dist_x + dist_y;
3199  int b_max = dist_y - dist_x;
3200 
3201  /* Now determine the size along the edge, but due to the
3202  * chess board principle this counts double. */
3203  a_max = abs(a_max + (a_max > 0 ? 2 : -2)) / 2;
3204  b_max = abs(b_max + (b_max > 0 ? 2 : -2)) / 2;
3205 
3206  /* We get a 1x1 on normal 2x1 rectangles, due to it being
3207  * a seen as two sides. As the result for actual building
3208  * will be the same as non-diagonal dragging revert to that
3209  * behaviour to give it a more normally looking size. */
3210  if (a_max != 1 || b_max != 1) {
3211  dx = a_max;
3212  dy = b_max;
3213  }
3214  } else if (style & HT_RECT) {
3215  if (dx == 1) {
3216  style = HT_LINE | HT_DIR_Y;
3217  } else if (dy == 1) {
3218  style = HT_LINE | HT_DIR_X;
3219  }
3220  }
3221 
3222  if (dx != 1 || dy != 1) {
3223  int heightdiff = CalcHeightdiff(style, 0, t0, t1);
3224 
3225  params[index++] = dx - (style & HT_POINT ? 1 : 0);
3226  params[index++] = dy - (style & HT_POINT ? 1 : 0);
3227  if (heightdiff != 0) params[index++] = heightdiff;
3228  }
3229 
3230  ShowMeasurementTooltips(measure_strings_area[index], index, params);
3231  }
3232  break;
3233 
3234  default: NOT_REACHED();
3235  }
3236 
3237  _thd.selend.x = x;
3238  _thd.selend.y = y;
3239 }
3240 
3246 {
3248 
3249  /* stop drag mode if the window has been closed */
3250  Window *w = _thd.GetCallbackWnd();
3251  if (w == nullptr) {
3253  return ES_HANDLED;
3254  }
3255 
3256  /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
3257  if (_left_button_down) {
3258  w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
3259  return ES_HANDLED;
3260  }
3261 
3262  /* mouse button released..
3263  * keep the selected tool, but reset it to the original mode. */
3265  HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
3266  if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) {
3267  _thd.place_mode = HT_RECT | others;
3268  } else if (_thd.select_method & VPM_SIGNALDIRS) {
3269  _thd.place_mode = HT_RECT | others;
3270  } else if (_thd.select_method & VPM_RAILDIRS) {
3271  _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others);
3272  } else {
3273  _thd.place_mode = HT_POINT | others;
3274  }
3275  SetTileSelectSize(1, 1);
3276 
3277  HideMeasurementTooltips();
3278  w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
3279 
3280  return ES_HANDLED;
3281 }
3282 
3291 {
3292  SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number);
3293 }
3294 
3295 #include "table/animcursors.h"
3296 
3305 void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
3306 {
3307  if (_thd.window_class != WC_INVALID) {
3308  /* Undo clicking on button and drag & drop */
3309  Window *w = _thd.GetCallbackWnd();
3310  /* Call the abort function, but set the window class to something
3311  * that will never be used to avoid infinite loops. Setting it to
3312  * the 'next' window class must not be done because recursion into
3313  * this function might in some cases reset the newly set object to
3314  * place or not properly reset the original selection. */
3315  _thd.window_class = WC_INVALID;
3316  if (w != nullptr) {
3317  w->OnPlaceObjectAbort();
3318  HideMeasurementTooltips();
3319  }
3320  }
3321 
3322  /* Mark the old selection dirty, in case the selection shape or colour changes */
3324 
3325  SetTileSelectSize(1, 1);
3326 
3327  _thd.make_square_red = false;
3328 
3329  if (mode == HT_DRAG) { // HT_DRAG is for dragdropping trains in the depot window
3330  mode = HT_NONE;
3332  } else {
3334  }
3335 
3336  _thd.place_mode = mode;
3337  _thd.window_class = window_class;
3338  _thd.window_number = window_num;
3339 
3340  if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode
3341  VpStartPreSizing();
3342  }
3343 
3344  if ((icon & ANIMCURSOR_FLAG) != 0) {
3345  SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]);
3346  } else {
3347  SetMouseCursor(icon, pal);
3348  }
3349 
3350 }
3351 
3354 {
3356 }
3357 
3358 Point GetViewportStationMiddle(const ViewPort *vp, const Station *st)
3359 {
3360  int x = TileX(st->xy) * TILE_SIZE;
3361  int y = TileY(st->xy) * TILE_SIZE;
3362  int z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1));
3363 
3364  Point p = RemapCoords(x, y, z);
3365  p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left;
3366  p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top;
3367  return p;
3368 }
3369 
3374 };
3375 
3378 #ifdef WITH_SSE
3379  { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
3380 #endif
3382 };
3383 
3386 {
3387  for (uint i = 0; i < lengthof(_vp_sprite_sorters); i++) {
3388  if (_vp_sprite_sorters[i].fct_checker()) {
3389  _vp_sprite_sorter = _vp_sprite_sorters[i].fct_sorter;
3390  break;
3391  }
3392  }
3393  assert(_vp_sprite_sorter != nullptr);
3394 }
3395 
3405 CommandCost CmdScrollViewport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
3406 {
3407  if (_current_company != OWNER_DEITY) return CMD_ERROR;
3409  switch (target) {
3410  case VST_EVERYONE:
3411  break;
3412  case VST_COMPANY:
3413  if (_local_company != (CompanyID)p2) return CommandCost();
3414  break;
3415  case VST_CLIENT:
3416  if (_network_own_client_id != (ClientID)p2) return CommandCost();
3417  break;
3418  default:
3419  return CMD_ERROR;
3420  }
3421 
3422  if (flags & DC_EXEC) {
3424  ScrollMainWindowToTile(tile);
3425  }
3426  return CommandCost();
3427 }
3428 
3429 static void MarkCatchmentTilesDirty()
3430 {
3431  if (_viewport_highlight_town != nullptr) {
3433  return;
3434  }
3435  if (_viewport_highlight_station != nullptr) {
3438  _viewport_highlight_station = nullptr;
3439  } else {
3441  for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
3442  MarkTileDirtyByTile(tile);
3443  }
3444  }
3445  }
3446 }
3447 
3454 void SetViewportCatchmentStation(const Station *st, bool sel)
3455 {
3458  if (sel && _viewport_highlight_station != st) {
3459  MarkCatchmentTilesDirty();
3461  _viewport_highlight_town = nullptr;
3462  MarkCatchmentTilesDirty();
3463  } else if (!sel && _viewport_highlight_station == st) {
3464  MarkCatchmentTilesDirty();
3465  _viewport_highlight_station = nullptr;
3466  }
3468 }
3469 
3476 void SetViewportCatchmentTown(const Town *t, bool sel)
3477 {
3480  if (sel && _viewport_highlight_town != t) {
3481  _viewport_highlight_station = nullptr;
3484  } else if (!sel && _viewport_highlight_town == t) {
3485  _viewport_highlight_town = nullptr;
3487  }
3489 }
EventState
State of handling an event.
Definition: window_type.h:711
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition: vehicle.cpp:1107
bool DoZoomInOutWindow(ZoomStateChange how, Window *w)
Zooms a viewport in a window in or out.
Definition: main_gui.cpp:136
Functions related to OTTD&#39;s strings.
static TileType GetTileType(TileIndex tile)
Get the tiletype of a given tile.
Definition: tile_map.h:96
ViewportDragDropSelectionProcess
Drag and drop selection process, or, what to do with an area of land when you&#39;ve selected it...
Y direction.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
bool measure_tooltip
show a permanent tooltip when dragging tools
Definition: settings_type.h:98
static bool IsHalftileSlope(Slope s)
Checks for non-continuous slope on halftile foundations.
Definition: slope_func.h:47
Iterator to iterate over all tiles belonging to a bitmaptilearea.
Definition: bitmap_type.h:107
static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
Draws autorail highlights.
Definition: viewport.cpp:951
static const PaletteID PALETTE_SEL_TILE_RED
makes a square red. is used when removing rails or other stuff
Definition: sprites.h:1552
static void Swap(T &a, T &b)
Type safe swap operation.
Definition: math_func.hpp:275
the north corner of the tile is raised
Definition: slope_type.h:53
Corner
Enumeration of tile corners.
Definition: slope_type.h:22
uint32 PaletteID
The number of the palette.
Definition: gfx_type.h:18
static const uint TILE_PIXELS
Pixel distance between tile columns/rows in #ZOOM_LVL_BASE.
Definition: tile_type.h:15
WindowNumber window_number
The WindowNumber of the window that is responsible for the selection mode.
static uint MapSizeX()
Get the size of the map along the X.
Definition: map_func.h:72
static const int MAX_TILE_EXTENT_RIGHT
Maximum right extent of tile relative to north corner.
Definition: viewport.cpp:107
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:79
bool IsDraggingDiagonal()
Is the user dragging a &#39;diagonal rectangle&#39;?
Definition: viewport.cpp:2460
int32 zmin
minimal world Z coordinate of bounding box
Definition of stuff that is very close to a company, like the company struct itself.
int32 zmax
maximal world Z coordinate of bounding box
static const PaletteID PALETTE_TO_TRANSPARENT
This sets the sprite to transparent.
Definition: sprites.h:1584
Window * FindWindowFromPt(int x, int y)
Do a search for a window at specific coordinates.
Definition: window.cpp:1878
void ShowWaypointWindow(const Waypoint *wp)
Show the window for the given waypoint.
int virtual_left
Virtual left coordinate.
Definition: viewport_type.h:28
int32 top
minimal screen Y coordinate of sprite (= y + sprite->y_offs), reference point for child sprites ...
void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom)
Initialize viewport of the window for use.
Definition: viewport.cpp:220
static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
Check if the direction of start and end tile should be swapped based on the dragging-style.
Definition: viewport.cpp:2720
Data about how and where to blit pixels.
Definition: gfx_type.h:154
static uint MapSizeY()
Get the size of the map along the Y.
Definition: map_func.h:82
Horizontally center the text.
Definition: gfx_func.h:95
Tile information, used while rendering the tile.
Definition: tile_cmd.h:42
Sprite combining will start with the next unclipped sprite.
Definition: viewport.cpp:151
SpriteCombineMode
Mode of "sprite combining".
Definition: viewport.cpp:149
void SetWidgetDisabledState(byte widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:392
Point pos
Location, in tile "units", of the northern tile of the selected area.
No special mouse mode.
Definition: window_gui.h:905
Point pos
logical mouse position
Definition: gfx_type.h:117
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3215
area of land of limited size
void(* VpSpriteSorter)(ParentSpriteToSortVector *psd)
Type for the actual viewport sprite sorter.
The mask to for the main sprite.
Definition: sprites.h:1537
static const PaletteID PALETTE_TILE_RED_PULSATING
pulsating red tile drawn if you try to build a wrong tunnel or raise/lower land where it is not possi...
Definition: sprites.h:1551
uint32 GetCompanyMask()
Get a bitmask of the currently shown companies.
Definition: linkgraph_gui.h:68
signs
Definition: transparency.h:23
byte _display_opt
What do we want to draw/do?
EconomySettings economy
settings to change the economy
int left
x position of left edge of the window
Definition: window_gui.h:317
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition: window.cpp:80
bool VehicleClicked(const Vehicle *v)
Dispatch a "vehicle selected" event if any window waits for it.
Zoom out (get helicopter view).
Definition: viewport_type.h:82
static int GetTilePixelZ(TileIndex tile)
Get bottom height of the tile.
Definition: tile_map.h:294
int height
Screen height of the viewport.
Definition: viewport_type.h:26
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:291
int32 y
screen Y coordinate of sprite
Definition: viewport.cpp:125
Declarations for accessing the k-d tree of towns.
Display waypoint names.
Definition: openttd.h:46
void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
Update the status of the zoom-buttons according to the zoom-level of the viewport.
Definition: viewport.cpp:476
static Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap...
Definition: landscape.h:82
vertical right
VpSorterChecker fct_checker
The check function.
Definition: viewport.cpp:3372
TileType
The different types of tiles.
Definition: tile_type.h:40
void SetWidgetDirty(byte widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:597
static int UnScaleByZoomLower(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_NORMAL)
Definition: zoom_func.h:56
int next
next child to draw (-1 at the end)
Definition: viewport.cpp:134
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
Dragging an object.
Definition: window_gui.h:906
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1130
The passed event is not handled.
Definition: window_type.h:713
X direction.
Display station names.
Definition: openttd.h:42
byte _colour_gradient[COLOUR_END][8]
All 16 colour gradients 8 colours per gradient from darkest (0) to lightest (7)
Definition: gfx.cpp:52
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
Definition: viewport.cpp:2423
static int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_NORMAL) When shifting right...
Definition: zoom_func.h:34
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:23
drag only in X axis
Definition: viewport_type.h:98
Data structure describing a sprite.
Definition: spritecache.h:16
Slope tileh
Slope of the tile.
Definition: tile_cmd.h:45
Sprite combining is active. AddSortableSpriteToDraw outputs child sprites.
Definition: viewport.cpp:152
Types for recording game performance data.
Drag only in X axis with limited size.
static const AnimCursor *const _animcursors[]
This is an array of pointers to all the animated cursor definitions we have above.
Definition: animcursors.h:85
similar to VMP_RAILDIRS, but with different cursor
void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip)
Shows a tooltip.
Definition: misc_gui.cpp:764
Slope GetTilePixelSlopeOutsideMap(int x, int y, int *h)
Return the slope of a given tile, also for tiles outside the map (virtual "black" tiles)...
Definition: tile_map.cpp:82
static void CheckUnderflow(int &test, int &other, int mult)
Check for underflowing the map.
Definition: viewport.cpp:2834
Point size
Size, in tile "units", of the white/red selection area.
virtual void SetPixel(void *video, int x, int y, uint8 colour)=0
Draw a pixel with a given colour on the video-buffer.
End for iteration.
Definition: zoom_type.h:28
bool population_in_label
show the population of a town in his label?
drag only in Y axis
Definition: viewport_type.h:99
Drag only in Y axis with limited size.
Functions related to vehicles.
static const int MAX_TILE_EXTENT_LEFT
Maximum left extent of tile relative to north corner.
Definition: viewport.cpp:106
Zoomed 16 times out.
Definition: zoom_type.h:26
int virtual_height
height << zoom
Definition: viewport_type.h:31
Point new_size
New value for size; used to determine whether to redraw the selection.
static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub=nullptr, int extra_offs_x=0, int extra_offs_y=0)
Schedules a tile sprite for drawing.
Definition: viewport.cpp:497
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:205
Vehicle data structure.
Definition: vehicle_base.h:210
Point new_pos
New value for pos; used to determine whether to redraw the selection.
int top
y position of top edge of the window
Definition: window_gui.h:318
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
Display town names.
Definition: openttd.h:41
static int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_NORMAL) When shifting right...
Definition: zoom_func.h:22
Tindex index
Index of this pool item.
Definition: pool_type.hpp:189
int foundation[FOUNDATION_PART_END]
Foundation sprites (index into parent_sprites_to_draw).
Definition: viewport.cpp:174
static const int DRAW_STRING_BUFFER
Size of the buffer used for drawing strings.
Definition: gfx_func.h:83
static bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition: slope_func.h:36
bool show_zone
NOSAVE: mark town to show the local authority zone in the viewports.
Definition: town.h:102
Display signs, station names and waypoint names of opponent companies. Buoys and oilrig-stations are ...
Definition: openttd.h:47
Zoom in (get more detailed view).
Definition: viewport_type.h:81
Representation of a waypoint.
Definition: waypoint_base.h:16
void SetViewportCatchmentTown(const Town *t, bool sel)
Select or deselect town for coverage area highlight.
Definition: viewport.cpp:3476
Maximum number of sprites that can be loaded at a given time.
Definition: sprites.h:1536
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:48
void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, Outputter outputter) const
Find all items contained within the given rectangle.
Definition: kdtree.hpp:462
Number of zoom levels.
Definition: zoom_type.h:30
All players.
SpriteCombineMode combine_sprites
Current mode of "sprite combining".
Definition: viewport.cpp:172
T FindNearest(CoordT x, CoordT y) const
Find the element closest to given coordinate, in Manhattan distance.
Definition: kdtree.hpp:444
Second part (halftile foundation)
Definition: viewport.cpp:141
static Corner GetHalftileSlopeCorner(Slope s)
Returns the leveled halftile of a halftile slope.
Definition: slope_func.h:148
byte dist_local_authority
distance for town local authority, default 20
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
WindowClass
Window classes.
Definition: window_type.h:37
ParentSpriteToSortVector parent_sprites_to_sort
Parent sprite pointer array used for sorting.
Definition: viewport.cpp:167
static int DivAwayFromZero(int a, uint b)
Computes (a / b) rounded away from zero.
Definition: math_func.hpp:353
virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
The user is dragging over the map when the tile highlight mode has been set.
Definition: window_gui.h:773
Invalid window.
Definition: window_type.h:694
virtual void OnPlaceObjectAbort()
The user cancelled a tile highlight mode that has been set.
Definition: window_gui.h:763
Common return value for all commands.
Definition: command_type.h:23
How all blitters should look like.
Definition: base.hpp:28
ClientID
&#39;Unique&#39; identifier to be given to clients
Definition: network_type.h:39
static Slope SlopeWithOneCornerRaised(Corner corner)
Returns the slope with a specific corner raised.
Definition: slope_func.h:99
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition: vehicle_type.h:55
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition: viewport.cpp:757
Functions related to signs.
void UpdatePosition(int center, int top, StringID str, StringID str_small=STR_NULL)
Update the position of the viewport sign.
Definition: viewport.cpp:1442
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
vertical left
Presizing mode (docks, tunnels).
Definition: window_gui.h:908
Functions related to the vehicle&#39;s GUIs.
Left margin.
Definition: viewport_type.h:39
int z
Height.
Definition: tile_cmd.h:47
Window * GetCallbackWnd()
Get the window that started the current highlighting.
Definition: viewport.cpp:2469
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:13
FoundationPart foundation_part
Currently active foundation for ground sprite drawing.
Definition: viewport.cpp:175
void MarkDirty(ZoomLevel maxzoom=ZOOM_LVL_MAX) const
Mark the sign dirty in all viewports.
Definition: viewport.cpp:1469
int32 x
screen X coordinate of sprite
Definition: viewport.cpp:124
Highlight/sprite information for autorail.
CommandCost CmdScrollViewport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Scroll players main viewport.
Definition: viewport.cpp:3405
HighLightStyle place_mode
Method which is used to place the selection.
Functions, definitions and such used only by the GUI.
TileIndex GetNorthernBridgeEnd(TileIndex t)
Finds the northern end of a bridge starting at a middle tile.
Definition: bridge_map.cpp:39
static Waypoint * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
ViewportScrollTarget
Target of the viewport scrolling GS method.
static bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Definition: math_func.hpp:248
Display signs.
Definition: openttd.h:43
Point foundation_offset[FOUNDATION_PART_END]
Pixel offset for ground sprites on the foundations.
Definition: viewport.cpp:177
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:175
Right margin.
Definition: viewport_type.h:40
Functions related to (drawing on) viewports.
void Draw(const DrawPixelInfo *dpi)
Draw the linkgraph overlay or some part of it, in the area given.
Declaration of linkgraph overlay GUI.
Data structure for an opened window.
Definition: window_gui.h:276
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:35
Data structure storing rendering information.
Definition: viewport.cpp:161
static bool IsValidTile(TileIndex tile)
Checks if a tile is valid.
Definition: tile_map.h:161
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition: viewport.cpp:767
static bool IsInsideMM(const T x, const size_t min, const size_t max)
Checks if a value is in an interval.
Definition: math_func.hpp:264
static bool IsBridgeAbove(TileIndex t)
checks if a bridge is set above the ground of this tile
Definition: bridge_map.h:45
Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y, bool clamp_to_map)
Translate screen coordinate in a viewport to underlying tile coordinate.
Definition: viewport.cpp:417
dragging items in the depot windows
Begin for iteration.
Definition: zoom_type.h:21
static HighLightStyle GetAutorailHT(int x, int y)
returns the best autorail highlight type from map coordinates
Definition: viewport.cpp:2440
Point selstart
The location where the dragging started.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold...
Definition: town_cmd.cpp:3488
Main window; Window numbers:
Definition: window_type.h:44
byte sizelimit
Whether the selection is limited in length, and what the maximum length is.
First part (normal foundation or no foundation)
Definition: viewport.cpp:140
Point selend
The location where the drag currently ends.
uint x
X position of the tile in unit coordinates.
Definition: tile_cmd.h:43
The tile has no ownership.
Definition: company_type.h:25
TileIndex xy
town center tile
Definition: town.h:54
Every AddSortableSpriteToDraw start its own bounding box.
Definition: viewport.cpp:150
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
int16 y_offs
Number of pixels to shift the sprite downwards.
Definition: spritecache.h:20
TileIndex tile
Tile index.
Definition: tile_cmd.h:46
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:289
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:173
int32 ymin
minimal world Y coordinate of bounding box
int32 first_child
the first child to draw.
masks the drag-direction
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows)...
Definition: viewport.cpp:3353
static T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition: math_func.hpp:95
const Town * _viewport_highlight_town
Currently selected town for coverage area highlight.
Definition: viewport.cpp:989
int32 top
The top of the sign.
Definition: viewport_type.h:48
void SetRedErrorSquare(TileIndex tile)
Set a tile to display a red error square.
Definition: viewport.cpp:2405
size_t Count() const
Get number of elements stored in tree.
Definition: kdtree.hpp:433
Tooltip window; Window numbers:
Definition: window_type.h:109
void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
highlighting tiles while only going over them with the mouse
Definition: viewport.cpp:2605
void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
Definition: viewport.cpp:3305
int32 x
screen X coordinate of sprite
void MarkAllViewportsDirty(int left, int top, int right, int bottom)
Mark all viewports that display an area as dirty (in need of repaint).
Definition: viewport.cpp:1905
Point offs
Offset, in tile "units", for the blue coverage area from the selected area&#39;s northern tile...
static TownID GetTownIndex(TileIndex t)
Get the index of which town this house/street is attached to.
Definition: town_map.h:22
uint32 VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
ViewportPlaceMethod
Viewport place method (type of highlighted area and placed objects)
Definition: viewport_type.h:96
end marker
void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
Draw a sprite in a viewport.
Definition: gfx.cpp:808
DoCommandFlag
List of flags for a command.
Definition: command_type.h:342
bool _left_button_down
Is left mouse button pressed?
Definition: gfx.cpp:38
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:176
drag in X or Y direction
Definition: viewport_type.h:97
ClientID _network_own_client_id
Our client identifier.
Definition: network.cpp:59
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:78
static const CursorID ANIMCURSOR_FLAG
Flag for saying a cursor sprite is an animated cursor.
Definition: sprites.h:1484
static void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond=TCC_NONE)
Displays the measurement tooltips when selecting multiple tiles.
Definition: viewport.cpp:2593
static ViewportSSCSS _vp_sprite_sorters[]
List of sorters ordered from best to worst.
Definition: viewport.cpp:3377
static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
Make sure we don&#39;t draw a too big area at a time.
Definition: viewport.cpp:1729
Definition of base types and functions in a cross-platform compatible way.
Location information about a sign as seen on the viewport.
Definition: viewport_type.h:46
static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
Draws the bounding boxes of all ParentSprites.
Definition: viewport.cpp:1581
static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
Sort parent sprites pointer array.
Definition: viewport.cpp:1506
A number of safeguards to prevent using unsafe methods.
StationList stations_near
NOSAVE: List of nearby stations.
Definition: town.h:89
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:245
static void SetSelectionTilesDirty()
Marks the selected tiles as dirty.
Definition: viewport.cpp:1955
Base of waypoints.
static void CheckOverflow(int &test, int &other, int max, int mult)
Check for overflowing the map.
Definition: viewport.cpp:2849
rectangle (stations, depots, ...)
uint y
Y position of the tile in unit coordinates.
Definition: tile_cmd.h:44
int32 y
screen Y coordinate of sprite
static uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition: math_func.hpp:314
ViewportPlaceMethod select_method
The method which governs how tiles are selected.
static void HighlightTownLocalAuthorityTiles(const TileInfo *ti)
Highlights tiles insede local authority of selected towns.
Definition: viewport.cpp:1044
void StartStopVehicle(const Vehicle *v, bool texteffect)
Executes CMD_START_STOP_VEHICLE for given vehicle.
Data structure for a window viewport.
Definition: window_gui.h:256
All zoomlevels below or equal to this, will result in details on the screen, like road-work...
Definition: zoom_type.h:43
static Slope GetTilePixelSlope(TileIndex tile, int *h)
Return the slope of a given tile.
Definition: tile_map.h:280
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in #ZOOM_LVL_BASE.
Definition: tile_type.h:16
int32 scrollpos_x
Currently shown x coordinate (virtual screen coordinate of topleft corner of the viewport).
Definition: window_gui.h:258
Single player.
int32 xmin
minimal world X coordinate of bounding box
HighLightStyle drawstyle
Lower bits 0-3 are reserved for detailed highlight information.
uint16 width_normal
The width when not zoomed out (normal font)
Definition: viewport_type.h:49
void SetViewportCatchmentStation(const Station *st, bool sel)
Select or deselect station for coverage area highlight.
Definition: viewport.cpp:3454
static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal)
Draws a selection rectangle on a tile.
Definition: viewport.cpp:891
Map accessor functions for bridges.
bool IsInsideRotatedRectangle(int x, int y)
Checks whether a point is inside the selected a diagonal rectangle given by _thd.size and _thd...
Definition: viewport.cpp:794
static Slope SlopeWithThreeCornersRaised(Corner corner)
Returns the slope with all except one corner raised.
Definition: slope_func.h:206
ZoomLevel zoom_max
maximum zoom out level
int virtual_width
width << zoom
Definition: viewport_type.h:30
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:1938
static const PaletteID PALETTE_SEL_TILE_BLUE
This draws a blueish square (catchment areas for example)
Definition: sprites.h:1553
Sizing mode.
Definition: window_gui.h:907
Station view; Window numbers:
Definition: window_type.h:338
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:498
void ShowVehicleViewWindow(const Vehicle *v)
Shows the vehicle view window of the given vehicle.
static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
Calculates height difference between one tile and another.
Definition: viewport.cpp:2754
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:271
void SetDirtyBlocks(int left, int top, int right, int bottom)
This function extends the internal _invalid_rect rectangle as it now contains the rectangle defined b...
Definition: gfx.cpp:1419
bool smooth_scroll
smooth scroll viewports
Definition: settings_type.h:97
autorail (one piece), lower bits: direction
static int GetViewportY(Point tile)
Returns the y coordinate in the viewport coordinate system where the given tile is painted...
Definition: viewport.cpp:1159
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition: factory.hpp:145
VehicleID follow_vehicle
VehicleID to follow if following a vehicle, INVALID_VEHICLE otherwise.
Definition: window_gui.h:257
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:40
static void ClampViewportToMap(const ViewPort *vp, int *scroll_x, int *scroll_y)
Ensure that a given viewport has a valid scroll position.
Definition: viewport.cpp:1796
static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub)
Adds a child sprite to a parent sprite.
Definition: viewport.cpp:619
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
Definition: viewport.cpp:2385
Also allow &#39;diagonal rectangles&#39;. Only usable in combination with HT_RECT or HT_POINT.
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
Definition: viewport.cpp:3290
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Definition: vehicle_base.h:592
Point new_outersize
New value for outersize; used to determine whether to redraw the selection.
drag only in horizontal direction
void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
Draws the projection of a parallelepiped.
Definition: gfx.cpp:276
ViewPort * IsPtInWindowViewport(const Window *w, int x, int y)
Is a xy position inside the viewport of the window?
Definition: viewport.cpp:393
int32 dest_scrollpos_y
Current destination y coordinate to display (virtual screen coordinate of topleft corner of the viewp...
Definition: window_gui.h:261
const SubSprite * sub
only draw a rectangular part of the sprite
Definition: viewport.cpp:131
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition: viewport.cpp:659
static Slope RemoveHalftileSlope(Slope s)
Removes a halftile slope from a slope.
Definition: slope_func.h:60
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
bool make_square_red
Whether to give a tile a red selection.
uint16 height
Height of the sprite.
Definition: spritecache.h:17
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:137
static const int MAX_TILE_EXTENT_TOP
Maximum top extent of tile relative to north corner (not considering bridges).
Definition: viewport.cpp:108
The most basic (normal) sprite.
Definition: gfx_type.h:297
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:984
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
point (lower land, raise land, level land, ...)
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:700
static HighLightStyle Check2x1AutoRail(int mode)
returns information about the 2x1 piece to be build.
Definition: viewport.cpp:2676
int32 center
The center position of the sign.
Definition: viewport_type.h:47
static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
Marks a viewport as dirty for repaint if it displays (a part of) the area the needs to be repainted...
Definition: viewport.cpp:1869
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:17
const SubSprite * sub
only draw a rectangular part of the sprite
ViewportDragDropSelectionProcess select_proc
The procedure that has to be called when the selection is done.
void SetMouseCursor(CursorID sprite, PaletteID pal)
Assign a single non-animated sprite to the cursor.
Definition: gfx.cpp:1618
Mask for the tile drag-type modes.
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition: viewport.cpp:2483
static uint ScaleByMapSize1D(uint n)
Scales the given value by the maps circumference, where the given value is for a 256 by 256 map...
Definition: map_func.h:136
A pair-construct of a TileIndexDiff.
Definition: map_type.h:57
int * last_foundation_child[FOUNDATION_PART_END]
Tail of ChildSprite list of the foundations. (index into child_screen_sprites_to_draw) ...
Definition: viewport.cpp:176
int left
Screen coordinate left edge of the viewport.
Definition: viewport_type.h:23
static const int TILE_HEIGHT_STEP
One Z unit tile height difference is displayed as 50m.
Definition: viewport_func.h:19
void DrawViewport() const
Draw the viewport of this window.
Definition: viewport.cpp:1771
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1162
static TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between to tiles from a TileIndexDiffC struct.
Definition: map_func.h:230
execute the given command
Definition: command_type.h:344
static bool IsInRangeInclusive(int begin, int end, int check)
Check if the parameter "check" is inside the interval between begin and end, including both begin and...
Definition: viewport.cpp:782
void SetAnimatedMouseCursor(const AnimCursor *table)
Assign an animation to the cursor.
Definition: gfx.cpp:1631
uint16 width
Width of the sprite.
Definition: spritecache.h:18
Functions related to companies.
default
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:28
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:194
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
int32 dest_scrollpos_x
Current destination x coordinate to display (virtual screen coordinate of topleft corner of the viewp...
Definition: window_gui.h:260
area of land in X and Y directions
static bool ViewportSortParentSpritesChecker()
This fallback sprite checker always exists.
Definition: viewport.cpp:1500
Bottom margin.
Definition: viewport_type.h:42
static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
Adds a child sprite to the active foundation.
Definition: viewport.cpp:523
Parent sprite that should be drawn.
static uint TilePixelHeightOutsideMap(int x, int y)
Returns the height of a tile in pixels, also for tiles outside the map (virtual "black" tiles)...
Definition: tile_map.h:84
GUISettings gui
settings related to the GUI
SpriteID image
sprite to draw
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:340
Invisible tiles at the SW and SE border.
Definition: tile_type.h:48
Base class for all vehicles.
void Build(It begin, It end)
Clear and rebuild the tree from a new sequence of elements,.
Definition: kdtree.hpp:365
Data structure for viewport, display of a part of the world.
Definition: viewport_type.h:22
static void DrawTileSelection(const TileInfo *ti)
Checks if the specified tile is selected and if so draws selection using correct selectionstyle.
Definition: viewport.cpp:1078
static void ViewportAddLandscape()
Add the landscape to the viewport, i.e.
Definition: viewport.cpp:1168
Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition: landscape.cpp:103
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:17
Time spent drawing world viewports in GUI.
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:78
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1587
Window * z_front
The window in front of us in z-order.
Definition: window_gui.h:338
static const byte _string_colourmap[17]
Colour mapping for TextColour.
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:157
bool diagonal
Whether the dragged area is a 45 degrees rotated rectangle.
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition: pool_type.hpp:321
All players in specific company.
void HandleClickOnSign(const Sign *si)
Handle clicking on a sign.
Definition: signs_gui.cpp:556
Helper class for getting the best sprite sorter.
Definition: viewport.cpp:3371
static int GetBridgePixelHeight(TileIndex tile)
Get the height (&#39;z&#39;) of a bridge in pixels.
Definition: bridge_map.h:84
bool(* VpSorterChecker)()
Type for method for checking whether a viewport sprite sorter exists.
TileIndex redsq
The tile that has to get a red selection.
static const int MAX_TILE_EXTENT_BOTTOM
Maximum bottom extent of tile relative to north corner (worst case: SLOPE_STEEP_N).
Definition: viewport.cpp:109
int32 ymax
maximal world Y coordinate of bounding box
Top margin.
Definition: viewport_type.h:41
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:215
int32 xmax
maximal world X coordinate of bounding box
when a sprite is to be displayed transparently, this bit needs to be set.
Definition: sprites.h:1526
static T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:81
const Station * _viewport_highlight_station
Currently selected station for coverage area highlight.
Definition: viewport.cpp:988
void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method)
Selects tiles while dragging.
Definition: viewport.cpp:3078
TileIndex xy
Base tile of the station.
void Reset()
Reset tile highlighting.
Definition: viewport.cpp:2448
static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part)
Draws sprites between ground sprite and everything above.
Definition: viewport.cpp:873
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
Functions related to zooming.
static Point InverseRemapCoords(int x, int y)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition: landscape.h:112
Slope
Enumeration for the slope-type.
Definition: slope_type.h:48
Town view; Window numbers:
Definition: window_type.h:326
A tile of a station.
Definition: tile_type.h:46
Neither foundation nor groundsprite drawn yet.
Definition: viewport.cpp:139
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition: landscape.cpp:60
BitmapTileArea catchment_tiles
NOSAVE: Set of individual tiles covered by catchment area.
Definition: station_base.h:470
TownCache cache
Container for all cacheable data.
Definition: town.h:56
static uint MapMaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition: map_func.h:111
RAII class for measuring multi-step elements of performance.
Town data structure.
Definition: town.h:53
void VpSetPresizeRange(TileIndex from, TileIndex to)
Highlights all tiles between a set of two tiles.
Definition: viewport.cpp:2648
int16 x_offs
Number of pixels to shift the sprite to the right.
Definition: spritecache.h:19
Used to only draw a part of the sprite.
Definition: gfx_type.h:217
Vehicle * CheckClickOnVehicle(const ViewPort *vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition: vehicle.cpp:1165
byte max_bridge_height
maximum height of bridges
virtual void * MoveTo(void *video, int x, int y)=0
Move the destination pointer the requested amount x and y, keeping in mind any pitch and bpp of the r...
static const uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition: tile_type.h:14
static const uint MAX_BUILDING_PIXELS
Maximum height of a building in pixels in #ZOOM_LVL_BASE. (Also applies to "bridge buildings" on the ...
Definition: tile_type.h:18
Functions related to OTTD&#39;s landscape.
The normal zoom level.
Definition: zoom_type.h:22
int32 z_pos
z coordinate.
Definition: vehicle_base.h:268
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2396
void OffsetGroundSprite(int x, int y)
Called when a foundation has been drawn for the current tile.
Definition: viewport.cpp:587
Functions related to commands.
Network functions used by other parts of OpenTTD.
VpSpriteSorter fct_sorter
The sorting function.
Definition: viewport.cpp:3373
uint32 CursorID
The number of the cursor (sprite)
Definition: gfx_type.h:19
Coordinates of a point in 2D.
used for autorail highlighting (longer stretches), lower bits: direction
a steep slope falling to south (from north)
Definition: slope_type.h:69
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:45
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition: viewport.cpp:575
TrackedViewportSign sign
Location of name sign, UpdateVirtCoord updates this.
Definition: town.h:46
Owner owner
The owner of this station.
Colours _company_colours[MAX_COMPANIES]
NOSAVE: can be determined from company structs.
Definition: company_cmd.cpp:46
static uint TileHeight(TileIndex tile)
Returns the height of a tile.
Definition: tile_map.h:29
The colour translation of GRF&#39;s strings.
special mode used for highlighting while dragging (and for tunnels/docks)
static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign)
Test whether a sign is below the mouse.
Definition: viewport.cpp:2080
uint16 SignID
The type of the IDs of signs.
Definition: signs_type.h:14
bool freeze
Freeze highlight in place.
EventState VpHandlePlaceSizingDrag()
Handle the mouse while dragging for placement/resizing.
Definition: viewport.cpp:3245
Index of the small font in the font tables.
Definition: gfx_type.h:203
static uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition: slope_func.h:415
ConstructionSettings construction
construction of things in-game
Colour value is already a real palette colour index, not an index of a StringColour.
Definition: gfx_type.h:268
HighLightStyle
Highlighting draw styles.
Functions related to waypoints.
K-dimensional tree, specialised for 2-dimensional space.
Definition: kdtree.hpp:38
DrawTileProc * draw_tile_proc
Called to render the tile and its contents to the screen.
Definition: tile_cmd.h:146
void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale)
Add a child sprite to a parent sprite.
Definition: viewport.cpp:815
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:129
drag only in vertical direction
vehicle is accepted as target as well (bitmask)
ZoomLevel zoom
The zoom level of the viewport.
Definition: viewport_type.h:33
horizontal lower
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:319
Metadata about the current highlighting.
int32 x_pos
x coordinate.
Definition: vehicle_base.h:266
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
void InitializeSpriteSorter()
Choose the "best" sprite sorter and set _vp_sprite_sorter.
Definition: viewport.cpp:3385
Types related to sprite sorting.
PaletteID pal
palette to use
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:83
ZoomLevel
All zoom levels we know.
Definition: zoom_type.h:19
Base of the town class.
static uint TileHeightOutsideMap(int x, int y)
Returns the height of a tile, also for tiles outside the map (virtual "black" tiles).
Definition: tile_map.h:42
int virtual_top
Virtual top coordinate.
Definition: viewport_type.h:29
void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2, Colours colour)
Add a string to draw in the viewport.
Definition: viewport.cpp:1292
int32 left
minimal screen X coordinate of sprite (= x + sprite->x_offs), reference point for child sprites ...
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:705
horizontal upper
WindowClass window_class
Window class.
Definition: window_gui.h:311
Specification of a rectangle with absolute coordinates of all edges.
A house by a town.
Definition: tile_type.h:44
WindowClass window_class
The WindowClass of the window that is responsible for the selection mode.
virtual void OnPlaceObject(Point pt, TileIndex tile)
The user clicked some place on the map when a tile highlight mode has been set.
Definition: window_gui.h:751
The passed event is handled.
Definition: window_type.h:712
int32 y_pos
y coordinate.
Definition: vehicle_base.h:267
uint16 width_small
The width when zoomed out (small font)
Definition: viewport_type.h:50
TrackedViewportSign sign
NOSAVE: Dimensions of sign.
static uint MapMaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition: map_func.h:102
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:312
void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite at a specific world-coordinate relative to the current tile.
Definition: viewport.cpp:552
static bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren&#39;t in the game menu (there&#39;s never transpar...
Definition: transparency.h:59
FoundationPart
Enumeration of multi-part foundations.
Definition: viewport.cpp:138
static TileHighlightType GetTileHighlightType(TileIndex t)
Get tile highlight type of coverage area for a given tile.
Definition: viewport.cpp:996
Functions related to tile highlights.
HighLightStyle next_drawstyle
Queued, but not yet drawn style.
Window functions not directly related to making/drawing windows.
all rail directions
int top
Screen coordinate top edge of the viewport.
Definition: viewport_type.h:24
void SetDirty()
Mark the linkgraph dirty to be rebuilt next time Draw() is called.
Definition: linkgraph_gui.h:62
static void ViewportDrawDirtyBlocks()
Draw/colour the blocks that have been redrawn.
Definition: viewport.cpp:1599
Point outersize
Size, in tile "units", of the blue coverage area excluding the side of the selected area...
Makes the background transparent if set.
Definition: window_gui.h:27
#define TILE_ADD(x, y)
Adds to tiles together.
Definition: map_func.h:244
ZoomLevel zoom_min
minimum zoom out level
ViewportData * viewport
Pointer to viewport data, if present.
Definition: window_gui.h:326
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition: sprites.h:1367
Base classes/functions for stations.
bool kdtree_valid
Are the sign data valid for use with the _viewport_sign_kdtree?
Definition: viewport_type.h:58
static Station * Get(size_t index)
Gets station with given index.
static T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
Definition: math_func.hpp:230
bool comparison_done
Used during sprite sorting: true if sprite has been compared with all other sprites.
CargoTypes GetCargoMask()
Get a bitmask of the currently shown cargoes.
Definition: linkgraph_gui.h:65
static Point RemapCoords2(int x, int y)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap...
Definition: landscape.h:98
int32 scrollpos_y
Currently shown y coordinate (virtual screen coordinate of topleft corner of the viewport).
Definition: window_gui.h:259
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
The object is owned by a superuser / goal script.
Definition: company_type.h:27
static bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
Definition: vehicle_func.h:89
const SubSprite * sub
only draw a rectangular part of the sprite
Definition: viewport.cpp:123
bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
Definition: viewport.cpp:2350
Base class for all station-ish types.
Station data structure.
Definition: station_base.h:450
static bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren&#39;t in the game menu (there&#39;s never transpar...
Definition: transparency.h:48
Factory to &#39;query&#39; all available blitters.
byte dirty
Whether the build station window needs to redraw due to the changed selection.
static uint TilePixelHeight(TileIndex tile)
Returns the height of a tile in pixels.
Definition: tile_map.h:72
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition: map_func.h:163
static Corner OppositeCorner(Corner corner)
Returns the opposite corner.
Definition: slope_func.h:184
static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht)
Draw tile highlight for coverage area highlight.
Definition: viewport.cpp:1029
This file defines all the the animated cursors.
virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
The user has dragged over the map when the tile highlight mode has been set.
Definition: window_gui.h:784
int height
Height of the window (number of pixels down in y direction)
Definition: window_gui.h:320
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition: gfx.cpp:1462
void UpdateViewportPosition(Window *w)
Update the viewport position being displayed.
Definition: viewport.cpp:1820
#define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start)
Iterate over all windows.
Definition: window_gui.h:889
static int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition: tile_map.h:304
Base class for signs.
static void CalcRaildirsDrawstyle(int x, int y, int method)
while dragging
Definition: viewport.cpp:2858
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
int width
Screen width of the viewport.
Definition: viewport_type.h:25