OpenTTD Source: src/viewport.cpp Source File

OpenTTD Source 15.0-RC2

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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
63#include "stdafx.h"
64#include "core/backup_type.hpp"
65#include "landscape.h"
66#include "viewport_func.h"
67#include "station_base.h"
68#include "waypoint_base.h"
69#include "town.h"
70#include "signs_base.h"
71#include "signs_func.h"
72#include "vehicle_base.h"
73#include "vehicle_gui.h"
74#include "blitter/factory.hpp"
75#include "strings_func.h"
76#include "zoom_func.h"
77#include "vehicle_func.h"
78#include "company_func.h"
79#include "waypoint_func.h"
80#include "window_func.h"
81#include "tilehighlight_func.h"
82#include "window_gui.h"
83#include "linkgraph/linkgraph_gui.h"
84#include "viewport_kdtree.h"
85#include "town_kdtree.h"
86#include "viewport_sprite_sorter.h"
87#include "bridge_map.h"
88#include "company_base.h"
89#include "command_func.h"
90#include "network/network_func.h"
91#include "framerate_type.h"
92#include "viewport_cmd.h"
93
94#include <forward_list>
95#include <stack>
96
97#include "widgets/vehicle_widget.h"
98
99#include "table/strings.h"
100#include "table/string_colours.h"
101
102#include "safeguards.h"
103
104 Point _tile_fract_coords;
105
106
107 ViewportSignKdtree _viewport_sign_kdtree{};
108static int _viewport_sign_maxwidth = 0;
109
110
111 static const int MAX_TILE_EXTENT_LEFT = ZOOM_BASE * TILE_PIXELS;
112 static const int MAX_TILE_EXTENT_RIGHT = ZOOM_BASE * TILE_PIXELS;
113 static const int MAX_TILE_EXTENT_TOP = ZOOM_BASE * MAX_BUILDING_PIXELS;
114 static const int MAX_TILE_EXTENT_BOTTOM = ZOOM_BASE * (TILE_PIXELS + 2 * TILE_HEIGHT);
115
116 struct StringSpriteToDraw {
117 std::string string;
118 uint16_t width;
119 Colours colour;
120 ViewportStringFlags flags;
121 int32_t x;
122 int32_t y;
123};
124
125 struct TileSpriteToDraw {
126 SpriteID image;
127 PaletteID pal;
128 const SubSprite *sub;
129 int32_t x;
130 int32_t y;
131};
132
133 struct ChildScreenSpriteToDraw {
134 SpriteID image;
135 PaletteID pal;
136 const SubSprite *sub;
137 int32_t x;
138 int32_t y;
139 bool relative;
140 int next;
141};
142
144 enum FoundationPart : uint8_t {
145 FOUNDATION_PART_NONE = 0xFF,
146 FOUNDATION_PART_NORMAL = 0,
147 FOUNDATION_PART_HALFTILE = 1,
148 FOUNDATION_PART_END
149};
150
155 enum SpriteCombineMode : uint8_t {
156 SPRITE_COMBINE_NONE,
157 SPRITE_COMBINE_PENDING,
158 SPRITE_COMBINE_ACTIVE,
159};
160
161typedef std::vector<TileSpriteToDraw> TileSpriteToDrawVector;
162typedef std::vector<StringSpriteToDraw> StringSpriteToDrawVector;
163typedef std::vector<ParentSpriteToDraw> ParentSpriteToDrawVector;
164typedef std::vector<ChildScreenSpriteToDraw> ChildScreenSpriteToDrawVector;
165
166 constexpr int LAST_CHILD_NONE = -1;
167 constexpr int LAST_CHILD_PARENT = -2;
168
170 struct ViewportDrawer {
171 DrawPixelInfo dpi;
172
173 StringSpriteToDrawVector string_sprites_to_draw;
174 TileSpriteToDrawVector tile_sprites_to_draw;
175 ParentSpriteToDrawVector parent_sprites_to_draw;
176 ParentSpriteToSortVector parent_sprites_to_sort;
177 ChildScreenSpriteToDrawVector child_screen_sprites_to_draw;
178
179 int last_child;
180
181 SpriteCombineMode combine_sprites;
182
183 int foundation[FOUNDATION_PART_END];
184 FoundationPart foundation_part;
185 int last_foundation_child[FOUNDATION_PART_END];
186 Point foundation_offset[FOUNDATION_PART_END];
187};
188
189static bool MarkViewportDirty(const Viewport &vp, int left, int top, int right, int bottom);
190
191static ViewportDrawer _vd;
192
193 TileHighlightData _thd;
194static TileInfo _cur_ti;
195bool _draw_bounding_boxes = false;
196bool _draw_dirty_blocks = false;
197uint _dirty_block_colour = 0;
198static VpSpriteSorter _vp_sprite_sorter = nullptr;
199
200static Point MapXYZToViewport(const Viewport &vp, int x, int y, int z)
201{
202 Point p = RemapCoords(x, y, z);
203 p.x -= vp.virtual_width / 2;
204 p.y -= vp.virtual_height / 2;
205 return p;
206}
207
218 void InitializeWindowViewport(Window *w, int x, int y,
219 int width, int height, std::variant<TileIndex, VehicleID> focus, ZoomLevel zoom)
220{
221 assert(w->viewport == nullptr);
222
223 auto vp = std::make_unique<ViewportData>();
224
225 vp->left = x + w->left;
226 vp->top = y + w->top;
227 vp->width = width;
228 vp->height = height;
229
230 vp->zoom = Clamp(zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
231
232 vp->virtual_width = ScaleByZoom(width, zoom);
233 vp->virtual_height = ScaleByZoom(height, zoom);
234
235 Point pt;
236
237 if (std::holds_alternative<VehicleID>(focus)) {
238 const Vehicle *veh;
239
240 vp->follow_vehicle = std::get<VehicleID>(focus);
241 veh = Vehicle::Get(vp->follow_vehicle);
242 pt = MapXYZToViewport(*vp, veh->x_pos, veh->y_pos, veh->z_pos);
243 } else {
244 TileIndex tile = std::get<TileIndex>(focus);
245 if (tile == INVALID_TILE) {
246 /* No tile? Use center of main viewport. */
247 const Window *mw = GetMainWindow();
248
249 /* center on same place as main window (zoom is maximum, no adjustment needed) */
250 pt.x = mw->viewport->scrollpos_x + mw->viewport->virtual_width / 2;
251 pt.x -= vp->virtual_width / 2;
252 pt.y = mw->viewport->scrollpos_y + mw->viewport->virtual_height / 2;
253 pt.y -= vp->virtual_height / 2;
254 } else {
255 x = TileX(tile) * TILE_SIZE;
256 y = TileY(tile) * TILE_SIZE;
257 pt = MapXYZToViewport(*vp, x, y, GetSlopePixelZ(x, y));
258 }
259 vp->follow_vehicle = VehicleID::Invalid();
260 }
261
262 vp->scrollpos_x = pt.x;
263 vp->scrollpos_y = pt.y;
264 vp->dest_scrollpos_x = pt.x;
265 vp->dest_scrollpos_y = pt.y;
266
267 vp->overlay = nullptr;
268
269 vp->virtual_left = 0;
270 vp->virtual_top = 0;
271
272 w->viewport = std::move(vp);
273}
274
275static Point _vp_move_offs;
276
277static void DoSetViewportPosition(Window::IteratorToFront it, int left, int top, int width, int height)
278{
279 for (; !it.IsEnd(); ++it) {
280 const Window *w = *it;
281 if (left + width > w->left &&
282 w->left + w->width > left &&
283 top + height > w->top &&
284 w->top + w->height > top) {
285
286 if (left < w->left) {
287 DoSetViewportPosition(it, left, top, w->left - left, height);
288 DoSetViewportPosition(it, left + (w->left - left), top, width - (w->left - left), height);
289 return;
290 }
291
292 if (left + width > w->left + w->width) {
293 DoSetViewportPosition(it, left, top, (w->left + w->width - left), height);
294 DoSetViewportPosition(it, left + (w->left + w->width - left), top, width - (w->left + w->width - left), height);
295 return;
296 }
297
298 if (top < w->top) {
299 DoSetViewportPosition(it, left, top, width, (w->top - top));
300 DoSetViewportPosition(it, left, top + (w->top - top), width, height - (w->top - top));
301 return;
302 }
303
304 if (top + height > w->top + w->height) {
305 DoSetViewportPosition(it, left, top, width, (w->top + w->height - top));
306 DoSetViewportPosition(it, left, top + (w->top + w->height - top), width, height - (w->top + w->height - top));
307 return;
308 }
309
310 return;
311 }
312 }
313
314 {
315 int xo = _vp_move_offs.x;
316 int yo = _vp_move_offs.y;
317
318 if (abs(xo) >= width || abs(yo) >= height) {
319 /* fully_outside */
320 RedrawScreenRect(left, top, left + width, top + height);
321 return;
322 }
323
324 GfxScroll(left, top, width, height, xo, yo);
325
326 if (xo > 0) {
327 RedrawScreenRect(left, top, xo + left, top + height);
328 left += xo;
329 width -= xo;
330 } else if (xo < 0) {
331 RedrawScreenRect(left + width + xo, top, left + width, top + height);
332 width += xo;
333 }
334
335 if (yo > 0) {
336 RedrawScreenRect(left, top, width + left, top + yo);
337 } else if (yo < 0) {
338 RedrawScreenRect(left, top + height + yo, width + left, top + height);
339 }
340 }
341}
342
343static void SetViewportPosition(Window *w, int x, int y)
344{
345 Viewport &vp = *w->viewport;
346 int old_left = vp.virtual_left;
347 int old_top = vp.virtual_top;
348 int i;
349 int left, top, width, height;
350
351 vp.virtual_left = x;
352 vp.virtual_top = y;
353
354 /* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower)
355 * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL)
356 */
357 old_left = UnScaleByZoomLower(old_left, vp.zoom);
358 old_top = UnScaleByZoomLower(old_top, vp.zoom);
359 x = UnScaleByZoomLower(x, vp.zoom);
360 y = UnScaleByZoomLower(y, vp.zoom);
361
362 old_left -= x;
363 old_top -= y;
364
365 if (old_top == 0 && old_left == 0) return;
366
367 _vp_move_offs.x = old_left;
368 _vp_move_offs.y = old_top;
369
370 left = vp.left;
371 top = vp.top;
372 width = vp.width;
373 height = vp.height;
374
375 if (left < 0) {
376 width += left;
377 left = 0;
378 }
379
380 i = left + width - _screen.width;
381 if (i >= 0) width -= i;
382
383 if (width > 0) {
384 if (top < 0) {
385 height += top;
386 top = 0;
387 }
388
389 i = top + height - _screen.height;
390 if (i >= 0) height -= i;
391
392 if (height > 0) {
393 Window::IteratorToFront it(w);
394 ++it;
395 DoSetViewportPosition(it, left, top, width, height);
396 }
397 }
398}
399
408 Viewport *IsPtInWindowViewport(const Window *w, int x, int y)
409{
410 if (w->viewport == nullptr) return nullptr;
411
412 const Viewport &vp = *w->viewport;
413 if (IsInsideMM(x, vp.left, vp.left + vp.width) && IsInsideMM(y, vp.top, vp.top + vp.height)) return w->viewport.get();
414
415 return nullptr;
416}
417
430 Point TranslateXYToTileCoord(const Viewport &vp, int x, int y, bool clamp_to_map)
431{
432 if (!IsInsideBS(x, vp.left, vp.width) || !IsInsideBS(y, vp.top, vp.height)) {
433 Point pt = { -1, -1 };
434 return pt;
435 }
436
437 return InverseRemapCoords2(
438 ScaleByZoom(x - vp.left, vp.zoom) + vp.virtual_left,
439 ScaleByZoom(y - vp.top, vp.zoom) + vp.virtual_top, clamp_to_map);
440}
441
442/* When used for zooming, check area below current coordinates (x,y)
443 * and return the tile of the zoomed out/in position (zoom_x, zoom_y)
444 * when you just want the tile, make x = zoom_x and y = zoom_y */
445static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y)
446{
447 if (Window *w = FindWindowFromPt(x, y); w != nullptr) {
448 if (Viewport *vp = IsPtInWindowViewport(w, x, y); vp != nullptr) {
449 return TranslateXYToTileCoord(*vp, zoom_x, zoom_y);
450 }
451 }
452
453 return {-1, -1};
454}
455
456 Point GetTileBelowCursor()
457{
458 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
459}
460
461
462 Point GetTileZoomCenterWindow(bool in, Window * w)
463{
464 int x, y;
465 const Viewport &vp = *w->viewport;
466
467 if (in) {
468 x = ((_cursor.pos.x - vp.left) >> 1) + (vp.width >> 2);
469 y = ((_cursor.pos.y - vp.top) >> 1) + (vp.height >> 2);
470 } else {
471 x = vp.width - (_cursor.pos.x - vp.left);
472 y = vp.height - (_cursor.pos.y - vp.top);
473 }
474 /* Get the tile below the cursor and center on the zoomed-out center */
475 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp.left, y + vp.top);
476}
477
486 void HandleZoomMessage(Window *w, const Viewport &vp, WidgetID widget_zoom_in, WidgetID widget_zoom_out)
487{
488 w->SetWidgetDisabledState(widget_zoom_in, vp.zoom <= _settings_client.gui.zoom_min);
489 w->SetWidgetDirty(widget_zoom_in);
490
491 w->SetWidgetDisabledState(widget_zoom_out, vp.zoom >= _settings_client.gui.zoom_max);
492 w->SetWidgetDirty(widget_zoom_out);
493}
494
507 static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32_t x, int32_t y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0)
508{
509 assert((image & SPRITE_MASK) < MAX_SPRITES);
510
511 TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.emplace_back();
512 ts.image = image;
513 ts.pal = pal;
514 ts.sub = sub;
515 Point pt = RemapCoords(x, y, z);
516 ts.x = pt.x + extra_offs_x;
517 ts.y = pt.y + extra_offs_y;
518}
519
532 static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
533{
534 assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END));
535 assert(_vd.foundation[foundation_part] != -1);
536 Point offs = _vd.foundation_offset[foundation_part];
537
538 /* Change the active ChildSprite list to the one of the foundation */
539 AutoRestoreBackup backup(_vd.last_child, _vd.last_foundation_child[foundation_part]);
540 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub, false, false);
541}
542
556 void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32_t x, int32_t y, int z, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
557{
558 /* Switch to first foundation part, if no foundation was drawn */
559 if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL;
560
561 if (_vd.foundation[_vd.foundation_part] != -1) {
562 Point pt = RemapCoords(x, y, z);
563 AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, pt.x + extra_offs_x * ZOOM_BASE, pt.y + extra_offs_y * ZOOM_BASE);
564 } else {
565 AddTileSpriteToDraw(image, pal, _cur_ti.x + x, _cur_ti.y + y, _cur_ti.z + z, sub, extra_offs_x * ZOOM_BASE, extra_offs_y * ZOOM_BASE);
566 }
567}
568
579 void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
580{
581 DrawGroundSpriteAt(image, pal, 0, 0, 0, sub, extra_offs_x, extra_offs_y);
582}
583
591 void OffsetGroundSprite(int x, int y)
592{
593 /* Switch to next foundation part */
594 switch (_vd.foundation_part) {
595 case FOUNDATION_PART_NONE:
596 _vd.foundation_part = FOUNDATION_PART_NORMAL;
597 break;
598 case FOUNDATION_PART_NORMAL:
599 _vd.foundation_part = FOUNDATION_PART_HALFTILE;
600 break;
601 default: NOT_REACHED();
602 }
603
604 /* _vd.last_child is LAST_CHILD_NONE if foundation sprite was clipped by the viewport bounds */
605 if (_vd.last_child != LAST_CHILD_NONE) _vd.foundation[_vd.foundation_part] = static_cast<uint>(_vd.parent_sprites_to_draw.size()) - 1;
606
607 _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_BASE;
608 _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_BASE;
609 _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child;
610}
611
623 static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub)
624{
625 Point pt = RemapCoords(x, y, z);
626 const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal);
627
628 if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width ||
629 pt.x + spr->x_offs + spr->width <= _vd.dpi.left ||
630 pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height ||
631 pt.y + spr->y_offs + spr->height <= _vd.dpi.top)
632 return;
633
634 const ParentSpriteToDraw &pstd = _vd.parent_sprites_to_draw.back();
635 AddChildSpriteScreen(image, pal, pt.x - pstd.left, pt.y - pstd.top, false, sub, false);
636}
637
663 void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
664{
665 int32_t left, right, top, bottom;
666
667 assert((image & SPRITE_MASK) < MAX_SPRITES);
668
669 /* Move to bounding box. */
670 x += bounds.origin.x;
671 y += bounds.origin.y;
672 z += bounds.origin.z;
673
674 /* make the sprites transparent with the right palette */
675 if (transparent) {
676 SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
677 pal = PALETTE_TO_TRANSPARENT;
678 }
679
680 if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) {
681 AddCombinedSprite(image, pal, x + bounds.offset.x, y + bounds.offset.y, z + bounds.offset.z, sub);
682 return;
683 }
684
685 _vd.last_child = LAST_CHILD_NONE;
686
687 Point pt = RemapCoords(x + bounds.offset.x, y + bounds.offset.y, z + bounds.offset.z);
688 int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
689
690 /* Compute screen extents of sprite */
691 if (image == SPR_EMPTY_BOUNDING_BOX) {
692 left = tmp_left = RemapCoords(x + bounds.extent.x, y, z).x;
693 right = RemapCoords(x, y + bounds.extent.y, z).x + 1;
694 top = tmp_top = RemapCoords(x, y, z + bounds.extent.z).y;
695 bottom = RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1;
696 } else {
697 const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal);
698 left = tmp_left = (pt.x += spr->x_offs);
699 right = (pt.x + spr->width );
700 top = tmp_top = (pt.y += spr->y_offs);
701 bottom = (pt.y + spr->height);
702 }
703
704 if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
705 /* Compute maximal extents of sprite and its bounding box */
706 left = std::min(left , RemapCoords(x + bounds.extent.x, y, z).x);
707 right = std::max(right , RemapCoords(x, y + bounds.extent.y, z).x + 1);
708 top = std::min(top , RemapCoords(x, y, z + bounds.extent.z).y);
709 bottom = std::max(bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1);
710 }
711
712 /* Do not add the sprite to the viewport, if it is outside */
713 if (left >= _vd.dpi.left + _vd.dpi.width ||
714 right <= _vd.dpi.left ||
715 top >= _vd.dpi.top + _vd.dpi.height ||
716 bottom <= _vd.dpi.top) {
717 return;
718 }
719
720 ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.emplace_back();
721 ps.x = tmp_x;
722 ps.y = tmp_y;
723
724 ps.left = tmp_left;
725 ps.top = tmp_top;
726
727 ps.image = image;
728 ps.pal = pal;
729 ps.sub = sub;
730 ps.xmin = x;
731 ps.xmax = x + bounds.extent.x - 1;
732
733 ps.ymin = y;
734 ps.ymax = y + bounds.extent.y - 1;
735
736 ps.zmin = z;
737 ps.zmax = z + bounds.extent.z - 1;
738
739 ps.first_child = LAST_CHILD_NONE;
740
741 _vd.last_child = LAST_CHILD_PARENT;
742
743 if (_vd.combine_sprites == SPRITE_COMBINE_PENDING) _vd.combine_sprites = SPRITE_COMBINE_ACTIVE;
744}
745
764 void StartSpriteCombine()
765{
766 assert(_vd.combine_sprites == SPRITE_COMBINE_NONE);
767 _vd.combine_sprites = SPRITE_COMBINE_PENDING;
768}
769
774 void EndSpriteCombine()
775{
776 assert(_vd.combine_sprites != SPRITE_COMBINE_NONE);
777 _vd.combine_sprites = SPRITE_COMBINE_NONE;
778}
779
789 static bool IsInRangeInclusive(int begin, int end, int check)
790{
791 if (begin > end) std::swap(begin, end);
792 return begin <= check && check <= end;
793}
794
801 bool IsInsideRotatedRectangle(int x, int y)
802{
803 int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle.
804 int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative!
805 int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny.
806 int b = ((x - _thd.pos.x) - (y - _thd.pos.y));
807
808 /* Check if a and b are between 0 and dist_a or dist_b respectively. */
809 return IsInRangeInclusive(dist_a, 0, a) && IsInRangeInclusive(dist_b, 0, b);
810}
811
824 void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale, bool relative)
825{
826 assert((image & SPRITE_MASK) < MAX_SPRITES);
827
828 /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */
829 if (_vd.last_child == LAST_CHILD_NONE) return;
830
831 /* make the sprites transparent with the right palette */
832 if (transparent) {
833 SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
834 pal = PALETTE_TO_TRANSPARENT;
835 }
836
837 int32_t child_id = static_cast<int32_t>(_vd.child_screen_sprites_to_draw.size());
838 if (_vd.last_child != LAST_CHILD_PARENT) {
839 _vd.child_screen_sprites_to_draw[_vd.last_child].next = child_id;
840 } else {
841 _vd.parent_sprites_to_draw.back().first_child = child_id;
842 }
843
844 ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.emplace_back();
845 cs.image = image;
846 cs.pal = pal;
847 cs.sub = sub;
848 cs.x = scale ? x * ZOOM_BASE : x;
849 cs.y = scale ? y * ZOOM_BASE : y;
850 cs.relative = relative;
851 cs.next = LAST_CHILD_NONE;
852
853 /* Append the sprite to the active ChildSprite list.
854 * If the active ParentSprite is a foundation, update last_foundation_child as well.
855 * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */
856 if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = child_id;
857 if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = child_id;
858 _vd.last_child = child_id;
859}
860
870 static std::string &AddStringToDraw(int x, int y, Colours colour, ViewportStringFlags flags, uint16_t width)
871{
872 assert(width != 0);
873 StringSpriteToDraw &ss = _vd.string_sprites_to_draw.emplace_back();
874 ss.colour = colour;
875 ss.flags = flags;
876 ss.x = x;
877 ss.y = y;
878 ss.width = width;
879
880 return ss.string;
881}
882
883
897 static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part, int extra_offs_x = 0, int extra_offs_y = 0)
898{
899 if (_vd.foundation[foundation_part] == -1) {
900 /* draw on real ground */
901 AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset, nullptr, extra_offs_x, extra_offs_y);
902 } else {
903 /* draw on top of foundation */
904 AddChildSpriteToFoundation(image, pal, nullptr, foundation_part, extra_offs_x, extra_offs_y - z_offset * ZOOM_BASE);
905 }
906}
907
914 static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal)
915{
916 if (!IsValidTile(ti->tile)) return;
917
918 SpriteID sel;
919 if (IsHalftileSlope(ti->tileh)) {
920 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
921 SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner;
922 DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE);
923
924 Corner opposite_corner = OppositeCorner(halftile_corner);
925 if (IsSteepSlope(ti->tileh)) {
926 sel = SPR_HALFTILE_SELECTION_DOWN;
927 } else {
928 sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT);
929 }
930 sel += opposite_corner;
931 } else {
932 sel = SPR_SELECT_TILE + SlopeToSpriteOffset(ti->tileh);
933 }
934 DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL);
935}
936
937static bool IsPartOfAutoLine(int px, int py)
938{
939 px -= _thd.selstart.x;
940 py -= _thd.selstart.y;
941
942 if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false;
943
944 switch (_thd.drawstyle & HT_DIR_MASK) {
945 case HT_DIR_X: return py == 0; // x direction
946 case HT_DIR_Y: return px == 0; // y direction
947 case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
948 case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
949 case HT_DIR_VL: return px == py || px == py + 16; // vertical left
950 case HT_DIR_VR: return px == py || px == py - 16; // vertical right
951 default:
952 NOT_REACHED();
953 }
954}
955
956/* [direction][side] */
957static const HighLightStyle _autorail_type[6][2] = {
958 { HT_DIR_X, HT_DIR_X },
959 { HT_DIR_Y, HT_DIR_Y },
960 { HT_DIR_HU, HT_DIR_HL },
961 { HT_DIR_HL, HT_DIR_HU },
962 { HT_DIR_VL, HT_DIR_VR },
963 { HT_DIR_VR, HT_DIR_VL }
964};
965
966#include "table/autorail.h"
967
974 static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
975{
976 SpriteID image;
977 PaletteID pal;
978 int offset;
979
980 FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
981 Slope autorail_tileh = RemoveHalftileSlope(ti->tileh);
982 if (IsHalftileSlope(ti->tileh)) {
983 static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
984 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
985 if (autorail_type != _lower_rail[halftile_corner]) {
986 foundation_part = FOUNDATION_PART_HALFTILE;
987 /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */
988 autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
989 }
990 }
991
992 offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
993 if (offset >= 0) {
994 image = SPR_AUTORAIL_BASE + offset;
995 pal = PAL_NONE;
996 } else {
997 image = SPR_AUTORAIL_BASE - offset;
998 pal = PALETTE_SEL_TILE_RED;
999 }
1000
1001 DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
1002}
1003
1004enum TileHighlightType : uint8_t {
1005 THT_NONE,
1006 THT_WHITE,
1007 THT_BLUE,
1008 THT_RED,
1009};
1010
1011 const Station *_viewport_highlight_station;
1012 const Station *_viewport_highlight_station_rect;
1013 const Waypoint *_viewport_highlight_waypoint;
1014 const Waypoint *_viewport_highlight_waypoint_rect;
1015 const Town *_viewport_highlight_town;
1016
1022 static TileHighlightType GetTileHighlightType(TileIndex t)
1023{
1024 if (_viewport_highlight_station != nullptr) {
1025 if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_WHITE;
1026 if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE;
1027 }
1028
1029 if (_viewport_highlight_station_rect != nullptr) {
1030 if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station_rect->index) return THT_WHITE;
1031 const StationRect *r = &_viewport_highlight_station_rect->rect;
1032 if (r->PtInExtendedRect(TileX(t), TileY(t))) return THT_BLUE;
1033 }
1034
1035 if (_viewport_highlight_waypoint != nullptr) {
1036 if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_waypoint->index) return THT_BLUE;
1037 }
1038
1039 if (_viewport_highlight_waypoint_rect != nullptr) {
1040 if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_waypoint_rect->index) return THT_WHITE;
1041 const StationRect *r = &_viewport_highlight_waypoint_rect->rect;
1042 if (r->PtInExtendedRect(TileX(t), TileY(t))) return THT_BLUE;
1043 }
1044
1045 if (_viewport_highlight_town != nullptr) {
1046 if (IsTileType(t, MP_HOUSE)) {
1047 if (GetTownIndex(t) == _viewport_highlight_town->index) {
1048 TileHighlightType type = THT_RED;
1049 for (const Station *st : _viewport_highlight_town->stations_near) {
1050 if (st->owner != _current_company) continue;
1051 if (st->TileIsInCatchment(t)) return THT_BLUE;
1052 }
1053 return type;
1054 }
1055 } else if (IsTileType(t, MP_STATION)) {
1056 for (const Station *st : _viewport_highlight_town->stations_near) {
1057 if (st->owner != _current_company) continue;
1058 if (GetStationIndex(t) == st->index) return THT_WHITE;
1059 }
1060 }
1061 }
1062
1063 return THT_NONE;
1064}
1065
1071 static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht)
1072{
1073 switch (tht) {
1074 default:
1075 case THT_NONE: break;
1076 case THT_WHITE: DrawTileSelectionRect(ti, PAL_NONE); break;
1077 case THT_BLUE: DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); break;
1078 case THT_RED: DrawTileSelectionRect(ti, PALETTE_SEL_TILE_RED); break;
1079 }
1080}
1081
1086 static void HighlightTownLocalAuthorityTiles(const TileInfo *ti)
1087{
1088 /* Going through cases in order of computational time. */
1089
1090 if (_town_local_authority_kdtree.Count() == 0) return;
1091
1092 /* Tile belongs to town regardless of distance from town. */
1093 if (GetTileType(ti->tile) == MP_HOUSE) {
1094 if (!Town::GetByTile(ti->tile)->show_zone) return;
1095
1096 DrawTileSelectionRect(ti, PALETTE_CRASH);
1097 return;
1098 }
1099
1100 /* If the closest town in the highlighted list is far, we can stop searching. */
1101 TownID tid = _town_local_authority_kdtree.FindNearest(TileX(ti->tile), TileY(ti->tile));
1102 Town *closest_highlighted_town = Town::Get(tid);
1103
1104 if (DistanceManhattan(ti->tile, closest_highlighted_town->xy) >= _settings_game.economy.dist_local_authority) return;
1105
1106 /* Tile is inside of the local autrhority distance of a highlighted town,
1107 but it is possible that a non-highlighted town is even closer. */
1108 Town *closest_town = ClosestTownFromTile(ti->tile, _settings_game.economy.dist_local_authority);
1109
1110 if (closest_town->show_zone) {
1111 DrawTileSelectionRect(ti, PALETTE_CRASH);
1112 }
1113
1114}
1115
1120 static void DrawTileSelection(const TileInfo *ti)
1121{
1122 /* Highlight tiles inside local authority of selected towns. */
1123 HighlightTownLocalAuthorityTiles(ti);
1124
1125 /* Draw a red error square? */
1126 bool is_redsq = _thd.redsq == ti->tile;
1127 if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING);
1128
1129 TileHighlightType tht = GetTileHighlightType(ti->tile);
1130 DrawTileHighlightType(ti, tht);
1131
1132 /* No tile selection active? */
1133 if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return;
1134
1135 if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle
1136 if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner;
1137 return;
1138 }
1139
1140 /* Inside the inner area? */
1141 if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) &&
1142 IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) {
1143draw_inner:
1144 if (_thd.drawstyle & HT_RECT) {
1145 if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE);
1146 } else if (_thd.drawstyle & HT_POINT) {
1147 /* Figure out the Z coordinate for the single dot. */
1148 int z = 0;
1149 FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
1150 if (ti->tileh & SLOPE_N) {
1151 z += TILE_HEIGHT;
1152 if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT;
1153 }
1154 if (IsHalftileSlope(ti->tileh)) {
1155 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
1156 if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
1157 if (halftile_corner != CORNER_S) {
1158 foundation_part = FOUNDATION_PART_HALFTILE;
1159 if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
1160 }
1161 }
1162 DrawSelectionSprite(SPR_DOT, PAL_NONE, ti, z, foundation_part);
1163 } else if (_thd.drawstyle & HT_RAIL) {
1164 /* autorail highlight piece under cursor */
1165 HighLightStyle type = _thd.drawstyle & HT_DIR_MASK;
1166 assert(type < HT_DIR_END);
1167 DrawAutorailSelection(ti, _autorail_type[type][0]);
1168 } else if (IsPartOfAutoLine(ti->x, ti->y)) {
1169 /* autorail highlighting long line */
1170 HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK;
1171 uint side;
1172
1173 if (dir == HT_DIR_X || dir == HT_DIR_Y) {
1174 side = 0;
1175 } else {
1176 TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
1177 side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile)));
1178 }
1179
1180 DrawAutorailSelection(ti, _autorail_type[dir][side]);
1181 }
1182 return;
1183 }
1184
1185 /* Check if it's inside the outer area? */
1186 if (!is_redsq && (tht == THT_NONE || tht == THT_RED) && _thd.outersize.x > 0 &&
1187 IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
1188 IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
1189 /* Draw a blue rect. */
1190 DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE);
1191 return;
1192 }
1193}
1194
1201 static int GetViewportY(Point tile)
1202{
1203 /* Each increment in X or Y direction moves down by half a tile, i.e. TILE_PIXELS / 2. */
1204 return (tile.y * (int)(TILE_PIXELS / 2) + tile.x * (int)(TILE_PIXELS / 2) - TilePixelHeightOutsideMap(tile.x, tile.y)) << ZOOM_BASE_SHIFT;
1205}
1206
1210 static void ViewportAddLandscape()
1211{
1212 assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height);
1213 assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width);
1214
1215 Point upper_left = InverseRemapCoords(_vd.dpi.left, _vd.dpi.top);
1216 Point upper_right = InverseRemapCoords(_vd.dpi.left + _vd.dpi.width, _vd.dpi.top);
1217
1218 /* Transformations between tile coordinates and viewport rows/columns: See vp_column_row
1219 * column = y - x
1220 * row = x + y
1221 * x = (row - column) / 2
1222 * y = (row + column) / 2
1223 * Note: (row, columns) pairs are only valid, if they are both even or both odd.
1224 */
1225
1226 /* Columns overlap with neighbouring columns by a half tile.
1227 * - Left column is column of upper_left (rounded down) and one column to the left.
1228 * - Right column is column of upper_right (rounded up) and one column to the right.
1229 * Note: Integer-division does not round down for negative numbers, so ensure rounding with another increment/decrement.
1230 */
1231 int left_column = (upper_left.y - upper_left.x) / (int)TILE_SIZE - 2;
1232 int right_column = (upper_right.y - upper_right.x) / (int)TILE_SIZE + 2;
1233
1234 int potential_bridge_height = ZOOM_BASE * TILE_HEIGHT * _settings_game.construction.max_bridge_height;
1235
1236 /* Rows overlap with neighbouring rows by a half tile.
1237 * The first row that could possibly be visible is the row above upper_left (if it is at height 0).
1238 * Due to integer-division not rounding down for negative numbers, we need another decrement.
1239 */
1240 int row = (upper_left.x + upper_left.y) / (int)TILE_SIZE - 2;
1241 bool last_row = false;
1242 for (; !last_row; row++) {
1243 last_row = true;
1244 for (int column = left_column; column <= right_column; column++) {
1245 /* Valid row/column? */
1246 if ((row + column) % 2 != 0) continue;
1247
1248 Point tilecoord;
1249 tilecoord.x = (row - column) / 2;
1250 tilecoord.y = (row + column) / 2;
1251 assert(column == tilecoord.y - tilecoord.x);
1252 assert(row == tilecoord.y + tilecoord.x);
1253
1254 TileType tile_type;
1255 _cur_ti.x = tilecoord.x * TILE_SIZE;
1256 _cur_ti.y = tilecoord.y * TILE_SIZE;
1257
1258 if (IsInsideBS(tilecoord.x, 0, Map::SizeX()) && IsInsideBS(tilecoord.y, 0, Map::SizeY())) {
1259 /* This includes the south border at Map::MaxX / Map::MaxY. When terraforming we still draw tile selections there. */
1260 _cur_ti.tile = TileXY(tilecoord.x, tilecoord.y);
1261 tile_type = GetTileType(_cur_ti.tile);
1262 } else {
1263 _cur_ti.tile = INVALID_TILE;
1264 tile_type = MP_VOID;
1265 }
1266
1267 if (tile_type != MP_VOID) {
1268 /* We are inside the map => paint landscape. */
1269 std::tie(_cur_ti.tileh, _cur_ti.z) = GetTilePixelSlope(_cur_ti.tile);
1270 } else {
1271 /* We are outside the map => paint black. */
1272 std::tie(_cur_ti.tileh, _cur_ti.z) = GetTilePixelSlopeOutsideMap(tilecoord.x, tilecoord.y);
1273 }
1274
1275 int viewport_y = GetViewportY(tilecoord);
1276
1277 if (viewport_y + MAX_TILE_EXTENT_BOTTOM < _vd.dpi.top) {
1278 /* The tile in this column is not visible yet.
1279 * Tiles in other columns may be visible, but we need more rows in any case. */
1280 last_row = false;
1281 continue;
1282 }
1283
1284 int min_visible_height = viewport_y - (_vd.dpi.top + _vd.dpi.height);
1285 bool tile_visible = min_visible_height <= 0;
1286
1287 if (tile_type != MP_VOID) {
1288 /* Is tile with buildings visible? */
1289 if (min_visible_height < MAX_TILE_EXTENT_TOP) tile_visible = true;
1290
1291 if (IsBridgeAbove(_cur_ti.tile)) {
1292 /* Is the bridge visible? */
1293 TileIndex bridge_tile = GetNorthernBridgeEnd(_cur_ti.tile);
1294 int bridge_height = ZOOM_BASE * (GetBridgePixelHeight(bridge_tile) - TilePixelHeight(_cur_ti.tile));
1295 if (min_visible_height < bridge_height + MAX_TILE_EXTENT_TOP) tile_visible = true;
1296 }
1297
1298 /* Would a higher bridge on a more southern tile be visible?
1299 * If yes, we need to loop over more rows to possibly find one. */
1300 if (min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
1301 } else {
1302 /* Outside of map. If we are on the north border of the map, there may still be a bridge visible,
1303 * so we need to loop over more rows to possibly find one. */
1304 if ((tilecoord.x <= 0 || tilecoord.y <= 0) && min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
1305 }
1306
1307 if (tile_visible) {
1308 last_row = false;
1309 _vd.foundation_part = FOUNDATION_PART_NONE;
1310 _vd.foundation[0] = -1;
1311 _vd.foundation[1] = -1;
1312 _vd.last_foundation_child[0] = LAST_CHILD_NONE;
1313 _vd.last_foundation_child[1] = LAST_CHILD_NONE;
1314
1315 _tile_type_procs[tile_type]->draw_tile_proc(&_cur_ti);
1316 if (_cur_ti.tile != INVALID_TILE) DrawTileSelection(&_cur_ti);
1317 }
1318 }
1319 }
1320}
1321
1330std::string *ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sign, ViewportStringFlags flags, Colours colour)
1331{
1332 int left = dpi->left;
1333 int top = dpi->top;
1334 int right = left + dpi->width;
1335 int bottom = top + dpi->height;
1336
1337 bool small = flags.Test(ViewportStringFlag::Small);
1338 int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, dpi->zoom);
1339 int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom);
1340
1341 if (bottom < sign->top ||
1342 top > sign->top + sign_height ||
1343 right < sign->center - sign_half_width ||
1344 left > sign->center + sign_half_width) {
1345 return nullptr;
1346 }
1347
1348 return &AddStringToDraw(sign->center - sign_half_width, sign->top, colour, flags, small ? sign->width_small : sign->width_normal);
1349}
1350
1351static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom)
1352{
1353 const int fh = std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL));
1354 const int max_tw = _viewport_sign_maxwidth / 2 + 1;
1355 const int expand_y = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + fh + WidgetDimensions::scaled.fullbevel.bottom, zoom);
1356 const int expand_x = ScaleByZoom(WidgetDimensions::scaled.fullbevel.left + max_tw + WidgetDimensions::scaled.fullbevel.right, zoom);
1357
1358 r.left -= expand_x;
1359 r.right += expand_x;
1360 r.top -= expand_y;
1361 r.bottom += expand_y;
1362
1363 return r;
1364}
1365
1372 static void ViewportAddTownStrings(DrawPixelInfo *dpi, const std::vector<const Town *> &towns, bool small)
1373{
1374 ViewportStringFlags flags{};
1375 if (small) flags.Set({ViewportStringFlag::Small, ViewportStringFlag::Shadow});
1376
1377 StringID stringid_town = !small && _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_TOWN_NAME;
1378 StringID stringid_town_city = stringid_town;
1379 if (!small) {
1380 stringid_town_city = _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_CITY_POP : STR_VIEWPORT_TOWN_CITY;
1381 }
1382
1383 for (const Town *t : towns) {
1384 std::string *str = ViewportAddString(dpi, &t->cache.sign, flags, INVALID_COLOUR);
1385 if (str == nullptr) continue;
1386
1387 if (t->larger_town) {
1388 *str = GetString(stringid_town_city, t->index, t->cache.population);
1389 } else {
1390 *str = GetString(stringid_town, t->index, t->cache.population);
1391 }
1392 }
1393}
1394
1401 static void ViewportAddSignStrings(DrawPixelInfo *dpi, const std::vector<const Sign *> &signs, bool small)
1402{
1403 ViewportStringFlags flags{};
1404 if (small) flags.Set(ViewportStringFlag::Small);
1405
1406 /* Signs placed by a game script don't have a frame. */
1407 ViewportStringFlags deity_flags{flags};
1408 flags.Set(IsTransparencySet(TO_SIGNS) ? ViewportStringFlag::TransparentRect : ViewportStringFlag::ColourRect);
1409
1410 for (const Sign *si : signs) {
1411 std::string *str = ViewportAddString(dpi, &si->sign, (si->owner == OWNER_DEITY) ? deity_flags : flags,
1412 (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner]));
1413 if (str == nullptr) continue;
1414
1415 *str = GetString(STR_SIGN_NAME, si->index);
1416 }
1417}
1418
1425 static void ViewportAddStationStrings(DrawPixelInfo *dpi, const std::vector<const BaseStation *> &stations, bool small)
1426{
1427 /* Transparent station signs have colour text instead of a colour panel. */
1428 ViewportStringFlags flags{IsTransparencySet(TO_SIGNS) ? ViewportStringFlag::TextColour : ViewportStringFlag::ColourRect};
1429 if (small) flags.Set(ViewportStringFlag::Small);
1430
1431 for (const BaseStation *st : stations) {
1432 std::string *str = ViewportAddString(dpi, &st->sign, flags, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]);
1433 if (str == nullptr) continue;
1434
1435 if (Station::IsExpected(st)) { /* Station */
1436 *str = GetString(small ? STR_STATION_NAME : STR_VIEWPORT_STATION, st->index, st->facilities);
1437 } else { /* Waypoint */
1438 *str = GetString(STR_WAYPOINT_NAME, st->index);
1439 }
1440 }
1441}
1442
1443static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi)
1444{
1445 Rect search_rect{ dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height };
1446 search_rect = ExpandRectWithViewportSignMargins(search_rect, dpi->zoom);
1447
1448 bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && _game_mode != GM_MENU;
1449 bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && _game_mode != GM_MENU;
1450 bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES) && _game_mode != GM_MENU;
1451 bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS);
1452 bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
1453
1454 /* Collect all the items first and draw afterwards, to ensure layering */
1455 std::vector<const BaseStation *> stations;
1456 std::vector<const Town *> towns;
1457 std::vector<const Sign *> signs;
1458
1459 _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) {
1460 switch (item.type) {
1461 case ViewportSignKdtreeItem::VKI_STATION: {
1462 if (!show_stations) break;
1463 const BaseStation *st = BaseStation::Get(std::get<StationID>(item.id));
1464
1465 /* If no facilities are present the station is a ghost station. */
1466 StationFacilities facilities = st->facilities;
1467 if (facilities.None()) facilities = STATION_FACILITY_GHOST;
1468
1469 if (!facilities.Any(_facility_display_opt)) break;
1470
1471 /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */
1472 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
1473
1474 stations.push_back(st);
1475 break;
1476 }
1477
1478 case ViewportSignKdtreeItem::VKI_WAYPOINT: {
1479 if (!show_waypoints) break;
1480 const BaseStation *st = BaseStation::Get(std::get<StationID>(item.id));
1481
1482 /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */
1483 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
1484
1485 stations.push_back(st);
1486 break;
1487 }
1488
1489 case ViewportSignKdtreeItem::VKI_TOWN:
1490 if (!show_towns) break;
1491 towns.push_back(Town::Get(std::get<TownID>(item.id)));
1492 break;
1493
1494 case ViewportSignKdtreeItem::VKI_SIGN: {
1495 if (!show_signs) break;
1496 const Sign *si = Sign::Get(std::get<SignID>(item.id));
1497
1498 /* Don't draw if sign is owned by another company and competitor signs should be hidden.
1499 * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt
1500 * companies can leave OWNER_NONE signs after them. */
1501 if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break;
1502
1503 signs.push_back(si);
1504 break;
1505 }
1506
1507 default:
1508 NOT_REACHED();
1509 }
1510 });
1511
1512 /* Small versions of signs are used zoom level 4X and higher. */
1513 bool small = dpi->zoom >= ZoomLevel::Out4x;
1514
1515 /* Layering order (bottom to top): Town names, signs, stations */
1516 ViewportAddTownStrings(dpi, towns, small);
1517
1518 /* Do not draw signs nor station names if they are set invisible */
1519 if (IsInvisibilitySet(TO_SIGNS)) return;
1520
1521 ViewportAddSignStrings(dpi, signs, small);
1522 ViewportAddStationStrings(dpi, stations, small);
1523}
1524
1525
1533 void ViewportSign::UpdatePosition(int center, int top, std::string_view str, std::string_view str_small)
1534{
1535 if (this->width_normal != 0) this->MarkDirty();
1536
1537 this->top = top;
1538
1539 this->width_normal = WidgetDimensions::scaled.fullbevel.left + Align(GetStringBoundingBox(str).width, 2) + WidgetDimensions::scaled.fullbevel.right;
1540 this->center = center;
1541
1542 /* zoomed out version */
1543 if (str_small.empty()) str_small = str;
1544 this->width_small = WidgetDimensions::scaled.fullbevel.left + Align(GetStringBoundingBox(str_small, FS_SMALL).width, 2) + WidgetDimensions::scaled.fullbevel.right;
1545
1546 this->MarkDirty();
1547}
1548
1555 void ViewportSign::MarkDirty(ZoomLevel maxzoom) const
1556{
1557 Rect zoomlevels[to_underlying(ZoomLevel::End)];
1558
1559 /* We don't know which size will be drawn, so mark the largest area dirty. */
1560 const uint half_width = std::max(this->width_normal, this->width_small) / 2 + 1;
1561 const uint height = WidgetDimensions::scaled.fullbevel.top + std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL)) + WidgetDimensions::scaled.fullbevel.bottom + 1;
1562
1563 for (ZoomLevel zoom = ZoomLevel::Begin; zoom != ZoomLevel::End; zoom++) {
1564 zoomlevels[to_underlying(zoom)].left = this->center - ScaleByZoom(half_width, zoom);
1565 zoomlevels[to_underlying(zoom)].top = this->top - ScaleByZoom(1, zoom);
1566 zoomlevels[to_underlying(zoom)].right = this->center + ScaleByZoom(half_width, zoom);
1567 zoomlevels[to_underlying(zoom)].bottom = this->top + ScaleByZoom(height, zoom);
1568 }
1569
1570 for (const Window *w : Window::Iterate()) {
1571 if (w->viewport == nullptr) continue;
1572
1573 Viewport &vp = *w->viewport;
1574 if (vp.zoom <= maxzoom) {
1575 assert(vp.width != 0);
1576 Rect &zl = zoomlevels[to_underlying(vp.zoom)];
1577 MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom);
1578 }
1579 }
1580}
1581
1582static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv)
1583{
1584 for (const TileSpriteToDraw &ts : *tstdv) {
1585 DrawSpriteViewport(ts.image, ts.pal, ts.x, ts.y, ts.sub);
1586 }
1587}
1588
1590 static bool ViewportSortParentSpritesChecker()
1591{
1592 return true;
1593}
1594
1596 static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
1597{
1598 if (psdv->size() < 2) return;
1599
1600 /* We rely on sprites being, for the most part, already ordered.
1601 * So we don't need to move many of them and can keep track of their
1602 * order efficiently by using stack. We always move sprites to the front
1603 * of the current position, i.e. to the top of the stack.
1604 * Also use special constants to indicate sorting state without
1605 * adding extra fields to ParentSpriteToDraw structure.
1606 */
1607 const uint32_t ORDER_COMPARED = UINT32_MAX; // Sprite was compared but we still need to compare the ones preceding it
1608 const uint32_t ORDER_RETURNED = UINT32_MAX - 1; // Mark sorted sprite in case there are other occurrences of it in the stack
1609 std::stack<ParentSpriteToDraw *> sprite_order;
1610 uint32_t next_order = 0;
1611
1612 std::forward_list<std::pair<int64_t, ParentSpriteToDraw *>> sprite_list; // We store sprites in a list sorted by xmin+ymin
1613
1614 /* Initialize sprite list and order. */
1615 for (auto p = psdv->rbegin(); p != psdv->rend(); p++) {
1616 sprite_list.emplace_front((*p)->xmin + (*p)->ymin, *p);
1617 sprite_order.push(*p);
1618 (*p)->order = next_order++;
1619 }
1620
1621 sprite_list.sort();
1622
1623 std::vector<ParentSpriteToDraw *> preceding; // Temporarily stores sprites that precede current and their position in the list
1624 auto preceding_prev = sprite_list.begin(); // Store iterator in case we need to delete a single preceding sprite
1625 auto out = psdv->begin(); // Iterator to output sorted sprites
1626
1627 while (!sprite_order.empty()) {
1628
1629 auto s = sprite_order.top();
1630 sprite_order.pop();
1631
1632 /* Sprite is already sorted, ignore it. */
1633 if (s->order == ORDER_RETURNED) continue;
1634
1635 /* Sprite was already compared, just need to output it. */
1636 if (s->order == ORDER_COMPARED) {
1637 *(out++) = s;
1638 s->order = ORDER_RETURNED;
1639 continue;
1640 }
1641
1642 preceding.clear();
1643
1644 /* We only need sprites with xmin <= s->xmax && ymin <= s->ymax && zmin <= s->zmax
1645 * So by iterating sprites with xmin + ymin <= s->xmax + s->ymax
1646 * we get all we need and some more that we filter out later.
1647 * We don't include zmin into the sum as there are usually more neighbours on x and y than z
1648 * so including it will actually increase the amount of false positives.
1649 * Also min coordinates can be > max so using max(xmin, xmax) + max(ymin, ymax)
1650 * to ensure that we iterate the current sprite as we need to remove it from the list.
1651 */
1652 auto ssum = std::max(s->xmax, s->xmin) + std::max(s->ymax, s->ymin);
1653 auto prev = sprite_list.before_begin();
1654 auto x = sprite_list.begin();
1655 while (x != sprite_list.end() && x->first <= ssum) {
1656 auto p = x->second;
1657 if (p == s) {
1658 /* We found the current sprite, remove it and move on. */
1659 x = sprite_list.erase_after(prev);
1660 continue;
1661 }
1662
1663 auto p_prev = prev;
1664 prev = x++;
1665
1666 if (s->xmax < p->xmin || s->ymax < p->ymin || s->zmax < p->zmin) continue;
1667 if (s->xmin <= p->xmax && // overlap in X?
1668 s->ymin <= p->ymax && // overlap in Y?
1669 s->zmin <= p->zmax) { // overlap in Z?
1670 if (s->xmin + s->xmax + s->ymin + s->ymax + s->zmin + s->zmax <=
1671 p->xmin + p->xmax + p->ymin + p->ymax + p->zmin + p->zmax) {
1672 continue;
1673 }
1674 }
1675 preceding.push_back(p);
1676 preceding_prev = p_prev;
1677 }
1678
1679 if (preceding.empty()) {
1680 /* No preceding sprites, add current one to the output */
1681 *(out++) = s;
1682 s->order = ORDER_RETURNED;
1683 continue;
1684 }
1685
1686 /* Optimization for the case when we only have 1 sprite to move. */
1687 if (preceding.size() == 1) {
1688 auto p = preceding[0];
1689 /* We can only output the preceding sprite if there can't be any other sprites preceding it. */
1690 if (p->xmax <= s->xmax && p->ymax <= s->ymax && p->zmax <= s->zmax) {
1691 p->order = ORDER_RETURNED;
1692 s->order = ORDER_RETURNED;
1693 sprite_list.erase_after(preceding_prev);
1694 *(out++) = p;
1695 *(out++) = s;
1696 continue;
1697 }
1698 }
1699
1700 /* Sort all preceding sprites by order and assign new orders in reverse (as original sorter did). */
1701 std::sort(preceding.begin(), preceding.end(), [](const ParentSpriteToDraw *a, const ParentSpriteToDraw *b) {
1702 return a->order > b->order;
1703 });
1704
1705 s->order = ORDER_COMPARED;
1706 sprite_order.push(s); // Still need to output so push it back for now
1707
1708 for (auto p: preceding) {
1709 p->order = next_order++;
1710 sprite_order.push(p);
1711 }
1712 }
1713}
1714
1715
1716static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv)
1717{
1718 for (const ParentSpriteToDraw *ps : *psd) {
1719 if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub);
1720
1721 int child_idx = ps->first_child;
1722 while (child_idx >= 0) {
1723 const ChildScreenSpriteToDraw *cs = &(*csstdv)[child_idx];
1724 child_idx = cs->next;
1725 if (cs->relative) {
1726 DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub);
1727 } else {
1728 DrawSpriteViewport(cs->image, cs->pal, ps->x + cs->x, ps->y + cs->y, cs->sub);
1729 }
1730 }
1731 }
1732}
1733
1738 static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
1739{
1740 for (const ParentSpriteToDraw *ps : *psd) {
1741 Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner
1742 Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner
1743 Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner
1744 Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin ); // bottom front corner
1745
1746 DrawBox( pt1.x, pt1.y,
1747 pt2.x - pt1.x, pt2.y - pt1.y,
1748 pt3.x - pt1.x, pt3.y - pt1.y,
1749 pt4.x - pt1.x, pt4.y - pt1.y);
1750 }
1751}
1752
1756 static void ViewportDrawDirtyBlocks()
1757{
1758 Blitter *blitter = BlitterFactory::GetCurrentBlitter();
1759 const DrawPixelInfo *dpi = _cur_dpi;
1760 void *dst;
1761 int right = UnScaleByZoom(dpi->width, dpi->zoom);
1762 int bottom = UnScaleByZoom(dpi->height, dpi->zoom);
1763
1764 PixelColour colour = _string_colourmap[_dirty_block_colour & 0xF];
1765
1766 dst = dpi->dst_ptr;
1767
1768 uint8_t bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
1769 do {
1770 for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, colour);
1771 dst = blitter->MoveTo(dst, 0, 1);
1772 } while (--bottom > 0);
1773}
1774
1775static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv)
1776{
1777 for (const StringSpriteToDraw &ss : *sstdv) {
1778 bool small = ss.flags.Test(ViewportStringFlag::Small);
1779 int w = ss.width;
1780 int x = UnScaleByZoom(ss.x, zoom);
1781 int y = UnScaleByZoom(ss.y, zoom);
1782 int h = WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom;
1783
1784 TextColour colour = TC_WHITE;
1785 if (ss.flags.Test(ViewportStringFlag::ColourRect)) {
1786 if (ss.colour != INVALID_COLOUR) DrawFrameRect(x, y, x + w - 1, y + h - 1, ss.colour, {});
1787 colour = TC_BLACK;
1788 } else if (ss.flags.Test(ViewportStringFlag::TransparentRect)) {
1789 DrawFrameRect(x, y, x + w - 1, y + h - 1, ss.colour, FrameFlag::Transparent);
1790 }
1791
1792 if (ss.flags.Test(ViewportStringFlag::TextColour)) {
1793 if (ss.colour != INVALID_COLOUR) colour = GetColourGradient(ss.colour, SHADE_LIGHTER).ToTextColour();
1794 }
1795
1796 int left = x + WidgetDimensions::scaled.fullbevel.left;
1797 int right = x + w - 1 - WidgetDimensions::scaled.fullbevel.right;
1798 int top = y + WidgetDimensions::scaled.fullbevel.top;
1799
1800 int shadow_offset = 0;
1801 if (small && ss.flags.Test(ViewportStringFlag::Shadow)) {
1802 /* Shadow needs to be shifted 1 pixel. */
1803 shadow_offset = WidgetDimensions::scaled.fullbevel.top;
1804 DrawString(left + shadow_offset, right + shadow_offset, top, ss.string, TC_BLACK, SA_HOR_CENTER, false, FS_SMALL);
1805 }
1806
1807 DrawString(left, right, top - shadow_offset, ss.string, colour, SA_HOR_CENTER, false, small ? FS_SMALL : FS_NORMAL);
1808 }
1809}
1810
1811void ViewportDoDraw(const Viewport &vp, int left, int top, int right, int bottom)
1812{
1813 _vd.dpi.zoom = vp.zoom;
1814 int mask = ScaleByZoom(-1, vp.zoom);
1815
1816 _vd.combine_sprites = SPRITE_COMBINE_NONE;
1817
1818 _vd.dpi.width = (right - left) & mask;
1819 _vd.dpi.height = (bottom - top) & mask;
1820 _vd.dpi.left = left & mask;
1821 _vd.dpi.top = top & mask;
1822 _vd.dpi.pitch = _cur_dpi->pitch;
1823 _vd.last_child = LAST_CHILD_NONE;
1824
1825 int x = UnScaleByZoom(_vd.dpi.left - (vp.virtual_left & mask), vp.zoom) + vp.left;
1826 int y = UnScaleByZoom(_vd.dpi.top - (vp.virtual_top & mask), vp.zoom) + vp.top;
1827
1828 _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_cur_dpi->dst_ptr, x - _cur_dpi->left, y - _cur_dpi->top);
1829 AutoRestoreBackup dpi_backup(_cur_dpi, &_vd.dpi);
1830
1831 ViewportAddLandscape();
1832 ViewportAddVehicles(&_vd.dpi);
1833
1834 ViewportAddKdtreeSigns(&_vd.dpi);
1835
1836 DrawTextEffects(&_vd.dpi);
1837
1838 if (!_vd.tile_sprites_to_draw.empty()) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw);
1839
1840 for (auto &psd : _vd.parent_sprites_to_draw) {
1841 _vd.parent_sprites_to_sort.push_back(&psd);
1842 }
1843
1844 _vp_sprite_sorter(&_vd.parent_sprites_to_sort);
1845 ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw);
1846
1847 if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort);
1848 if (_draw_dirty_blocks) ViewportDrawDirtyBlocks();
1849
1850 DrawPixelInfo dp = _vd.dpi;
1851 ZoomLevel zoom = _vd.dpi.zoom;
1852 dp.zoom = ZoomLevel::Min;
1853 dp.width = UnScaleByZoom(dp.width, zoom);
1854 dp.height = UnScaleByZoom(dp.height, zoom);
1855 AutoRestoreBackup cur_dpi(_cur_dpi, &dp);
1856
1857 if (vp.overlay != nullptr && vp.overlay->GetCargoMask() != 0 && vp.overlay->GetCompanyMask().Any()) {
1858 /* translate to window coordinates */
1859 dp.left = x;
1860 dp.top = y;
1861 vp.overlay->Draw(&dp);
1862 }
1863
1864 if (!_vd.string_sprites_to_draw.empty()) {
1865 /* translate to world coordinates */
1866 dp.left = UnScaleByZoom(_vd.dpi.left, zoom);
1867 dp.top = UnScaleByZoom(_vd.dpi.top, zoom);
1868 ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw);
1869 }
1870
1871 _vd.string_sprites_to_draw.clear();
1872 _vd.tile_sprites_to_draw.clear();
1873 _vd.parent_sprites_to_draw.clear();
1874 _vd.parent_sprites_to_sort.clear();
1875 _vd.child_screen_sprites_to_draw.clear();
1876}
1877
1878static inline void ViewportDraw(const Viewport &vp, int left, int top, int right, int bottom)
1879{
1880 if (right <= vp.left || bottom <= vp.top) return;
1881
1882 if (left >= vp.left + vp.width) return;
1883
1884 if (left < vp.left) left = vp.left;
1885 if (right > vp.left + vp.width) right = vp.left + vp.width;
1886
1887 if (top >= vp.top + vp.height) return;
1888
1889 if (top < vp.top) top = vp.top;
1890 if (bottom > vp.top + vp.height) bottom = vp.top + vp.height;
1891
1892 ViewportDoDraw(vp,
1893 ScaleByZoom(left - vp.left, vp.zoom) + vp.virtual_left,
1894 ScaleByZoom(top - vp.top, vp.zoom) + vp.virtual_top,
1895 ScaleByZoom(right - vp.left, vp.zoom) + vp.virtual_left,
1896 ScaleByZoom(bottom - vp.top, vp.zoom) + vp.virtual_top
1897 );
1898}
1899
1903 void Window::DrawViewport() const
1904{
1905 PerformanceAccumulator framerate(PFE_DRAWWORLD);
1906
1907 DrawPixelInfo *dpi = _cur_dpi;
1908
1909 dpi->left += this->left;
1910 dpi->top += this->top;
1911
1912 ViewportDraw(*this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
1913
1914 dpi->left -= this->left;
1915 dpi->top -= this->top;
1916}
1917
1928 static inline void ClampViewportToMap(const Viewport &vp, int *scroll_x, int *scroll_y)
1929{
1930 /* Centre of the viewport is hot spot. */
1931 Point pt = {
1932 *scroll_x + vp.virtual_width / 2,
1933 *scroll_y + vp.virtual_height / 2
1934 };
1935
1936 /* Find nearest tile that is within borders of the map. */
1937 bool clamped;
1938 pt = InverseRemapCoords2(pt.x, pt.y, true, &clamped);
1939
1940 if (clamped) {
1941 /* Convert back to viewport coordinates and remove centering. */
1942 pt = RemapCoords2(pt.x, pt.y);
1943 *scroll_x = pt.x - vp.virtual_width / 2;
1944 *scroll_y = pt.y - vp.virtual_height / 2;
1945 }
1946}
1947
1960 static void ClampSmoothScroll(uint32_t delta_ms, int64_t delta_hi, int64_t delta_lo, int &delta_hi_clamped, int &delta_lo_clamped)
1961{
1963 constexpr int PIXELS_PER_TILE = TILE_PIXELS * 2 * ZOOM_BASE;
1964
1965 assert(delta_hi != 0);
1966
1967 /* Move at most 75% of the distance every 30ms, for a smooth experience */
1968 int64_t delta_left = delta_hi * std::pow(0.75, delta_ms / 30.0);
1969 /* Move never more than 16 tiles per 30ms. */
1970 int max_scroll = Map::ScaleBySize1D(16 * PIXELS_PER_TILE * delta_ms / 30);
1971
1972 /* We never go over the max_scroll speed. */
1973 delta_hi_clamped = Clamp(delta_hi - delta_left, -max_scroll, max_scroll);
1974 /* The lower delta is in ratio of the higher delta, so we keep going straight at the destination. */
1975 delta_lo_clamped = delta_lo * delta_hi_clamped / delta_hi;
1976
1977 /* Ensure we always move (delta_hi can't be zero). */
1978 if (delta_hi_clamped == 0) {
1979 delta_hi_clamped = delta_hi > 0 ? 1 : -1;
1980 }
1981}
1982
1988 void UpdateViewportPosition(Window *w, uint32_t delta_ms)
1989{
1990 ViewportData &vp = *w->viewport;
1991
1992 if (vp.follow_vehicle != VehicleID::Invalid()) {
1993 const Vehicle *veh = Vehicle::Get(vp.follow_vehicle);
1994 Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
1995
1996 vp.scrollpos_x = pt.x;
1997 vp.scrollpos_y = pt.y;
1998 SetViewportPosition(w, pt.x, pt.y);
1999 } else {
2000 /* Ensure the destination location is within the map */
2001 ClampViewportToMap(vp, &vp.dest_scrollpos_x, &vp.dest_scrollpos_y);
2002
2003 int delta_x = vp.dest_scrollpos_x - vp.scrollpos_x;
2004 int delta_y = vp.dest_scrollpos_y - vp.scrollpos_y;
2005
2006 int current_x = vp.scrollpos_x;
2007 int current_y = vp.scrollpos_y;
2008
2009 bool update_overlay = false;
2010 if (delta_x != 0 || delta_y != 0) {
2011 if (_settings_client.gui.smooth_scroll) {
2012 int delta_x_clamped;
2013 int delta_y_clamped;
2014
2015 if (abs(delta_x) > abs(delta_y)) {
2016 ClampSmoothScroll(delta_ms, delta_x, delta_y, delta_x_clamped, delta_y_clamped);
2017 } else {
2018 ClampSmoothScroll(delta_ms, delta_y, delta_x, delta_y_clamped, delta_x_clamped);
2019 }
2020
2021 vp.scrollpos_x += delta_x_clamped;
2022 vp.scrollpos_y += delta_y_clamped;
2023 } else {
2024 vp.scrollpos_x = vp.dest_scrollpos_x;
2025 vp.scrollpos_y = vp.dest_scrollpos_y;
2026 }
2027 update_overlay = (vp.scrollpos_x == vp.dest_scrollpos_x &&
2028 vp.scrollpos_y == vp.dest_scrollpos_y);
2029 }
2030
2031 ClampViewportToMap(vp, &vp.scrollpos_x, &vp.scrollpos_y);
2032
2033 /* When moving small amounts around the border we can get stuck, and
2034 * not actually move. In those cases, teleport to the destination. */
2035 if ((delta_x != 0 || delta_y != 0) && current_x == vp.scrollpos_x && current_y == vp.scrollpos_y) {
2036 vp.scrollpos_x = vp.dest_scrollpos_x;
2037 vp.scrollpos_y = vp.dest_scrollpos_y;
2038 }
2039
2040 SetViewportPosition(w, vp.scrollpos_x, vp.scrollpos_y);
2041 if (update_overlay) RebuildViewportOverlay(w);
2042 }
2043}
2044
2055 static bool MarkViewportDirty(const Viewport &vp, int left, int top, int right, int bottom)
2056{
2057 /* Rounding wrt. zoom-out level */
2058 right += (1 << to_underlying(vp.zoom)) - 1;
2059 bottom += (1 << to_underlying(vp.zoom)) - 1;
2060
2061 right -= vp.virtual_left;
2062 if (right <= 0) return false;
2063
2064 bottom -= vp.virtual_top;
2065 if (bottom <= 0) return false;
2066
2067 left = std::max(0, left - vp.virtual_left);
2068
2069 if (left >= vp.virtual_width) return false;
2070
2071 top = std::max(0, top - vp.virtual_top);
2072
2073 if (top >= vp.virtual_height) return false;
2074
2075 AddDirtyBlock(
2076 UnScaleByZoomLower(left, vp.zoom) + vp.left,
2077 UnScaleByZoomLower(top, vp.zoom) + vp.top,
2078 UnScaleByZoom(right, vp.zoom) + vp.left + 1,
2079 UnScaleByZoom(bottom, vp.zoom) + vp.top + 1
2080 );
2081
2082 return true;
2083}
2084
2094 bool MarkAllViewportsDirty(int left, int top, int right, int bottom)
2095{
2096 bool dirty = false;
2097
2098 for (const Window *w : Window::Iterate()) {
2099 if (w->viewport != nullptr) {
2100 assert(w->viewport->width != 0);
2101 if (MarkViewportDirty(*w->viewport, left, top, right, bottom)) dirty = true;
2102 }
2103 }
2104
2105 return dirty;
2106}
2107
2108void ConstrainAllViewportsZoom()
2109{
2110 for (Window *w : Window::Iterate()) {
2111 if (w->viewport == nullptr) continue;
2112
2113 ZoomLevel zoom = Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
2114 if (zoom != w->viewport->zoom) {
2115 while (w->viewport->zoom < zoom) DoZoomInOutWindow(ZOOM_OUT, w);
2116 while (w->viewport->zoom > zoom) DoZoomInOutWindow(ZOOM_IN, w);
2117 }
2118 }
2119}
2120
2128 void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
2129{
2130 Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, tile_height_override * TILE_HEIGHT);
2131 MarkAllViewportsDirty(
2132 pt.x - MAX_TILE_EXTENT_LEFT,
2133 pt.y - MAX_TILE_EXTENT_TOP - ZOOM_BASE * TILE_HEIGHT * bridge_level_offset,
2134 pt.x + MAX_TILE_EXTENT_RIGHT,
2135 pt.y + MAX_TILE_EXTENT_BOTTOM);
2136}
2137
2145 static void SetSelectionTilesDirty()
2146{
2147 int x_size = _thd.size.x;
2148 int y_size = _thd.size.y;
2149
2150 if (!_thd.diagonal) { // Selecting in a straight rectangle (or a single square)
2151 int x_start = _thd.pos.x;
2152 int y_start = _thd.pos.y;
2153
2154 if (_thd.outersize.x != 0) {
2155 x_size += _thd.outersize.x;
2156 x_start += _thd.offs.x;
2157 y_size += _thd.outersize.y;
2158 y_start += _thd.offs.y;
2159 }
2160
2161 x_size -= TILE_SIZE;
2162 y_size -= TILE_SIZE;
2163
2164 assert(x_size >= 0);
2165 assert(y_size >= 0);
2166
2167 int x_end = Clamp(x_start + x_size, 0, Map::SizeX() * TILE_SIZE - TILE_SIZE);
2168 int y_end = Clamp(y_start + y_size, 0, Map::SizeY() * TILE_SIZE - TILE_SIZE);
2169
2170 x_start = Clamp(x_start, 0, Map::SizeX() * TILE_SIZE - TILE_SIZE);
2171 y_start = Clamp(y_start, 0, Map::SizeY() * TILE_SIZE - TILE_SIZE);
2172
2173 /* make sure everything is multiple of TILE_SIZE */
2174 assert((x_end | y_end | x_start | y_start) % TILE_SIZE == 0);
2175
2176 /* How it works:
2177 * Suppose we have to mark dirty rectangle of 3x4 tiles:
2178 * x
2179 * xxx
2180 * xxxxx
2181 * xxxxx
2182 * xxx
2183 * x
2184 * This algorithm marks dirty columns of tiles, so it is done in 3+4-1 steps:
2185 * 1) x 2) x
2186 * xxx Oxx
2187 * Oxxxx xOxxx
2188 * xxxxx Oxxxx
2189 * xxx xxx
2190 * x x
2191 * And so forth...
2192 */
2193
2194 int top_x = x_end; // coordinates of top dirty tile
2195 int top_y = y_start;
2196 int bot_x = top_x; // coordinates of bottom dirty tile
2197 int bot_y = top_y;
2198
2199 do {
2200 /* topmost dirty point */
2201 TileIndex top_tile = TileVirtXY(top_x, top_y);
2202 Point top = RemapCoords(top_x, top_y, GetTileMaxPixelZ(top_tile));
2203
2204 /* bottommost point */
2205 TileIndex bottom_tile = TileVirtXY(bot_x, bot_y);
2206 Point bot = RemapCoords(bot_x + TILE_SIZE, bot_y + TILE_SIZE, GetTilePixelZ(bottom_tile)); // bottommost point
2207
2208 /* the 'x' coordinate of 'top' and 'bot' is the same (and always in the same distance from tile middle),
2209 * tile height/slope affects only the 'y' on-screen coordinate! */
2210
2211 int l = top.x - TILE_PIXELS * ZOOM_BASE; // 'x' coordinate of left side of the dirty rectangle
2212 int t = top.y; // 'y' coordinate of top side of the dirty rectangle
2213 int r = top.x + TILE_PIXELS * ZOOM_BASE; // 'x' coordinate of right side of the dirty rectangle
2214 int b = bot.y; // 'y' coordinate of bottom side of the dirty rectangle
2215
2216 static const int OVERLAY_WIDTH = 4 * ZOOM_BASE; // part of selection sprites is drawn outside the selected area (in particular: terraforming)
2217
2218 /* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */
2219 MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH);
2220
2221 /* haven't we reached the topmost tile yet? */
2222 if (top_x != x_start) {
2223 top_x -= TILE_SIZE;
2224 } else {
2225 top_y += TILE_SIZE;
2226 }
2227
2228 /* the way the bottom tile changes is different when we reach the bottommost tile */
2229 if (bot_y != y_end) {
2230 bot_y += TILE_SIZE;
2231 } else {
2232 bot_x -= TILE_SIZE;
2233 }
2234 } while (bot_x >= top_x);
2235 } else { // Selecting in a 45 degrees rotated (diagonal) rectangle.
2236 /* a_size, b_size describe a rectangle with rotated coordinates */
2237 int a_size = x_size + y_size, b_size = x_size - y_size;
2238
2239 int interval_a = a_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE;
2240 int interval_b = b_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE;
2241
2242 for (int a = -interval_a; a != a_size + interval_a; a += interval_a) {
2243 for (int b = -interval_b; b != b_size + interval_b; b += interval_b) {
2244 uint x = (_thd.pos.x + (a + b) / 2) / TILE_SIZE;
2245 uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE;
2246
2247 if (x < Map::MaxX() && y < Map::MaxY()) {
2248 MarkTileDirtyByTile(TileXY(x, y));
2249 }
2250 }
2251 }
2252 }
2253}
2254
2255
2256void SetSelectionRed(bool b)
2257{
2258 _thd.make_square_red = b;
2259 SetSelectionTilesDirty();
2260}
2261
2270 static bool CheckClickOnViewportSign(const Viewport &vp, int x, int y, const ViewportSign *sign)
2271{
2272 bool small = (vp.zoom >= ZoomLevel::Out4x);
2273 int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp.zoom);
2274 int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, vp.zoom);
2275
2276 return y >= sign->top && y < sign->top + sign_height &&
2277 x >= sign->center - sign_half_width && x < sign->center + sign_half_width;
2278}
2279
2280
2288 static bool CheckClickOnViewportSign(const Viewport &vp, int x, int y)
2289{
2290 if (_game_mode == GM_MENU) return false;
2291
2292 x = ScaleByZoom(x - vp.left, vp.zoom) + vp.virtual_left;
2293 y = ScaleByZoom(y - vp.top, vp.zoom) + vp.virtual_top;
2294
2295 Rect search_rect{ x - 1, y - 1, x + 1, y + 1 };
2296 search_rect = ExpandRectWithViewportSignMargins(search_rect, vp.zoom);
2297
2298 bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && !IsInvisibilitySet(TO_SIGNS);
2299 bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && !IsInvisibilitySet(TO_SIGNS);
2300 bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES);
2301 bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS);
2302 bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
2303
2304 /* Topmost of each type that was hit */
2305 BaseStation *st = nullptr, *last_st = nullptr;
2306 Town *t = nullptr, *last_t = nullptr;
2307 Sign *si = nullptr, *last_si = nullptr;
2308
2309 /* See ViewportAddKdtreeSigns() for details on the search logic */
2310 _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) {
2311 switch (item.type) {
2312 case ViewportSignKdtreeItem::VKI_STATION: {
2313 if (!show_stations) break;
2314 st = BaseStation::Get(std::get<StationID>(item.id));
2315 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
2316
2317 StationFacilities facilities = st->facilities;
2318 if (facilities.None()) facilities = STATION_FACILITY_GHOST;
2319 if (!facilities.Any(_facility_display_opt)) break;
2320
2321 if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st;
2322 break;
2323 }
2324
2325 case ViewportSignKdtreeItem::VKI_WAYPOINT:
2326 if (!show_waypoints) break;
2327 st = BaseStation::Get(std::get<StationID>(item.id));
2328 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
2329 if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st;
2330 break;
2331
2332 case ViewportSignKdtreeItem::VKI_TOWN:
2333 if (!show_towns) break;
2334 t = Town::Get(std::get<TownID>(item.id));
2335 if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) last_t = t;
2336 break;
2337
2338 case ViewportSignKdtreeItem::VKI_SIGN:
2339 if (!show_signs) break;
2340 si = Sign::Get(std::get<SignID>(item.id));
2341 if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break;
2342 if (CheckClickOnViewportSign(vp, x, y, &si->sign)) last_si = si;
2343 break;
2344
2345 default:
2346 NOT_REACHED();
2347 }
2348 });
2349
2350 /* Select which hit to handle based on priority */
2351 if (last_st != nullptr) {
2352 if (Station::IsExpected(last_st)) {
2353 ShowStationViewWindow(last_st->index);
2354 } else {
2355 ShowWaypointWindow(Waypoint::From(last_st));
2356 }
2357 return true;
2358 } else if (last_t != nullptr) {
2359 ShowTownViewWindow(last_t->index);
2360 return true;
2361 } else if (last_si != nullptr) {
2362 HandleClickOnSign(last_si);
2363 return true;
2364 } else {
2365 return false;
2366 }
2367}
2368
2369
2370 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id)
2371{
2372 ViewportSignKdtreeItem item;
2373 item.type = VKI_STATION;
2374 item.id = id;
2375
2376 const Station *st = Station::Get(id);
2377 assert(st->sign.kdtree_valid);
2378 item.center = st->sign.center;
2379 item.top = st->sign.top;
2380
2381 /* Assume the sign can be a candidate for drawing, so measure its width */
2382 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, st->sign.width_normal, st->sign.width_small});
2383
2384 return item;
2385}
2386
2387 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id)
2388{
2389 ViewportSignKdtreeItem item;
2390 item.type = VKI_WAYPOINT;
2391 item.id = id;
2392
2393 const Waypoint *st = Waypoint::Get(id);
2394 assert(st->sign.kdtree_valid);
2395 item.center = st->sign.center;
2396 item.top = st->sign.top;
2397
2398 /* Assume the sign can be a candidate for drawing, so measure its width */
2399 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, st->sign.width_normal, st->sign.width_small});
2400
2401 return item;
2402}
2403
2404 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id)
2405{
2406 ViewportSignKdtreeItem item;
2407 item.type = VKI_TOWN;
2408 item.id = id;
2409
2410 const Town *town = Town::Get(id);
2411 assert(town->cache.sign.kdtree_valid);
2412 item.center = town->cache.sign.center;
2413 item.top = town->cache.sign.top;
2414
2415 /* Assume the sign can be a candidate for drawing, so measure its width */
2416 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, town->cache.sign.width_normal, town->cache.sign.width_small});
2417
2418 return item;
2419}
2420
2421 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id)
2422{
2423 ViewportSignKdtreeItem item;
2424 item.type = VKI_SIGN;
2425 item.id = id;
2426
2427 const Sign *sign = Sign::Get(id);
2428 assert(sign->sign.kdtree_valid);
2429 item.center = sign->sign.center;
2430 item.top = sign->sign.top;
2431
2432 /* Assume the sign can be a candidate for drawing, so measure its width */
2433 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, sign->sign.width_normal, sign->sign.width_small});
2434
2435 return item;
2436}
2437
2438void RebuildViewportKdtree()
2439{
2440 /* Reset biggest size sign seen */
2441 _viewport_sign_maxwidth = 0;
2442
2443 std::vector<ViewportSignKdtreeItem> items;
2444 items.reserve(BaseStation::GetNumItems() + Town::GetNumItems() + Sign::GetNumItems());
2445
2446 for (const Station *st : Station::Iterate()) {
2447 if (st->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeStation(st->index));
2448 }
2449
2450 for (const Waypoint *wp : Waypoint::Iterate()) {
2451 if (wp->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeWaypoint(wp->index));
2452 }
2453
2454 for (const Town *town : Town::Iterate()) {
2455 if (town->cache.sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeTown(town->index));
2456 }
2457
2458 for (const Sign *sign : Sign::Iterate()) {
2459 if (sign->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeSign(sign->index));
2460 }
2461
2462 _viewport_sign_kdtree.Build(items.begin(), items.end());
2463}
2464
2465
2466static bool CheckClickOnLandscape(const Viewport &vp, int x, int y)
2467{
2468 Point pt = TranslateXYToTileCoord(vp, x, y);
2469
2470 if (pt.x != -1) return ClickTile(TileVirtXY(pt.x, pt.y));
2471 return true;
2472}
2473
2474static void PlaceObject()
2475{
2476 Point pt;
2477 Window *w;
2478
2479 pt = GetTileBelowCursor();
2480 if (pt.x == -1) return;
2481
2482 if ((_thd.place_mode & HT_DRAG_MASK) == HT_POINT) {
2483 pt.x += TILE_SIZE / 2;
2484 pt.y += TILE_SIZE / 2;
2485 }
2486
2487 _tile_fract_coords.x = pt.x & TILE_UNIT_MASK;
2488 _tile_fract_coords.y = pt.y & TILE_UNIT_MASK;
2489
2490 w = _thd.GetCallbackWnd();
2491 if (w != nullptr) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y));
2492}
2493
2494
2495bool HandleViewportClicked(const Viewport &vp, int x, int y)
2496{
2497 const Vehicle *v = CheckClickOnVehicle(vp, x, y);
2498
2499 if (_thd.place_mode & HT_VEHICLE) {
2500 if (v != nullptr && VehicleClicked(v)) return true;
2501 }
2502
2503 /* Vehicle placement mode already handled above. */
2504 if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
2505 PlaceObject();
2506 return true;
2507 }
2508
2509 if (CheckClickOnViewportSign(vp, x, y)) return true;
2510 bool result = CheckClickOnLandscape(vp, x, y);
2511
2512 if (v != nullptr) {
2513 Debug(misc, 2, "Vehicle {} (index {}) at {}", v->unitnumber, v->index, fmt::ptr(v));
2514 if (IsCompanyBuildableVehicleType(v)) {
2515 v = v->First();
2516 if (_ctrl_pressed && v->owner == _local_company) {
2517 StartStopVehicle(v, true);
2518 } else {
2519 ShowVehicleViewWindow(v);
2520 }
2521 }
2522 return true;
2523 }
2524 return result;
2525}
2526
2527void RebuildViewportOverlay(Window *w)
2528{
2529 if (w->viewport->overlay != nullptr &&
2530 w->viewport->overlay->GetCompanyMask().Any() &&
2531 w->viewport->overlay->GetCargoMask() != 0) {
2532 w->viewport->overlay->SetDirty();
2533 w->SetDirty();
2534 }
2535}
2536
2546 bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant)
2547{
2548 /* The slope cannot be acquired outside of the map, so make sure we are always within the map. */
2549 if (z == -1) {
2550 if ( x >= 0 && x <= (int)Map::SizeX() * (int)TILE_SIZE - 1
2551 && y >= 0 && y <= (int)Map::SizeY() * (int)TILE_SIZE - 1) {
2552 z = GetSlopePixelZ(x, y);
2553 } else {
2554 z = TileHeightOutsideMap(x / (int)TILE_SIZE, y / (int)TILE_SIZE);
2555 }
2556 }
2557
2558 Point pt = MapXYZToViewport(*w->viewport, x, y, z);
2559 w->viewport->CancelFollow(*w);
2560
2561 if (w->viewport->dest_scrollpos_x == pt.x && w->viewport->dest_scrollpos_y == pt.y) return false;
2562
2563 if (instant) {
2564 w->viewport->scrollpos_x = pt.x;
2565 w->viewport->scrollpos_y = pt.y;
2566 RebuildViewportOverlay(w);
2567 }
2568
2569 w->viewport->dest_scrollpos_x = pt.x;
2570 w->viewport->dest_scrollpos_y = pt.y;
2571 return true;
2572}
2573
2581 bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
2582{
2583 return ScrollWindowTo(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, -1, w, instant);
2584}
2585
2592 bool ScrollMainWindowToTile(TileIndex tile, bool instant)
2593{
2594 return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, instant);
2595}
2596
2601 void SetRedErrorSquare(TileIndex tile)
2602{
2603 TileIndex old;
2604
2605 old = _thd.redsq;
2606 _thd.redsq = tile;
2607
2608 if (tile != old) {
2609 if (tile != INVALID_TILE) MarkTileDirtyByTile(tile);
2610 if (old != INVALID_TILE) MarkTileDirtyByTile(old);
2611 }
2612}
2613
2619 void SetTileSelectSize(int w, int h)
2620{
2621 _thd.new_size.x = w * TILE_SIZE;
2622 _thd.new_size.y = h * TILE_SIZE;
2623 _thd.new_outersize.x = 0;
2624 _thd.new_outersize.y = 0;
2625}
2626
2627void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
2628{
2629 _thd.offs.x = ox * TILE_SIZE;
2630 _thd.offs.y = oy * TILE_SIZE;
2631 _thd.new_outersize.x = sx * TILE_SIZE;
2632 _thd.new_outersize.y = sy * TILE_SIZE;
2633}
2634
2636 static HighLightStyle GetAutorailHT(int x, int y)
2637{
2638 return HT_RAIL | _autorail_piece[x & TILE_UNIT_MASK][y & TILE_UNIT_MASK];
2639}
2640
2644 void TileHighlightData::Reset()
2645{
2646 this->pos.x = 0;
2647 this->pos.y = 0;
2648 this->new_pos.x = 0;
2649 this->new_pos.y = 0;
2650}
2651
2656 bool TileHighlightData::IsDraggingDiagonal()
2657{
2658 return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down;
2659}
2660
2665 Window *TileHighlightData::GetCallbackWnd()
2666{
2667 return FindWindowById(this->window_class, this->window_number);
2668}
2669
2670
2671
2679 void UpdateTileSelection()
2680{
2681 int x1;
2682 int y1;
2683
2684 if (_thd.freeze) return;
2685
2686 HighLightStyle new_drawstyle = HT_NONE;
2687 bool new_diagonal = false;
2688
2689 if ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL) {
2690 x1 = _thd.selend.x;
2691 y1 = _thd.selend.y;
2692 if (x1 != -1) {
2693 int x2 = _thd.selstart.x & ~TILE_UNIT_MASK;
2694 int y2 = _thd.selstart.y & ~TILE_UNIT_MASK;
2695 x1 &= ~TILE_UNIT_MASK;
2696 y1 &= ~TILE_UNIT_MASK;
2697
2698 if (_thd.IsDraggingDiagonal()) {
2699 new_diagonal = true;
2700 } else {
2701 if (x1 >= x2) std::swap(x1, x2);
2702 if (y1 >= y2) std::swap(y1, y2);
2703 }
2704 _thd.new_pos.x = x1;
2705 _thd.new_pos.y = y1;
2706 _thd.new_size.x = x2 - x1;
2707 _thd.new_size.y = y2 - y1;
2708 if (!new_diagonal) {
2709 _thd.new_size.x += TILE_SIZE;
2710 _thd.new_size.y += TILE_SIZE;
2711 }
2712 new_drawstyle = _thd.next_drawstyle;
2713 }
2714 } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
2715 Point pt = GetTileBelowCursor();
2716 x1 = pt.x;
2717 y1 = pt.y;
2718 if (x1 != -1) {
2719 switch (_thd.place_mode & HT_DRAG_MASK) {
2720 case HT_RECT:
2721 new_drawstyle = HT_RECT;
2722 break;
2723 case HT_POINT:
2724 new_drawstyle = HT_POINT;
2725 x1 += TILE_SIZE / 2;
2726 y1 += TILE_SIZE / 2;
2727 break;
2728 case HT_RAIL:
2729 /* Draw one highlighted tile in any direction */
2730 new_drawstyle = GetAutorailHT(pt.x, pt.y);
2731 break;
2732 case HT_LINE:
2733 switch (_thd.place_mode & HT_DIR_MASK) {
2734 case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break;
2735 case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break;
2736
2737 case HT_DIR_HU:
2738 case HT_DIR_HL:
2739 new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL;
2740 break;
2741
2742 case HT_DIR_VL:
2743 case HT_DIR_VR:
2744 new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
2745 break;
2746
2747 default: NOT_REACHED();
2748 }
2749 _thd.selstart.x = x1 & ~TILE_UNIT_MASK;
2750 _thd.selstart.y = y1 & ~TILE_UNIT_MASK;
2751 break;
2752 default:
2753 NOT_REACHED();
2754 }
2755 _thd.new_pos.x = x1 & ~TILE_UNIT_MASK;
2756 _thd.new_pos.y = y1 & ~TILE_UNIT_MASK;
2757 }
2758 }
2759
2760 /* redraw selection */
2761 if (_thd.drawstyle != new_drawstyle ||
2762 _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
2763 _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
2764 _thd.outersize.x != _thd.new_outersize.x ||
2765 _thd.outersize.y != _thd.new_outersize.y ||
2766 _thd.diagonal != new_diagonal) {
2767 /* Clear the old tile selection? */
2768 if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
2769
2770 _thd.drawstyle = new_drawstyle;
2771 _thd.pos = _thd.new_pos;
2772 _thd.size = _thd.new_size;
2773 _thd.outersize = _thd.new_outersize;
2774 _thd.diagonal = new_diagonal;
2775 _thd.dirty = 0xff;
2776
2777 /* Draw the new tile selection? */
2778 if ((new_drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
2779 }
2780}
2781
2786 static inline void ShowMeasurementTooltips(EncodedString &&text)
2787{
2788 if (!_settings_client.gui.measure_tooltip) return;
2789 GuiShowTooltips(_thd.GetCallbackWnd(), std::move(text), TCC_EXIT_VIEWPORT);
2790}
2791
2792static void HideMeasurementTooltips()
2793{
2794 CloseWindowById(WC_TOOLTIPS, 0);
2795}
2796
2798 void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
2799{
2800 _thd.select_method = method;
2801 _thd.select_proc = process;
2802 _thd.selend.x = TileX(tile) * TILE_SIZE;
2803 _thd.selstart.x = TileX(tile) * TILE_SIZE;
2804 _thd.selend.y = TileY(tile) * TILE_SIZE;
2805 _thd.selstart.y = TileY(tile) * TILE_SIZE;
2806
2807 /* Needed so several things (road, autoroad, bridges, ...) are placed correctly.
2808 * In effect, placement starts from the centre of a tile
2809 */
2810 if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) {
2811 _thd.selend.x += TILE_SIZE / 2;
2812 _thd.selend.y += TILE_SIZE / 2;
2813 _thd.selstart.x += TILE_SIZE / 2;
2814 _thd.selstart.y += TILE_SIZE / 2;
2815 }
2816
2817 HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
2818 if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) {
2819 _thd.place_mode = HT_SPECIAL | others;
2820 _thd.next_drawstyle = HT_RECT | others;
2821 } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) {
2822 _thd.place_mode = HT_SPECIAL | others;
2823 _thd.next_drawstyle = _thd.drawstyle | others;
2824 } else {
2825 _thd.place_mode = HT_SPECIAL | others;
2826 _thd.next_drawstyle = HT_POINT | others;
2827 }
2828 _special_mouse_mode = WSM_SIZING;
2829}
2830
2832 void VpStartDragging(ViewportDragDropSelectionProcess process)
2833{
2834 _thd.select_method = VPM_X_AND_Y;
2835 _thd.select_proc = process;
2836 _thd.selstart.x = 0;
2837 _thd.selstart.y = 0;
2838 _thd.next_drawstyle = HT_RECT;
2839
2840 _special_mouse_mode = WSM_DRAGGING;
2841}
2842
2843void VpSetPlaceSizingLimit(int limit)
2844{
2845 _thd.sizelimit = limit;
2846}
2847
2853 void VpSetPresizeRange(TileIndex from, TileIndex to)
2854{
2855 uint64_t distance = DistanceManhattan(from, to) + 1;
2856
2857 _thd.selend.x = TileX(to) * TILE_SIZE;
2858 _thd.selend.y = TileY(to) * TILE_SIZE;
2859 _thd.selstart.x = TileX(from) * TILE_SIZE;
2860 _thd.selstart.y = TileY(from) * TILE_SIZE;
2861 _thd.next_drawstyle = HT_RECT;
2862
2863 /* show measurement only if there is any length to speak of */
2864 if (distance > 1) {
2865 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_LENGTH, distance));
2866 } else {
2867 HideMeasurementTooltips();
2868 }
2869}
2870
2871static void VpStartPreSizing()
2872{
2873 _thd.selend.x = -1;
2874 _special_mouse_mode = WSM_PRESIZE;
2875}
2876
2881 static HighLightStyle Check2x1AutoRail(int mode)
2882{
2883 int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
2884 int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK);
2885 int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
2886 int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK);
2887
2888 switch (mode) {
2889 default: NOT_REACHED();
2890 case 0: // end piece is lower right
2891 if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
2892 if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
2893 return HT_DIR_Y;
2894
2895 case 1:
2896 if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
2897 if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
2898 return HT_DIR_Y;
2899
2900 case 2:
2901 if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
2902 if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
2903 return HT_DIR_X;
2904
2905 case 3:
2906 if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
2907 if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
2908 return HT_DIR_X;
2909 }
2910}
2911
2925 static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
2926{
2927 uint start_x = TileX(start_tile);
2928 uint start_y = TileY(start_tile);
2929 uint end_x = TileX(end_tile);
2930 uint end_y = TileY(end_tile);
2931
2932 switch (style & HT_DRAG_MASK) {
2933 case HT_RAIL:
2934 case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y));
2935
2936 case HT_RECT:
2937 case HT_POINT: return (end_x != start_x && end_y < start_y);
2938 default: NOT_REACHED();
2939 }
2940
2941 return false;
2942}
2943
2959 static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
2960{
2961 bool swap = SwapDirection(style, start_tile, end_tile);
2962 uint h0, h1; // Start height and end height.
2963
2964 if (start_tile == end_tile) return 0;
2965 if (swap) std::swap(start_tile, end_tile);
2966
2967 switch (style & HT_DRAG_MASK) {
2968 case HT_RECT:
2969 /* In the case of an area we can determine whether we were dragging south or
2970 * east by checking the X-coordinates of the tiles */
2971 if (TileX(end_tile) > TileX(start_tile)) {
2972 /* Dragging south does not need to change the start tile. */
2973 end_tile = TileAddByDir(end_tile, DIR_S);
2974 } else {
2975 /* Dragging east. */
2976 start_tile = TileAddByDir(start_tile, DIR_SW);
2977 end_tile = TileAddByDir(end_tile, DIR_SE);
2978 }
2979 [[fallthrough]];
2980
2981 case HT_POINT:
2982 h0 = TileHeight(start_tile);
2983 h1 = TileHeight(end_tile);
2984 break;
2985 default: { // All other types, this is mostly only line/autorail
2986 static const HighLightStyle flip_style_direction[] = {
2987 HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL
2988 };
2989 static const std::pair<TileIndexDiffC, TileIndexDiffC> start_heightdiff_line_by_dir[] = {
2990 { {1, 0}, {1, 1} }, // HT_DIR_X
2991 { {0, 1}, {1, 1} }, // HT_DIR_Y
2992 { {1, 0}, {0, 0} }, // HT_DIR_HU
2993 { {1, 0}, {1, 1} }, // HT_DIR_HL
2994 { {1, 0}, {1, 1} }, // HT_DIR_VL
2995 { {0, 1}, {1, 1} }, // HT_DIR_VR
2996 };
2997 static const std::pair<TileIndexDiffC, TileIndexDiffC> end_heightdiff_line_by_dir[] = {
2998 { {0, 1}, {0, 0} }, // HT_DIR_X
2999 { {1, 0}, {0, 0} }, // HT_DIR_Y
3000 { {0, 1}, {0, 0} }, // HT_DIR_HU
3001 { {1, 1}, {0, 1} }, // HT_DIR_HL
3002 { {1, 0}, {0, 0} }, // HT_DIR_VL
3003 { {0, 0}, {0, 1} }, // HT_DIR_VR
3004 };
3005 static_assert(std::size(start_heightdiff_line_by_dir) == HT_DIR_END);
3006 static_assert(std::size(end_heightdiff_line_by_dir) == HT_DIR_END);
3007
3008 distance %= 2; // we're only interested if the distance is even or uneven
3009 style &= HT_DIR_MASK;
3010 assert(style < HT_DIR_END);
3011
3012 /* To handle autorail, we do some magic to be able to use a lookup table.
3013 * Firstly if we drag the other way around, we switch start&end, and if needed
3014 * also flip the drag-position. Eg if it was on the left, and the distance is even
3015 * that means the end, which is now the start is on the right */
3016 if (swap && distance == 0) style = flip_style_direction[style];
3017
3018 /* Lambda to help calculating the height at one side of the line. */
3019 auto get_height = [](auto &tile, auto &heightdiffs) {
3020 return std::max(
3021 TileHeight(TileAdd(tile, ToTileIndexDiff(heightdiffs.first))),
3022 TileHeight(TileAdd(tile, ToTileIndexDiff(heightdiffs.second))));
3023 };
3024
3025 /* Use lookup table for start-tile based on HighLightStyle direction */
3026 h0 = get_height(start_tile, start_heightdiff_line_by_dir[style]);
3027
3028 /* Use lookup table for end-tile based on HighLightStyle direction
3029 * flip around side (lower/upper, left/right) based on distance */
3030 if (distance == 0) style = flip_style_direction[style];
3031 h1 = get_height(end_tile, end_heightdiff_line_by_dir[style]);
3032 break;
3033 }
3034 }
3035
3036 if (swap) std::swap(h0, h1);
3037 return (int)(h1 - h0) * TILE_HEIGHT_STEP;
3038}
3039
3046 static void CheckUnderflow(int &test, int &other, int mult)
3047{
3048 if (test >= 0) return;
3049
3050 other += mult * test;
3051 test = 0;
3052}
3053
3061 static void CheckOverflow(int &test, int &other, int max, int mult)
3062{
3063 if (test <= max) return;
3064
3065 other += mult * (test - max);
3066 test = max;
3067}
3068
3070 static void CalcRaildirsDrawstyle(int x, int y, int method)
3071{
3072 HighLightStyle b;
3073
3074 int dx = _thd.selstart.x - (_thd.selend.x & ~TILE_UNIT_MASK);
3075 int dy = _thd.selstart.y - (_thd.selend.y & ~TILE_UNIT_MASK);
3076 uint w = abs(dx) + TILE_SIZE;
3077 uint h = abs(dy) + TILE_SIZE;
3078
3079 if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) {
3080 /* We 'force' a selection direction; first four rail buttons. */
3081 method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS);
3082 int raw_dx = _thd.selstart.x - _thd.selend.x;
3083 int raw_dy = _thd.selstart.y - _thd.selend.y;
3084 switch (method) {
3085 case VPM_FIX_X:
3086 b = HT_LINE | HT_DIR_Y;
3087 x = _thd.selstart.x;
3088 break;
3089
3090 case VPM_FIX_Y:
3091 b = HT_LINE | HT_DIR_X;
3092 y = _thd.selstart.y;
3093 break;
3094
3095 case VPM_FIX_HORIZONTAL:
3096 if (dx == -dy) {
3097 /* We are on a straight horizontal line. Determine the 'rail'
3098 * to build based the sub tile location. */
3099 b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
3100 } else {
3101 /* We are not on a straight line. Determine the rail to build
3102 * based on whether we are above or below it. */
3103 b = dx + dy >= (int)TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL;
3104
3105 /* Calculate where a horizontal line through the start point and
3106 * a vertical line from the selected end point intersect and
3107 * use that point as the end point. */
3108 int offset = (raw_dx - raw_dy) / 2;
3109 x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK);
3110 y = _thd.selstart.y + (offset & ~TILE_UNIT_MASK);
3111
3112 /* 'Build' the last half rail tile if needed */
3113 if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) {
3114 if (dx + dy >= (int)TILE_SIZE) {
3115 x -= (int)TILE_SIZE;
3116 } else {
3117 y += (int)TILE_SIZE;
3118 }
3119 }
3120
3121 /* Make sure we do not overflow the map! */
3122 CheckUnderflow(x, y, 1);
3123 CheckUnderflow(y, x, 1);
3124 CheckOverflow(x, y, (Map::MaxX() - 1) * TILE_SIZE, 1);
3125 CheckOverflow(y, x, (Map::MaxY() - 1) * TILE_SIZE, 1);
3126 assert(x >= 0 && y >= 0 && x <= (int)(Map::MaxX() * TILE_SIZE) && y <= (int)(Map::MaxY() * TILE_SIZE));
3127 }
3128 break;
3129
3130 case VPM_FIX_VERTICAL:
3131 if (dx == dy) {
3132 /* We are on a straight vertical line. Determine the 'rail'
3133 * to build based the sub tile location. */
3134 b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3135 } else {
3136 /* We are not on a straight line. Determine the rail to build
3137 * based on whether we are left or right from it. */
3138 b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3139
3140 /* Calculate where a vertical line through the start point and
3141 * a horizontal line from the selected end point intersect and
3142 * use that point as the end point. */
3143 int offset = (raw_dx + raw_dy + (int)TILE_SIZE) / 2;
3144 x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK);
3145 y = _thd.selstart.y - (offset & ~TILE_UNIT_MASK);
3146
3147 /* 'Build' the last half rail tile if needed */
3148 if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) {
3149 if (dx < dy) {
3150 y -= (int)TILE_SIZE;
3151 } else {
3152 x -= (int)TILE_SIZE;
3153 }
3154 }
3155
3156 /* Make sure we do not overflow the map! */
3157 CheckUnderflow(x, y, -1);
3158 CheckUnderflow(y, x, -1);
3159 CheckOverflow(x, y, (Map::MaxX() - 1) * TILE_SIZE, -1);
3160 CheckOverflow(y, x, (Map::MaxY() - 1) * TILE_SIZE, -1);
3161 assert(x >= 0 && y >= 0 && x <= (int)(Map::MaxX() * TILE_SIZE) && y <= (int)(Map::MaxY() * TILE_SIZE));
3162 }
3163 break;
3164
3165 default:
3166 NOT_REACHED();
3167 }
3168 } else if (TileVirtXY(_thd.selstart.x, _thd.selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile
3169 if (method & VPM_RAILDIRS) {
3170 b = GetAutorailHT(x, y);
3171 } else { // rect for autosignals on one tile
3172 b = HT_RECT;
3173 }
3174 } else if (h == TILE_SIZE) { // Is this in X direction?
3175 if (dx == (int)TILE_SIZE) { // 2x1 special handling
3176 b = (Check2x1AutoRail(3)) | HT_LINE;
3177 } else if (dx == -(int)TILE_SIZE) {
3178 b = (Check2x1AutoRail(2)) | HT_LINE;
3179 } else {
3180 b = HT_LINE | HT_DIR_X;
3181 }
3182 y = _thd.selstart.y;
3183 } else if (w == TILE_SIZE) { // Or Y direction?
3184 if (dy == (int)TILE_SIZE) { // 2x1 special handling
3185 b = (Check2x1AutoRail(1)) | HT_LINE;
3186 } else if (dy == -(int)TILE_SIZE) { // 2x1 other direction
3187 b = (Check2x1AutoRail(0)) | HT_LINE;
3188 } else {
3189 b = HT_LINE | HT_DIR_Y;
3190 }
3191 x = _thd.selstart.x;
3192 } else if (w > h * 2) { // still count as x dir?
3193 b = HT_LINE | HT_DIR_X;
3194 y = _thd.selstart.y;
3195 } else if (h > w * 2) { // still count as y dir?
3196 b = HT_LINE | HT_DIR_Y;
3197 x = _thd.selstart.x;
3198 } else { // complicated direction
3199 int d = w - h;
3200 _thd.selend.x = _thd.selend.x & ~TILE_UNIT_MASK;
3201 _thd.selend.y = _thd.selend.y & ~TILE_UNIT_MASK;
3202
3203 /* four cases. */
3204 if (x > _thd.selstart.x) {
3205 if (y > _thd.selstart.y) {
3206 /* south */
3207 if (d == 0) {
3208 b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3209 } else if (d >= 0) {
3210 x = _thd.selstart.x + h;
3211 b = HT_LINE | HT_DIR_VL;
3212 } else {
3213 y = _thd.selstart.y + w;
3214 b = HT_LINE | HT_DIR_VR;
3215 }
3216 } else {
3217 /* west */
3218 if (d == 0) {
3219 b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
3220 } else if (d >= 0) {
3221 x = _thd.selstart.x + h;
3222 b = HT_LINE | HT_DIR_HL;
3223 } else {
3224 y = _thd.selstart.y - w;
3225 b = HT_LINE | HT_DIR_HU;
3226 }
3227 }
3228 } else {
3229 if (y > _thd.selstart.y) {
3230 /* east */
3231 if (d == 0) {
3232 b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
3233 } else if (d >= 0) {
3234 x = _thd.selstart.x - h;
3235 b = HT_LINE | HT_DIR_HU;
3236 } else {
3237 y = _thd.selstart.y + w;
3238 b = HT_LINE | HT_DIR_HL;
3239 }
3240 } else {
3241 /* north */
3242 if (d == 0) {
3243 b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3244 } else if (d >= 0) {
3245 x = _thd.selstart.x - h;
3246 b = HT_LINE | HT_DIR_VR;
3247 } else {
3248 y = _thd.selstart.y - w;
3249 b = HT_LINE | HT_DIR_VL;
3250 }
3251 }
3252 }
3253 }
3254
3255 if (_settings_client.gui.measure_tooltip) {
3256 TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
3257 TileIndex t1 = TileVirtXY(x, y);
3258 uint distance = DistanceManhattan(t0, t1) + 1;
3259
3260 if (distance == 1) {
3261 HideMeasurementTooltips();
3262 } else {
3263 int heightdiff = CalcHeightdiff(b, distance, t0, t1);
3264 /* If we are showing a tooltip for horizontal or vertical drags,
3265 * 2 tiles have a length of 1. To bias towards the ceiling we add
3266 * one before division. It feels more natural to count 3 lengths as 2 */
3267 if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) {
3268 distance = CeilDiv(distance, 2);
3269 }
3270
3271 if (heightdiff == 0) {
3272 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_LENGTH, distance));
3273 } else {
3274 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_LENGTH_HEIGHTDIFF, distance, heightdiff));
3275 }
3276 }
3277 }
3278
3279 _thd.selend.x = x;
3280 _thd.selend.y = y;
3281 _thd.next_drawstyle = b;
3282}
3283
3291 void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method)
3292{
3293 int sx, sy;
3294 HighLightStyle style;
3295
3296 if (x == -1) {
3297 _thd.selend.x = -1;
3298 return;
3299 }
3300
3301 /* Special handling of drag in any (8-way) direction */
3302 if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) {
3303 _thd.selend.x = x;
3304 _thd.selend.y = y;
3305 CalcRaildirsDrawstyle(x, y, method);
3306 return;
3307 }
3308
3309 /* Needed so level-land is placed correctly */
3310 if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_POINT) {
3311 x += TILE_SIZE / 2;
3312 y += TILE_SIZE / 2;
3313 }
3314
3315 sx = _thd.selstart.x;
3316 sy = _thd.selstart.y;
3317
3318 int limit = 0;
3319
3320 switch (method) {
3321 case VPM_X_OR_Y: // drag in X or Y direction
3322 if (abs(sy - y) < abs(sx - x)) {
3323 y = sy;
3324 style = HT_DIR_X;
3325 } else {
3326 x = sx;
3327 style = HT_DIR_Y;
3328 }
3329 goto calc_heightdiff_single_direction;
3330
3331 case VPM_X_LIMITED: // Drag in X direction (limited size).
3332 limit = (_thd.sizelimit - 1) * TILE_SIZE;
3333 [[fallthrough]];
3334
3335 case VPM_FIX_X: // drag in Y direction
3336 x = sx;
3337 style = HT_DIR_Y;
3338 goto calc_heightdiff_single_direction;
3339
3340 case VPM_Y_LIMITED: // Drag in Y direction (limited size).
3341 limit = (_thd.sizelimit - 1) * TILE_SIZE;
3342 [[fallthrough]];
3343
3344 case VPM_FIX_Y: // drag in X direction
3345 y = sy;
3346 style = HT_DIR_X;
3347
3348calc_heightdiff_single_direction:;
3349 if (limit > 0) {
3350 x = sx + Clamp(x - sx, -limit, limit);
3351 y = sy + Clamp(y - sy, -limit, limit);
3352 }
3353 if (_settings_client.gui.measure_tooltip) {
3354 TileIndex t0 = TileVirtXY(sx, sy);
3355 TileIndex t1 = TileVirtXY(x, y);
3356 uint distance = DistanceManhattan(t0, t1) + 1;
3357
3358 if (distance == 1) {
3359 HideMeasurementTooltips();
3360 } else {
3361 /* With current code passing a HT_LINE style to calculate the height
3362 * difference is enough. However if/when a point-tool is created
3363 * with this method, function should be called with new_style (below)
3364 * instead of HT_LINE | style case HT_POINT is handled specially
3365 * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
3366 int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1);
3367
3368 if (heightdiff == 0) {
3369 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_LENGTH, distance));
3370 } else {
3371 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_LENGTH_HEIGHTDIFF, distance, heightdiff));
3372 }
3373 }
3374 }
3375 break;
3376
3377 case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area.
3378 limit = (_thd.sizelimit - 1) * TILE_SIZE;
3379 x = sx + Clamp(x - sx, -limit, limit);
3380 y = sy + Clamp(y - sy, -limit, limit);
3381 [[fallthrough]];
3382
3383 case VPM_X_AND_Y: // drag an X by Y area
3384 if (_settings_client.gui.measure_tooltip) {
3385 TileIndex t0 = TileVirtXY(sx, sy);
3386 TileIndex t1 = TileVirtXY(x, y);
3387 uint dx = Delta(TileX(t0), TileX(t1)) + 1;
3388 uint dy = Delta(TileY(t0), TileY(t1)) + 1;
3389
3390 /* If dragging an area (eg dynamite tool) and it is actually a single
3391 * row/column, change the type to 'line' to get proper calculation for height */
3392 style = (HighLightStyle)_thd.next_drawstyle;
3393 if (_thd.IsDraggingDiagonal()) {
3394 /* Determine the "area" of the diagonal dragged selection.
3395 * We assume the area is the number of tiles along the X
3396 * edge and the number of tiles along the Y edge. However,
3397 * multiplying these two numbers does not give the exact
3398 * number of tiles; basically we are counting the black
3399 * squares on a chess board and ignore the white ones to
3400 * make the tile counts at the edges match up. There is no
3401 * other way to make a proper count though.
3402 *
3403 * First convert to the rotated coordinate system. */
3404 int dist_x = TileX(t0) - TileX(t1);
3405 int dist_y = TileY(t0) - TileY(t1);
3406 int a_max = dist_x + dist_y;
3407 int b_max = dist_y - dist_x;
3408
3409 /* Now determine the size along the edge, but due to the
3410 * chess board principle this counts double. */
3411 a_max = abs(a_max + (a_max > 0 ? 2 : -2)) / 2;
3412 b_max = abs(b_max + (b_max > 0 ? 2 : -2)) / 2;
3413
3414 /* We get a 1x1 on normal 2x1 rectangles, due to it being
3415 * a seen as two sides. As the result for actual building
3416 * will be the same as non-diagonal dragging revert to that
3417 * behaviour to give it a more normally looking size. */
3418 if (a_max != 1 || b_max != 1) {
3419 dx = a_max;
3420 dy = b_max;
3421 }
3422 } else if (style & HT_RECT) {
3423 if (dx == 1) {
3424 style = HT_LINE | HT_DIR_Y;
3425 } else if (dy == 1) {
3426 style = HT_LINE | HT_DIR_X;
3427 }
3428 }
3429
3430 if (dx != 1 || dy != 1) {
3431 int heightdiff = CalcHeightdiff(style, 0, t0, t1);
3432
3433 dx -= (style & HT_POINT ? 1 : 0);
3434 dy -= (style & HT_POINT ? 1 : 0);
3435
3436 if (heightdiff == 0) {
3437 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_AREA, dx, dy));
3438 } else {
3439 ShowMeasurementTooltips(GetEncodedString(STR_MEASURE_AREA_HEIGHTDIFF, dx, dy, heightdiff));
3440 }
3441 }
3442 }
3443 break;
3444
3445 default: NOT_REACHED();
3446 }
3447
3448 _thd.selend.x = x;
3449 _thd.selend.y = y;
3450}
3451
3456 EventState VpHandlePlaceSizingDrag()
3457{
3458 if (_special_mouse_mode != WSM_SIZING && _special_mouse_mode != WSM_DRAGGING) return ES_NOT_HANDLED;
3459
3460 /* stop drag mode if the window has been closed */
3461 Window *w = _thd.GetCallbackWnd();
3462 if (w == nullptr) {
3463 ResetObjectToPlace();
3464 return ES_HANDLED;
3465 }
3466
3467 /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
3468 if (_left_button_down) {
3469 if (_special_mouse_mode == WSM_DRAGGING) {
3470 /* Only register a drag event when the mouse moved. */
3471 if (_thd.new_pos.x == _thd.selstart.x && _thd.new_pos.y == _thd.selstart.y) return ES_HANDLED;
3472 _thd.selstart.x = _thd.new_pos.x;
3473 _thd.selstart.y = _thd.new_pos.y;
3474 }
3475
3476 w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
3477 return ES_HANDLED;
3478 }
3479
3480 /* Mouse button released. */
3481 _special_mouse_mode = WSM_NONE;
3482 if (_special_mouse_mode == WSM_DRAGGING) return ES_HANDLED;
3483
3484 /* Keep the selected tool, but reset it to the original mode. */
3485 HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
3486 if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) {
3487 _thd.place_mode = HT_RECT | others;
3488 } else if (_thd.select_method & VPM_SIGNALDIRS) {
3489 _thd.place_mode = HT_RECT | others;
3490 } else if (_thd.select_method & VPM_RAILDIRS) {
3491 _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others);
3492 } else {
3493 _thd.place_mode = HT_POINT | others;
3494 }
3495 SetTileSelectSize(1, 1);
3496
3497 HideMeasurementTooltips();
3498 w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
3499
3500 return ES_HANDLED;
3501}
3502
3510 void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
3511{
3512 SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number);
3513}
3514
3515#include "table/animcursors.h"
3516
3525 void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
3526{
3527 if (_thd.window_class != WC_INVALID) {
3528 /* Undo clicking on button and drag & drop */
3529 Window *w = _thd.GetCallbackWnd();
3530 /* Call the abort function, but set the window class to something
3531 * that will never be used to avoid infinite loops. Setting it to
3532 * the 'next' window class must not be done because recursion into
3533 * this function might in some cases reset the newly set object to
3534 * place or not properly reset the original selection. */
3535 _thd.window_class = WC_INVALID;
3536 if (w != nullptr) {
3537 w->OnPlaceObjectAbort();
3538 HideMeasurementTooltips();
3539 }
3540 }
3541
3542 /* Mark the old selection dirty, in case the selection shape or colour changes */
3543 if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
3544
3545 SetTileSelectSize(1, 1);
3546
3547 _thd.make_square_red = false;
3548
3549 if (mode == HT_DRAG) { // HT_DRAG is for dragdropping trains in the depot window
3550 mode = HT_NONE;
3551 _special_mouse_mode = WSM_DRAGDROP;
3552 } else {
3553 _special_mouse_mode = WSM_NONE;
3554 }
3555
3556 _thd.place_mode = mode;
3557 _thd.window_class = window_class;
3558 _thd.window_number = window_num;
3559
3560 if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode
3561 VpStartPreSizing();
3562 }
3563
3564 if ((icon & ANIMCURSOR_FLAG) != 0) {
3565 SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]);
3566 } else {
3567 SetMouseCursor(icon, pal);
3568 }
3569
3570}
3571
3573 void ResetObjectToPlace()
3574{
3575 SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
3576}
3577
3578 Point GetViewportStationMiddle(const Viewport &vp, const Station *st)
3579{
3580 int x = TileX(st->xy) * TILE_SIZE;
3581 int y = TileY(st->xy) * TILE_SIZE;
3582 int z = GetSlopePixelZ(Clamp(x, 0, Map::SizeX() * TILE_SIZE - 1), Clamp(y, 0, Map::SizeY() * TILE_SIZE - 1));
3583
3584 Point p = RemapCoords(x, y, z);
3585 p.x = UnScaleByZoom(p.x - vp.virtual_left, vp.zoom) + vp.left;
3586 p.y = UnScaleByZoom(p.y - vp.virtual_top, vp.zoom) + vp.top;
3587 return p;
3588}
3589
3591 struct ViewportSSCSS {
3592 VpSorterChecker fct_checker;
3593 VpSpriteSorter fct_sorter;
3594};
3595
3597 static const ViewportSSCSS _vp_sprite_sorters[] = {
3598#ifdef WITH_SSE
3599 { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
3600#endif
3601 { &ViewportSortParentSpritesChecker, &ViewportSortParentSprites }
3602};
3603
3605 void InitializeSpriteSorter()
3606{
3607 for (const auto &sprite_sorter : _vp_sprite_sorters) {
3608 if (sprite_sorter.fct_checker()) {
3609 _vp_sprite_sorter = sprite_sorter.fct_sorter;
3610 break;
3611 }
3612 }
3613 assert(_vp_sprite_sorter != nullptr);
3614}
3615
3624 CommandCost CmdScrollViewport(DoCommandFlags flags, TileIndex tile, ViewportScrollTarget target, uint32_t ref)
3625{
3626 if (_current_company != OWNER_DEITY) return CMD_ERROR;
3627 switch (target) {
3628 case VST_EVERYONE:
3629 break;
3630 case VST_COMPANY:
3631 if (_local_company != (CompanyID)ref) return CommandCost();
3632 break;
3633 case VST_CLIENT:
3634 if (_network_own_client_id != (ClientID)ref) return CommandCost();
3635 break;
3636 default:
3637 return CMD_ERROR;
3638 }
3639
3640 if (flags.Test(DoCommandFlag::Execute)) {
3641 ResetObjectToPlace();
3642 ScrollMainWindowToTile(tile);
3643 }
3644 return CommandCost();
3645}
3646
3647void MarkCatchmentTilesDirty()
3648{
3649 if (_viewport_highlight_town != nullptr) {
3650 MarkWholeScreenDirty();
3651 return;
3652 }
3653
3654 if (_viewport_highlight_station != nullptr) {
3655 if (_viewport_highlight_station->catchment_tiles.tile == INVALID_TILE) {
3656 MarkWholeScreenDirty();
3657 _viewport_highlight_station = nullptr;
3658 } else {
3659 BitmapTileIterator it(_viewport_highlight_station->catchment_tiles);
3660 for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
3661 MarkTileDirtyByTile(tile);
3662 }
3663 }
3664 }
3665
3666 if (_viewport_highlight_station_rect != nullptr) {
3667 if (!_viewport_highlight_station_rect->IsInUse()) {
3668 _viewport_highlight_station_rect = nullptr;
3669 }
3670 MarkWholeScreenDirty();
3671 }
3672
3673 if (_viewport_highlight_waypoint != nullptr) {
3674 if (!_viewport_highlight_waypoint->IsInUse()) {
3675 _viewport_highlight_waypoint = nullptr;
3676 }
3677 MarkWholeScreenDirty();
3678 }
3679
3680 if (_viewport_highlight_waypoint_rect != nullptr) {
3681 if (!_viewport_highlight_waypoint_rect->IsInUse()) {
3682 _viewport_highlight_waypoint_rect = nullptr;
3683 }
3684 MarkWholeScreenDirty();
3685 }
3686}
3687
3688static void SetWindowDirtyForViewportCatchment()
3689{
3690 if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index);
3691 if (_viewport_highlight_station_rect != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station_rect->index);
3692 if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index);
3693 if (_viewport_highlight_waypoint_rect != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint_rect->index);
3694 if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index);
3695}
3696
3697static void ClearViewportCatchment()
3698{
3699 MarkCatchmentTilesDirty();
3700 _viewport_highlight_station = nullptr;
3701 _viewport_highlight_station_rect = nullptr;
3702 _viewport_highlight_waypoint = nullptr;
3703 _viewport_highlight_waypoint_rect = nullptr;
3704 _viewport_highlight_town = nullptr;
3705}
3706
3713 void SetViewportCatchmentStation(const Station *st, bool sel)
3714{
3715 SetWindowDirtyForViewportCatchment();
3716 /* Mark tiles dirty for redrawing and update selected station if a different station is already highlighted. */
3717 if (sel && _viewport_highlight_station != st) {
3718 ClearViewportCatchment();
3719 _viewport_highlight_station = st;
3720 MarkCatchmentTilesDirty();
3721 /* Mark tiles dirty for redrawing and clear station selection if deselecting highlight. */
3722 } else if (!sel && _viewport_highlight_station == st) {
3723 MarkCatchmentTilesDirty();
3724 _viewport_highlight_station = nullptr;
3725 }
3726 /* Redraw the currently selected station window */
3727 if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index);
3728}
3729
3736 void SetViewportStationRect(const Station *st, bool sel)
3737{
3738 SetWindowDirtyForViewportCatchment();
3739 /* Mark tiles dirty for redrawing and update selected station if a different station is already highlighted. */
3740 if (sel && _viewport_highlight_station_rect != st) {
3741 ClearViewportCatchment();
3742 _viewport_highlight_station_rect = st;
3743 MarkCatchmentTilesDirty();
3744 /* Mark tiles dirty for redrawing and clear station selection if deselecting highlight. */
3745 } else if (!sel && _viewport_highlight_station_rect == st) {
3746 MarkCatchmentTilesDirty();
3747 _viewport_highlight_station_rect = nullptr;
3748 }
3749 /* Redraw the currently selected station window */
3750 if (_viewport_highlight_station_rect != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station_rect->index);
3751}
3752
3759 void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel)
3760{
3761 SetWindowDirtyForViewportCatchment();
3762 /* Mark tiles dirty for redrawing and update selected waypoint if a different waypoint is already highlighted. */
3763 if (sel && _viewport_highlight_waypoint != wp) {
3764 ClearViewportCatchment();
3765 _viewport_highlight_waypoint = wp;
3766 MarkCatchmentTilesDirty();
3767 /* Mark tiles dirty for redrawing and clear waypoint selection if deselecting highlight. */
3768 } else if (!sel && _viewport_highlight_waypoint == wp) {
3769 MarkCatchmentTilesDirty();
3770 _viewport_highlight_waypoint = nullptr;
3771 }
3772 /* Redraw the currently selected waypoint window */
3773 if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index);
3774}
3775
3782 void SetViewportWaypointRect(const Waypoint *wp, bool sel)
3783{
3784 SetWindowDirtyForViewportCatchment();
3785 /* Mark tiles dirty for redrawing and update selected waypoint if a different waypoint is already highlighted. */
3786 if (sel && _viewport_highlight_waypoint_rect != wp) {
3787 ClearViewportCatchment();
3788 _viewport_highlight_waypoint_rect = wp;
3789 MarkCatchmentTilesDirty();
3790 /* Mark tiles dirty for redrawing and clear waypoint selection if deselecting highlight. */
3791 } else if (!sel && _viewport_highlight_waypoint_rect == wp) {
3792 MarkCatchmentTilesDirty();
3793 _viewport_highlight_waypoint_rect = nullptr;
3794 }
3795 /* Redraw the currently selected waypoint window */
3796 if (_viewport_highlight_waypoint_rect != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint_rect->index);
3797}
3798
3805 void SetViewportCatchmentTown(const Town *t, bool sel)
3806{
3807 SetWindowDirtyForViewportCatchment();
3808 /* Mark tiles dirty for redrawing and update selected town if a different town is already highlighted. */
3809 if (sel && _viewport_highlight_town != t) {
3810 ClearViewportCatchment();
3811 _viewport_highlight_town = t;
3812 MarkWholeScreenDirty();
3813 /* Mark tiles dirty for redrawing and clear town selection if deselecting highlight. */
3814 } else if (!sel && _viewport_highlight_town == t) {
3815 _viewport_highlight_town = nullptr;
3816 MarkWholeScreenDirty();
3817 }
3818 /* Redraw the currently selected town window */
3819 if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index);
3820}
3821
3826 void ViewportData::CancelFollow(const Window &viewport_window)
3827{
3828 if (this->follow_vehicle == VehicleID::Invalid()) return;
3829
3830 if (viewport_window.window_class == WC_MAIN_WINDOW) {
3831 /* We're cancelling follow in the main viewport, so we need to check for a vehicle view window
3832 * to raise the location follow widget. */
3833 Window *vehicle_window = FindWindowById(WC_VEHICLE_VIEW, this->follow_vehicle);
3834 if (vehicle_window != nullptr) vehicle_window->RaiseWidgetWhenLowered(WID_VV_LOCATION);
3835 }
3836
3837 this->follow_vehicle = VehicleID::Invalid();
3838}
animcursors.h
This file defines all the the animated cursors.
_animcursors
static constexpr std::span< const AnimCursor > _animcursors[]
This is an array of pointers to all the animated cursor definitions we have above.
Definition animcursors.h:67
autorail.h
Highlight/sprite information for autorail.
backup_type.hpp
Class for backupping variables and making sure they are restored later.
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
HasBit
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
GetNorthernBridgeEnd
TileIndex GetNorthernBridgeEnd(TileIndex t)
Finds the northern end of a bridge starting at a middle tile.
Definition bridge_map.cpp:39
bridge_map.h
Map accessor functions for bridges.
GetBridgePixelHeight
int GetBridgePixelHeight(TileIndex tile)
Get the height ('z') of a bridge in pixels.
Definition bridge_map.h:84
IsBridgeAbove
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
BaseBitSet::Set
constexpr Timpl & Set()
Set all bits.
Definition base_bitset_type.hpp:40
BitmapTileIterator
Iterator to iterate over all tiles belonging to a bitmaptilearea.
Definition bitmap_type.h:106
BlitterFactory::GetCurrentBlitter
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:136
Blitter
How all blitters should look like.
Definition base.hpp:29
Blitter::MoveTo
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...
Blitter::SetPixel
virtual void SetPixel(void *video, int x, int y, PixelColour colour)=0
Draw a pixel with a given colour on the video-buffer.
CommandCost
Common return value for all commands.
Definition command_type.h:24
EncodedString
Container for an encoded string, created by GetEncodedString.
Definition strings_type.h:98
EnumBitSet< ViewportStringFlag, uint8_t >
Kdtree
K-dimensional tree, specialised for 2-dimensional space.
Definition kdtree.hpp:33
Kdtree::Build
void Build(It begin, It end)
Clear and rebuild the tree from a new sequence of elements,.
Definition kdtree.hpp:360
Kdtree::Count
size_t Count() const
Get number of elements stored in tree.
Definition kdtree.hpp:428
Kdtree::FindContained
void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, const Outputter &outputter) const
Find all items contained within the given rectangle.
Definition kdtree.hpp:457
Kdtree::FindNearest
T FindNearest(CoordT x, CoordT y) const
Find the element closest to given coordinate, in Manhattan distance.
Definition kdtree.hpp:439
PerformanceAccumulator
RAII class for measuring multi-step elements of performance.
Definition framerate_type.h:113
WidgetDimensions
Definition window_gui.h:32
WidgetDimensions::scaled
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
WidgetDimensions::fullbevel
RectPadding fullbevel
Always-scaled bevel thickness.
Definition window_gui.h:39
command_func.h
Functions related to commands.
CMD_ERROR
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition command_func.h:28
DoCommandFlag::Execute
@ Execute
execute the given command
company_base.h
Definition of stuff that is very close to a company, like the company struct itself.
_company_colours
TypedIndexContainer< std::array< Colours, MAX_COMPANIES >, CompanyID > _company_colours
NOSAVE: can be determined from company structs.
Definition company_cmd.cpp:57
_local_company
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition company_cmd.cpp:55
_current_company
CompanyID _current_company
Company currently doing an action.
Definition company_cmd.cpp:56
company_func.h
Functions related to companies.
OWNER_DEITY
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
Definition company_type.h:28
OWNER_NONE
static constexpr Owner OWNER_NONE
The tile has no ownership.
Definition company_type.h:26
Debug
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
DIR_SW
@ DIR_SW
Southwest.
Definition direction_type.h:31
DIR_SE
@ DIR_SE
Southeast.
Definition direction_type.h:29
DIR_S
@ DIR_S
South.
Definition direction_type.h:30
to_underlying
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
factory.hpp
Factory to 'query' all available blitters.
GetCharacterHeight
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
framerate_type.h
Types for recording game performance data.
PFE_DRAWWORLD
@ PFE_DRAWWORLD
Time spent drawing world viewports in GUI.
Definition framerate_type.h:57
SetMouseCursor
void SetMouseCursor(CursorID sprite, PaletteID pal)
Assign a single non-animated sprite to the cursor.
Definition gfx.cpp:1703
_left_button_down
bool _left_button_down
Is left mouse button pressed?
Definition gfx.cpp:41
GetStringBoundingBox
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:894
DrawString
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:665
_ctrl_pressed
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
SetAnimatedMouseCursor
void SetAnimatedMouseCursor(std::span< const AnimCursor > table)
Assign an animation to the cursor.
Definition gfx.cpp:1716
DrawSpriteViewport
void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
Draw a sprite in a viewport.
Definition gfx.cpp:1003
DrawBox
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:422
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
SpriteType::Normal
@ Normal
The most basic (normal) sprite.
FS_SMALL
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
CursorID
uint32_t CursorID
The number of the cursor (sprite)
Definition gfx_type.h:19
SA_HOR_CENTER
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:389
PaletteID
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
TextColour
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
MarkAllViewportsDirty
bool 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:2094
Window::SetDirty
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:966
AddDirtyBlock
void AddDirtyBlock(int left, int top, int right, int bottom)
Extend the internal _invalid_rect rectangle to contain the rectangle defined by the given parameters.
Definition gfx.cpp:1513
ViewportSign::MarkDirty
void MarkDirty(ZoomLevel maxzoom=ZoomLevel::Max) const
Mark the sign dirty in all viewports.
Definition viewport.cpp:1555
MarkViewportDirty
static bool 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:2055
MarkWholeScreenDirty
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1546
RedrawScreenRect
void RedrawScreenRect(int left, int top, int right, int bottom)
Repaints a specific rectangle of the screen.
Definition gfx.cpp:1423
MarkTileDirtyByTile
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:2128
SetSelectionTilesDirty
static void SetSelectionTilesDirty()
Marks the selected tiles as dirty.
Definition viewport.cpp:2145
_tile_type_procs
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition landscape.cpp:68
InverseRemapCoords2
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:114
GetSlopePixelZ
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition landscape.cpp:306
landscape.h
Functions related to OTTD's landscape.
RemapCoords
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:81
RemapCoords2
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:97
InverseRemapCoords
Point InverseRemapCoords(int x, int y)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition landscape.h:111
linkgraph_gui.h
Declaration of linkgraph overlay GUI.
DoZoomInOutWindow
bool DoZoomInOutWindow(ZoomStateChange how, Window *w)
Zooms a viewport in a window in or out.
Definition main_gui.cpp:93
DistanceManhattan
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:158
TileVirtXY
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:416
TileAddByDir
TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition map_func.h:611
ToTileIndexDiff
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:452
TileXY
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:385
TileY
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:437
TileX
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:427
TileAdd
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:469
IsInsideBS
constexpr 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:252
IsInsideMM
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition math_func.hpp:267
abs
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
Align
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition math_func.hpp:37
CeilDiv
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition math_func.hpp:310
Delta
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
Definition math_func.hpp:234
Clamp
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
GuiShowTooltips
void GuiShowTooltips(Window *parent, EncodedString &&text, TooltipCloseCondition close_tooltip)
Shows a tooltip.
Definition misc_gui.cpp:693
_network_own_client_id
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:71
network_func.h
Network functions used by other parts of OpenTTD.
ClientID
ClientID
'Unique' identifier to be given to clients
Definition network_type.h:43
DO_SHOW_TOWN_NAMES
@ DO_SHOW_TOWN_NAMES
Display town names.
Definition openttd.h:46
DO_SHOW_COMPETITOR_SIGNS
@ DO_SHOW_COMPETITOR_SIGNS
Display signs, station names and waypoint names of opponent companies. Buoys and oilrig-stations are ...
Definition openttd.h:52
DO_SHOW_SIGNS
@ DO_SHOW_SIGNS
Display signs.
Definition openttd.h:48
DO_SHOW_WAYPOINT_NAMES
@ DO_SHOW_WAYPOINT_NAMES
Display waypoint names.
Definition openttd.h:51
DO_SHOW_STATION_NAMES
@ DO_SHOW_STATION_NAMES
Display station names.
Definition openttd.h:47
GetColourGradient
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:388
safeguards.h
A number of safeguards to prevent using unsafe methods.
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
signs_base.h
Base class for signs.
signs_func.h
Functions related to signs.
HandleClickOnSign
void HandleClickOnSign(const Sign *si)
Handle clicking on a sign.
Definition signs_gui.cpp:572
SlopeWithThreeCornersRaised
Slope SlopeWithThreeCornersRaised(Corner corner)
Returns the slope with all except one corner raised.
Definition slope_func.h:206
OppositeCorner
Corner OppositeCorner(Corner corner)
Returns the opposite corner.
Definition slope_func.h:184
GetHalftileSlopeCorner
static constexpr Corner GetHalftileSlopeCorner(Slope s)
Returns the leveled halftile of a halftile slope.
Definition slope_func.h:148
RemoveHalftileSlope
static constexpr Slope RemoveHalftileSlope(Slope s)
Removes a halftile slope from a slope.
Definition slope_func.h:60
SlopeToSpriteOffset
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition slope_func.h:415
IsSteepSlope
static constexpr bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition slope_func.h:36
IsHalftileSlope
static constexpr bool IsHalftileSlope(Slope s)
Checks for non-continuous slope on halftile foundations.
Definition slope_func.h:47
SlopeWithOneCornerRaised
Slope SlopeWithOneCornerRaised(Corner corner)
Returns the slope with a specific corner raised.
Definition slope_func.h:99
Corner
Corner
Enumeration of tile corners.
Definition slope_type.h:22
Slope
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
SLOPE_N
@ SLOPE_N
the north corner of the tile is raised
Definition slope_type.h:53
SLOPE_STEEP_N
@ SLOPE_STEEP_N
a steep slope falling to south (from north)
Definition slope_type.h:69
ScrollMainWindowTo
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
Definition smallmap_gui.cpp:2078
MAX_SPRITES
static constexpr uint32_t MAX_SPRITES
Masks needed for sprite operations.
Definition sprites.h:1569
PALETTE_TILE_RED_PULSATING
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:1583
ANIMCURSOR_FLAG
static const CursorID ANIMCURSOR_FLAG
Flag for saying a cursor sprite is an animated cursor.
Definition sprites.h:1521
PALETTE_SEL_TILE_RED
static const PaletteID PALETTE_SEL_TILE_RED
makes a square red. is used when removing rails or other stuff
Definition sprites.h:1584
SPRITE_MASK
static constexpr uint32_t SPRITE_MASK
The mask to for the main sprite.
Definition sprites.h:1570
PALETTE_MODIFIER_TRANSPARENT
static constexpr uint8_t PALETTE_MODIFIER_TRANSPARENT
when a sprite is to be displayed transparently, this bit needs to be set.
Definition sprites.h:1561
PALETTE_CRASH
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1619
SPR_CURSOR_MOUSE
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition sprites.h:1404
PALETTE_SEL_TILE_BLUE
static const PaletteID PALETTE_SEL_TILE_BLUE
This draws a blueish square (catchment areas for example)
Definition sprites.h:1585
PALETTE_TO_TRANSPARENT
static const PaletteID PALETTE_TO_TRANSPARENT
This sets the sprite to transparent.
Definition sprites.h:1616
station_base.h
Base classes/functions for stations.
ShowStationViewWindow
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
Definition station_gui.cpp:2174
GetStationIndex
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
string_colours.h
The colour translation of GRF's strings.
_string_colourmap
static constexpr PixelColour _string_colourmap[17]
Colour mapping for TextColour.
Definition string_colours.h:11
GetEncodedString
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
strings_func.h
Functions related to OTTD's strings.
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:19
AutoRestoreBackup
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Definition backup_type.hpp:150
BaseStation
Base class for all station-ish types.
Definition base_station_base.h:58
BaseStation::xy
TileIndex xy
Base tile of the station.
Definition base_station_base.h:59
BaseStation::rect
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Definition base_station_base.h:84
BaseStation::IsInUse
bool IsInUse() const
Check whether the base station currently is in use; in use means that it is not scheduled for deletio...
Definition base_station_base.h:171
BaseStation::sign
TrackedViewportSign sign
NOSAVE: Dimensions of sign.
Definition base_station_base.h:60
ChildScreenSpriteToDraw
Definition viewport.cpp:133
ChildScreenSpriteToDraw::next
int next
next child to draw (-1 at the end)
Definition viewport.cpp:140
ChildScreenSpriteToDraw::sub
const SubSprite * sub
only draw a rectangular part of the sprite
Definition viewport.cpp:136
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition settings_type.h:650
ConstructionSettings::max_bridge_height
uint8_t max_bridge_height
maximum height of bridges
Definition settings_type.h:414
Coord2D< int >
Coord2D::y
T y
Y coordinate.
Definition geometry_type.hpp:35
Coord2D::x
T x
X coordinate.
Definition geometry_type.hpp:34
Coord3D::x
T x
X coordinate.
Definition geometry_type.hpp:44
Coord3D::y
T y
Y coordinate.
Definition geometry_type.hpp:45
Coord3D::z
T z
Z coordinate.
Definition geometry_type.hpp:46
CursorVars::pos
Point pos
logical mouse position
Definition gfx_type.h:125
DrawPixelInfo
Data about how and where to blit pixels.
Definition gfx_type.h:157
EconomySettings::dist_local_authority
uint8_t dist_local_authority
distance for town local authority, default 20
Definition settings_type.h:545
GUISettings::population_in_label
bool population_in_label
show the population of a town in its label?
Definition settings_type.h:201
GUISettings::measure_tooltip
bool measure_tooltip
show a permanent tooltip when dragging tools
Definition settings_type.h:181
GUISettings::zoom_min
ZoomLevel zoom_min
minimum zoom out level
Definition settings_type.h:191
GUISettings::smooth_scroll
bool smooth_scroll
smooth scroll viewports
Definition settings_type.h:180
GUISettings::zoom_max
ZoomLevel zoom_max
maximum zoom out level
Definition settings_type.h:192
GameSettings::economy
EconomySettings economy
settings to change the economy
Definition settings_type.h:642
GameSettings::construction
ConstructionSettings construction
construction of things in-game
Definition settings_type.h:635
Map::SizeX
static uint SizeX()
Get the size of the map along the X.
Definition map_func.h:272
Map::SizeY
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:281
Map::ScaleBySize1D
static uint ScaleBySize1D(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:353
Map::MaxY
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:308
Map::MaxX
static uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:299
OrthogonalTileArea::tile
TileIndex tile
The base tile of the area.
Definition tilearea_type.h:19
ParentSpriteToDraw
Parent sprite that should be drawn.
Definition viewport_sprite_sorter.h:16
ParentSpriteToDraw::sub
const SubSprite * sub
only draw a rectangular part of the sprite
Definition viewport_sprite_sorter.h:31
ParentSpriteToDraw::zmin
int32_t zmin
minimal world Z coordinate of bounding box
Definition viewport_sprite_sorter.h:20
ParentSpriteToDraw::image
SpriteID image
sprite to draw
Definition viewport_sprite_sorter.h:29
ParentSpriteToDraw::xmax
int32_t xmax
maximal world X coordinate of bounding box
Definition viewport_sprite_sorter.h:24
ParentSpriteToDraw::ymax
int32_t ymax
maximal world Y coordinate of bounding box
Definition viewport_sprite_sorter.h:25
ParentSpriteToDraw::x
int32_t x
screen X coordinate of sprite
Definition viewport_sprite_sorter.h:21
ParentSpriteToDraw::y
int32_t y
screen Y coordinate of sprite
Definition viewport_sprite_sorter.h:27
ParentSpriteToDraw::first_child
int32_t first_child
the first child to draw.
Definition viewport_sprite_sorter.h:36
ParentSpriteToDraw::zmax
int32_t zmax
maximal world Z coordinate of bounding box
Definition viewport_sprite_sorter.h:26
ParentSpriteToDraw::xmin
int32_t xmin
minimal world X coordinate of bounding box
Definition viewport_sprite_sorter.h:18
ParentSpriteToDraw::ymin
int32_t ymin
minimal world Y coordinate of bounding box
Definition viewport_sprite_sorter.h:19
ParentSpriteToDraw::pal
PaletteID pal
palette to use
Definition viewport_sprite_sorter.h:30
ParentSpriteToDraw::left
int32_t left
minimal screen X coordinate of sprite (= x + sprite->x_offs), reference point for child sprites
Definition viewport_sprite_sorter.h:33
ParentSpriteToDraw::top
int32_t top
minimal screen Y coordinate of sprite (= y + sprite->y_offs), reference point for child sprites
Definition viewport_sprite_sorter.h:34
PixelColour
Colour for pixel/line drawing.
Definition gfx_type.h:405
PoolID< uint16_t, struct TownIDTag, 64000, 0xFFFF >
Pool::PoolItem<&_vehicle_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem<&_station_pool >::GetNumItems
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition pool_type.hpp:417
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition geometry_type.hpp:101
Sign
Definition signs_base.h:21
SpecializedStation< Station, false >::IsExpected
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
Definition base_station_base.h:229
SpecializedStation< Station, false >::Get
static Station * Get(auto index)
Gets station with given index.
Definition base_station_base.h:248
SpecializedStation< Waypoint, true >::From
static Waypoint * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
Definition base_station_base.h:277
SpriteBounds
Definition sprite.h:18
SpriteBounds::offset
Coord3D< int8_t > offset
Relative position of sprite from bounding box.
Definition sprite.h:21
SpriteBounds::origin
Coord3D< int8_t > origin
Position of northern corner within tile.
Definition sprite.h:19
SpriteBounds::extent
Coord3D< uint8_t > extent
Size of bounding box.
Definition sprite.h:20
Sprite
Data structure describing a sprite.
Definition spritecache_type.h:16
Sprite::width
uint16_t width
Width of the sprite.
Definition spritecache_type.h:18
Sprite::height
uint16_t height
Height of the sprite.
Definition spritecache_type.h:17
Sprite::y_offs
int16_t y_offs
Number of pixels to shift the sprite downwards.
Definition spritecache_type.h:20
Sprite::x_offs
int16_t x_offs
Number of pixels to shift the sprite to the right.
Definition spritecache_type.h:19
StationRect
StationRect - used to track station spread out rectangle - cheaper than scanning whole map.
Definition base_station_base.h:36
StationRect::PtInExtendedRect
bool PtInExtendedRect(int x, int y, int distance=0) const
Determines whether a given point (x, y) is within a certain distance of the station rectangle.
Definition station.cpp:564
Station
Station data structure.
Definition station_base.h:500
Station::catchment_tiles
BitmapTileArea catchment_tiles
NOSAVE: Set of individual tiles covered by catchment area.
Definition station_base.h:520
StringSpriteToDraw
Definition viewport.cpp:116
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
SubSprite
Used to only draw a part of the sprite.
Definition gfx_type.h:278
TileHighlightData
Metadata about the current highlighting.
Definition tilehighlight_type.h:46
TileHighlightData::redsq
TileIndex redsq
The tile that has to get a red selection.
Definition tilehighlight_type.h:72
TileHighlightData::new_pos
Point new_pos
New value for pos; used to determine whether to redraw the selection.
Definition tilehighlight_type.h:55
TileHighlightData::GetCallbackWnd
Window * GetCallbackWnd()
Get the window that started the current highlighting.
Definition viewport.cpp:2665
TileHighlightData::make_square_red
bool make_square_red
Whether to give a tile a red selection.
Definition tilehighlight_type.h:71
TileHighlightData::IsDraggingDiagonal
bool IsDraggingDiagonal()
Is the user dragging a 'diagonal rectangle'?
Definition viewport.cpp:2656
TileHighlightData::select_proc
ViewportDragDropSelectionProcess select_proc
The procedure that has to be called when the selection is done.
Definition tilehighlight_type.h:75
TileHighlightData::selstart
Point selstart
The location where the dragging started.
Definition tilehighlight_type.h:60
TileHighlightData::new_outersize
Point new_outersize
New value for outersize; used to determine whether to redraw the selection.
Definition tilehighlight_type.h:57
TileHighlightData::drawstyle
HighLightStyle drawstyle
Lower bits 0-3 are reserved for detailed highlight information.
Definition tilehighlight_type.h:64
TileHighlightData::place_mode
HighLightStyle place_mode
Method which is used to place the selection.
Definition tilehighlight_type.h:67
TileHighlightData::window_class
WindowClass window_class
The WindowClass of the window that is responsible for the selection mode.
Definition tilehighlight_type.h:68
TileHighlightData::dirty
uint8_t dirty
Whether the build station window needs to redraw due to the changed selection.
Definition tilehighlight_type.h:58
TileHighlightData::offs
Point offs
Offset, in tile "units", for the blue coverage area from the selected area's northern tile.
Definition tilehighlight_type.h:49
TileHighlightData::size
Point size
Size, in tile "units", of the white/red selection area.
Definition tilehighlight_type.h:48
TileHighlightData::sizelimit
uint8_t sizelimit
Whether the selection is limited in length, and what the maximum length is.
Definition tilehighlight_type.h:62
TileHighlightData::pos
Point pos
Location, in tile "units", of the northern tile of the selected area.
Definition tilehighlight_type.h:47
TileHighlightData::outersize
Point outersize
Size, in tile "units", of the blue coverage area excluding the side of the selected area.
Definition tilehighlight_type.h:50
TileHighlightData::diagonal
bool diagonal
Whether the dragged area is a 45 degrees rotated rectangle.
Definition tilehighlight_type.h:51
TileHighlightData::Reset
void Reset()
Reset tile highlighting.
Definition viewport.cpp:2644
TileHighlightData::selend
Point selend
The location where the drag currently ends.
Definition tilehighlight_type.h:61
TileHighlightData::new_size
Point new_size
New value for size; used to determine whether to redraw the selection.
Definition tilehighlight_type.h:56
TileHighlightData::freeze
bool freeze
Freeze highlight in place.
Definition tilehighlight_type.h:53
TileHighlightData::next_drawstyle
HighLightStyle next_drawstyle
Queued, but not yet drawn style.
Definition tilehighlight_type.h:65
TileHighlightData::select_method
ViewportPlaceMethod select_method
The method which governs how tiles are selected.
Definition tilehighlight_type.h:74
TileHighlightData::window_number
WindowNumber window_number
The WindowNumber of the window that is responsible for the selection mode.
Definition tilehighlight_type.h:69
TileInfo
Tile information, used while rendering the tile.
Definition tile_cmd.h:30
TileInfo::tileh
Slope tileh
Slope of the tile.
Definition tile_cmd.h:31
TileInfo::tile
TileIndex tile
Tile index.
Definition tile_cmd.h:32
TileSpriteToDraw
Definition viewport.cpp:125
TileSpriteToDraw::y
int32_t y
screen Y coordinate of sprite
Definition viewport.cpp:130
TileSpriteToDraw::x
int32_t x
screen X coordinate of sprite
Definition viewport.cpp:129
TileSpriteToDraw::sub
const SubSprite * sub
only draw a rectangular part of the sprite
Definition viewport.cpp:128
TileTypeProcs::draw_tile_proc
DrawTileProc * draw_tile_proc
Called to render the tile and its contents to the screen.
Definition tile_cmd.h:153
TownCache::sign
TrackedViewportSign sign
Location of name sign, UpdateVirtCoord updates this.
Definition town.h:54
Town
Town data structure.
Definition town.h:63
Town::xy
TileIndex xy
town center tile
Definition town.h:64
Town::cache
TownCache cache
Container for all cacheable data.
Definition town.h:66
Town::show_zone
bool show_zone
NOSAVE: mark town to show the local authority zone in the viewports.
Definition town.h:153
Town::stations_near
StationList stations_near
NOSAVE: List of nearby stations.
Definition town.h:140
TrackedViewportSign::kdtree_valid
bool kdtree_valid
Are the sign data valid for use with the _viewport_sign_kdtree?
Definition viewport_type.h:61
Vehicle
Vehicle data structure.
Definition vehicle_base.h:205
Vehicle::z_pos
int32_t z_pos
z coordinate.
Definition vehicle_base.h:267
Vehicle::First
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Definition vehicle_base.h:600
Vehicle::y_pos
int32_t y_pos
y coordinate.
Definition vehicle_base.h:266
Vehicle::x_pos
int32_t x_pos
x coordinate.
Definition vehicle_base.h:265
Vehicle::owner
Owner owner
Which company owns the vehicle?
Definition vehicle_base.h:270
Vehicle::unitnumber
UnitID unitnumber
unit number, for display purposes only
Definition vehicle_base.h:281
ViewportData
Data structure for a window viewport.
Definition window_gui.h:251
ViewportData::CancelFollow
void CancelFollow(const Window &viewport_window)
Cancel viewport vehicle following, and raise follow location widget if needed.
Definition viewport.cpp:3826
ViewportData::dest_scrollpos_y
int32_t dest_scrollpos_y
Current destination y coordinate to display (virtual screen coordinate of topleft corner of the viewp...
Definition window_gui.h:256
ViewportData::scrollpos_y
int32_t scrollpos_y
Currently shown y coordinate (virtual screen coordinate of topleft corner of the viewport).
Definition window_gui.h:254
ViewportData::dest_scrollpos_x
int32_t dest_scrollpos_x
Current destination x coordinate to display (virtual screen coordinate of topleft corner of the viewp...
Definition window_gui.h:255
ViewportData::follow_vehicle
VehicleID follow_vehicle
VehicleID to follow if following a vehicle, VehicleID::Invalid() otherwise.
Definition window_gui.h:252
ViewportData::scrollpos_x
int32_t scrollpos_x
Currently shown x coordinate (virtual screen coordinate of topleft corner of the viewport).
Definition window_gui.h:253
ViewportDrawer
Data structure storing rendering information.
Definition viewport.cpp:170
ViewportDrawer::foundation
int foundation[FOUNDATION_PART_END]
Foundation sprites (index into parent_sprites_to_draw).
Definition viewport.cpp:183
ViewportDrawer::last_foundation_child
int last_foundation_child[FOUNDATION_PART_END]
Tail of ChildSprite list of the foundations. (index into child_screen_sprites_to_draw)
Definition viewport.cpp:185
ViewportDrawer::parent_sprites_to_sort
ParentSpriteToSortVector parent_sprites_to_sort
Parent sprite pointer array used for sorting.
Definition viewport.cpp:176
ViewportDrawer::foundation_offset
Point foundation_offset[FOUNDATION_PART_END]
Pixel offset for ground sprites on the foundations.
Definition viewport.cpp:186
ViewportDrawer::combine_sprites
SpriteCombineMode combine_sprites
Current mode of "sprite combining".
Definition viewport.cpp:181
ViewportDrawer::foundation_part
FoundationPart foundation_part
Currently active foundation for ground sprite drawing.
Definition viewport.cpp:184
ViewportSSCSS
Helper class for getting the best sprite sorter.
Definition viewport.cpp:3591
ViewportSSCSS::fct_checker
VpSorterChecker fct_checker
The check function.
Definition viewport.cpp:3592
ViewportSSCSS::fct_sorter
VpSpriteSorter fct_sorter
The sorting function.
Definition viewport.cpp:3593
ViewportSignKdtreeItem
Definition viewport_kdtree.h:19
ViewportSign
Location information about a sign as seen on the viewport.
Definition viewport_type.h:47
ViewportSign::center
int32_t center
The center position of the sign.
Definition viewport_type.h:48
ViewportSign::width_small
uint16_t width_small
The width when zoomed out (small font)
Definition viewport_type.h:51
ViewportSign::width_normal
uint16_t width_normal
The width when not zoomed out (normal font)
Definition viewport_type.h:50
ViewportSign::UpdatePosition
void UpdatePosition(int center, int top, std::string_view str, std::string_view str_small={})
Update the position of the viewport sign.
Definition viewport.cpp:1533
ViewportSign::top
int32_t top
The top of the sign.
Definition viewport_type.h:49
Viewport
Data structure for viewport, display of a part of the world.
Definition viewport_type.h:31
Viewport::top
int top
Screen coordinate top edge of the viewport.
Definition viewport_type.h:33
Viewport::width
int width
Screen width of the viewport.
Definition viewport_type.h:34
Viewport::zoom
ZoomLevel zoom
The zoom level of the viewport.
Definition viewport_type.h:42
Viewport::virtual_top
int virtual_top
Virtual top coordinate.
Definition viewport_type.h:38
Viewport::virtual_left
int virtual_left
Virtual left coordinate.
Definition viewport_type.h:37
Viewport::virtual_width
int virtual_width
width << zoom
Definition viewport_type.h:39
Viewport::left
int left
Screen coordinate left edge of the viewport.
Definition viewport_type.h:32
Viewport::height
int height
Screen height of the viewport.
Definition viewport_type.h:35
Viewport::virtual_height
int virtual_height
height << zoom
Definition viewport_type.h:40
Waypoint
Representation of a waypoint.
Definition waypoint_base.h:23
WindowNumber
Number to differentiate different windows of the same class.
Definition window_type.h:760
Window::WindowIterator
Iterator to iterate all valid Windows.
Definition window_gui.h:875
Window
Data structure for an opened window.
Definition window_gui.h:274
Window::SetWidgetDirty
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:556
Window::viewport
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
Window::RaiseWidgetWhenLowered
void RaiseWidgetWhenLowered(WidgetID widget_index)
Marks a widget as raised and dirty (redraw), when it is marked as lowered.
Definition window_gui.h:479
Window::OnPlaceObjectAbort
virtual void OnPlaceObjectAbort()
The user cancelled a tile highlight mode that has been set.
Definition window_gui.h:822
Window::window_class
WindowClass window_class
Window class.
Definition window_gui.h:302
Window::DrawViewport
void DrawViewport() const
Draw the viewport of this window.
Definition viewport.cpp:1903
Window::OnPlaceObject
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:801
Window::left
int left
x position of left edge of the window
Definition window_gui.h:310
Window::top
int top
y position of top edge of the window
Definition window_gui.h:311
Window::OnPlaceMouseUp
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:843
Window::OnPlaceDrag
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:832
Window::SetWidgetDisabledState
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
Window::Iterate
AllWindows< false > Iterate
Iterate all windows in whatever order is easiest.
Definition window_gui.h:933
Window::height
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:313
Window::width
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
Window::window_number
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
GetTilePixelSlopeOutsideMap
std::tuple< Slope, int > GetTilePixelSlopeOutsideMap(int x, int y)
Return the slope of a given tile, also for tiles outside the map (virtual "black" tiles).
Definition tile_map.cpp:78
IsTileType
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
TileHeight
static uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
GetTilePixelZ
int GetTilePixelZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.h:302
GetTileMaxPixelZ
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
GetTilePixelSlope
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
IsValidTile
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TilePixelHeight
uint TilePixelHeight(Tile tile)
Returns the height of a tile in pixels.
Definition tile_map.h:72
TilePixelHeightOutsideMap
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
GetTileType
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
TileHeightOutsideMap
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
TILE_UNIT_MASK
static constexpr uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
MAX_BUILDING_PIXELS
static constexpr uint MAX_BUILDING_PIXELS
Maximum height of a building in pixels in ZOOM_BASE. (Also applies to "bridge buildings" on the bridg...
Definition tile_type.h:20
INVALID_TILE
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
TILE_SIZE
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
TILE_PIXELS
static constexpr uint TILE_PIXELS
Pixel distance between tile columns/rows in ZOOM_BASE.
Definition tile_type.h:17
TILE_HEIGHT
static constexpr uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
TileType
TileType
The different types of tiles.
Definition tile_type.h:47
MP_STATION
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
MP_HOUSE
@ MP_HOUSE
A house by a town.
Definition tile_type.h:51
MP_VOID
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
tilehighlight_func.h
Functions related to tile highlights.
HighLightStyle
HighLightStyle
Highlighting draw styles.
Definition tilehighlight_type.h:19
HT_LINE
@ HT_LINE
used for autorail highlighting (longer stretches), lower bits: direction
Definition tilehighlight_type.h:25
HT_DIR_HL
@ HT_DIR_HL
horizontal lower
Definition tilehighlight_type.h:36
HT_DIR_HU
@ HT_DIR_HU
horizontal upper
Definition tilehighlight_type.h:35
HT_DRAG
@ HT_DRAG
dragging items in the depot windows
Definition tilehighlight_type.h:24
HT_NONE
@ HT_NONE
default
Definition tilehighlight_type.h:20
HT_DIR_X
@ HT_DIR_X
X direction.
Definition tilehighlight_type.h:33
HT_DIAGONAL
@ HT_DIAGONAL
Also allow 'diagonal rectangles'. Only usable in combination with HT_RECT or HT_POINT.
Definition tilehighlight_type.h:28
HT_POINT
@ HT_POINT
point (lower land, raise land, level land, ...)
Definition tilehighlight_type.h:22
HT_RECT
@ HT_RECT
rectangle (stations, depots, ...)
Definition tilehighlight_type.h:21
HT_DIR_MASK
@ HT_DIR_MASK
masks the drag-direction
Definition tilehighlight_type.h:40
HT_RAIL
@ HT_RAIL
autorail (one piece), lower bits: direction
Definition tilehighlight_type.h:26
HT_DIR_END
@ HT_DIR_END
end marker
Definition tilehighlight_type.h:39
HT_DRAG_MASK
@ HT_DRAG_MASK
Mask for the tile drag-type modes.
Definition tilehighlight_type.h:29
HT_DIR_VL
@ HT_DIR_VL
vertical left
Definition tilehighlight_type.h:37
HT_VEHICLE
@ HT_VEHICLE
vehicle is accepted as target as well (bitmask)
Definition tilehighlight_type.h:27
HT_DIR_VR
@ HT_DIR_VR
vertical right
Definition tilehighlight_type.h:38
HT_SPECIAL
@ HT_SPECIAL
special mode used for highlighting while dragging (and for tunnels/docks)
Definition tilehighlight_type.h:23
HT_DIR_Y
@ HT_DIR_Y
Y direction.
Definition tilehighlight_type.h:34
town.h
Base of the town class.
ClosestTownFromTile
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:3952
town_kdtree.h
Declarations for accessing the k-d tree of towns.
GetTownIndex
TownID GetTownIndex(Tile t)
Get the index of which town this house/street is attached to.
Definition town_map.h:23
IsTransparencySet
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
Definition transparency.h:50
_display_opt
uint8_t _display_opt
What do we want to draw/do?
Definition transparency_gui.cpp:26
IsInvisibilitySet
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
Definition transparency.h:61
TO_SIGNS
@ TO_SIGNS
signs
Definition transparency.h:24
ViewportAddVehicles
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition vehicle.cpp:1121
CheckClickOnVehicle
Vehicle * CheckClickOnVehicle(const Viewport &vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition vehicle.cpp:1215
vehicle_base.h
Base class for all vehicles.
vehicle_func.h
Functions related to vehicles.
IsCompanyBuildableVehicleType
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
Definition vehicle_func.h:228
ShowVehicleViewWindow
void ShowVehicleViewWindow(const Vehicle *v)
Shows the vehicle view window of the given vehicle.
Definition vehicle_gui.cpp:3432
VehicleClicked
bool VehicleClicked(const Vehicle *v)
Dispatch a "vehicle selected" event if any window waits for it.
Definition vehicle_gui.cpp:3442
StartStopVehicle
void StartStopVehicle(const Vehicle *v, bool texteffect)
Executes CMD_START_STOP_VEHICLE for given vehicle.
Definition vehicle_gui.cpp:2938
vehicle_gui.h
Functions related to the vehicle's GUIs.
vehicle_widget.h
Types related to the vehicle widgets.
WID_VV_LOCATION
@ WID_VV_LOCATION
Center the main view on this vehicle.
Definition vehicle_widget.h:19
HighlightTownLocalAuthorityTiles
static void HighlightTownLocalAuthorityTiles(const TileInfo *ti)
Highlights tiles inside local authority of selected towns.
Definition viewport.cpp:1086
ViewportAddString
std::string * ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sign, ViewportStringFlags flags, Colours colour)
Add a string to draw in the current viewport.
Definition viewport.cpp:1330
CheckOverflow
static void CheckOverflow(int &test, int &other, int max, int mult)
Check for overflowing the map.
Definition viewport.cpp:3061
ScrollWindowToTile
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
Definition viewport.cpp:2581
FoundationPart
FoundationPart
Enumeration of multi-part foundations.
Definition viewport.cpp:144
FOUNDATION_PART_NONE
@ FOUNDATION_PART_NONE
Neither foundation nor groundsprite drawn yet.
Definition viewport.cpp:145
FOUNDATION_PART_HALFTILE
@ FOUNDATION_PART_HALFTILE
Second part (halftile foundation)
Definition viewport.cpp:147
FOUNDATION_PART_NORMAL
@ FOUNDATION_PART_NORMAL
First part (normal foundation or no foundation)
Definition viewport.cpp:146
SetTileSelectSize
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
Definition viewport.cpp:2619
CmdScrollViewport
CommandCost CmdScrollViewport(DoCommandFlags flags, TileIndex tile, ViewportScrollTarget target, uint32_t ref)
Scroll players main viewport.
Definition viewport.cpp:3624
ViewportAddStationStrings
static void ViewportAddStationStrings(DrawPixelInfo *dpi, const std::vector< const BaseStation * > &stations, bool small)
Add station strings to a viewport.
Definition viewport.cpp:1425
OffsetGroundSprite
void OffsetGroundSprite(int x, int y)
Called when a foundation has been drawn for the current tile.
Definition viewport.cpp:591
LAST_CHILD_NONE
constexpr int LAST_CHILD_NONE
There is no last_child to fill.
Definition viewport.cpp:166
ResetObjectToPlace
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition viewport.cpp:3573
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition viewport.cpp:2592
ViewportAddSignStrings
static void ViewportAddSignStrings(DrawPixelInfo *dpi, const std::vector< const Sign * > &signs, bool small)
Add sign strings to a viewport.
Definition viewport.cpp:1401
SetObjectToPlaceWnd
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:3510
LAST_CHILD_PARENT
constexpr int LAST_CHILD_PARENT
Fill last_child of the most recent parent sprite.
Definition viewport.cpp:167
MAX_TILE_EXTENT_TOP
static const int MAX_TILE_EXTENT_TOP
Maximum top extent of tile relative to north corner (not considering bridges).
Definition viewport.cpp:113
SetViewportStationRect
void SetViewportStationRect(const Station *st, bool sel)
Select or deselect station for rectangle area highlight.
Definition viewport.cpp:3736
ShowMeasurementTooltips
static void ShowMeasurementTooltips(EncodedString &&text)
Displays the measurement tooltips when selecting multiple tiles.
Definition viewport.cpp:2786
MAX_TILE_EXTENT_LEFT
static const int MAX_TILE_EXTENT_LEFT
Maximum left extent of tile relative to north corner.
Definition viewport.cpp:111
IsInsideRotatedRectangle
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:801
CalcHeightdiff
static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
Calculates height difference between one tile and another.
Definition viewport.cpp:2959
DrawTileSelectionRect
static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal)
Draws a selection rectangle on a tile.
Definition viewport.cpp:914
StartSpriteCombine
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:764
InitializeSpriteSorter
void InitializeSpriteSorter()
Choose the "best" sprite sorter and set _vp_sprite_sorter.
Definition viewport.cpp:3605
_vp_sprite_sorters
static const ViewportSSCSS _vp_sprite_sorters[]
List of sorters ordered from best to worst.
Definition viewport.cpp:3597
AddCombinedSprite
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:623
GetViewportY
static int GetViewportY(Point tile)
Returns the y coordinate in the viewport coordinate system where the given tile is painted.
Definition viewport.cpp:1201
AddChildSpriteToFoundation
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:532
GetAutorailHT
static HighLightStyle GetAutorailHT(int x, int y)
returns the best autorail highlight type from map coordinates
Definition viewport.cpp:2636
ClampSmoothScroll
static void ClampSmoothScroll(uint32_t delta_ms, int64_t delta_hi, int64_t delta_lo, int &delta_hi_clamped, int &delta_lo_clamped)
Clamp the smooth scroll to a maxmimum speed and distance based on time elapsed.
Definition viewport.cpp:1960
DrawTileSelection
static void DrawTileSelection(const TileInfo *ti)
Checks if the specified tile is selected and if so draws selection using correct selectionstyle.
Definition viewport.cpp:1120
GetTileHighlightType
static TileHighlightType GetTileHighlightType(TileIndex t)
Get tile highlight type of coverage area for a given tile.
Definition viewport.cpp:1022
IsInRangeInclusive
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:789
_viewport_highlight_waypoint_rect
const Waypoint * _viewport_highlight_waypoint_rect
Currently selected waypoint for rectangle highlight.
Definition viewport.cpp:1014
TranslateXYToTileCoord
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:430
DrawAutorailSelection
static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
Draws autorail highlights.
Definition viewport.cpp:974
SpriteCombineMode
SpriteCombineMode
Mode of "sprite combining".
Definition viewport.cpp:155
SPRITE_COMBINE_PENDING
@ SPRITE_COMBINE_PENDING
Sprite combining will start with the next unclipped sprite.
Definition viewport.cpp:157
SPRITE_COMBINE_ACTIVE
@ SPRITE_COMBINE_ACTIVE
Sprite combining is active. AddSortableSpriteToDraw outputs child sprites.
Definition viewport.cpp:158
SPRITE_COMBINE_NONE
@ SPRITE_COMBINE_NONE
Every AddSortableSpriteToDraw start its own bounding box.
Definition viewport.cpp:156
DrawTileHighlightType
static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht)
Draw tile highlight for coverage area highlight.
Definition viewport.cpp:1071
ViewportDrawBoundingBoxes
static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
Draws the bounding boxes of all ParentSprites.
Definition viewport.cpp:1738
ViewportAddTownStrings
static void ViewportAddTownStrings(DrawPixelInfo *dpi, const std::vector< const Town * > &towns, bool small)
Add town strings to a viewport.
Definition viewport.cpp:1372
SetViewportCatchmentWaypoint
void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel)
Select or deselect waypoint for coverage area highlight.
Definition viewport.cpp:3759
SetRedErrorSquare
void SetRedErrorSquare(TileIndex tile)
Set a tile to display a red error square.
Definition viewport.cpp:2601
ViewportSortParentSprites
static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
Sort parent sprites pointer array replicating the way original sorter did it.
Definition viewport.cpp:1596
VpSetPresizeRange
void VpSetPresizeRange(TileIndex from, TileIndex to)
Highlights all tiles between a set of two tiles.
Definition viewport.cpp:2853
VpSelectTilesWithMethod
void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method)
Selects tiles while dragging.
Definition viewport.cpp:3291
VpHandlePlaceSizingDrag
EventState VpHandlePlaceSizingDrag()
Handle the mouse while dragging for placement/resizing.
Definition viewport.cpp:3456
IsPtInWindowViewport
Viewport * IsPtInWindowViewport(const Window *w, int x, int y)
Is a xy position inside the viewport of the window?
Definition viewport.cpp:408
AddSortableSpriteToDraw
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:663
SetObjectToPlace
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:3525
EndSpriteCombine
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:774
MAX_TILE_EXTENT_RIGHT
static const int MAX_TILE_EXTENT_RIGHT
Maximum right extent of tile relative to north corner.
Definition viewport.cpp:112
AddChildSpriteScreen
void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale, bool relative)
Add a child sprite to a parent sprite.
Definition viewport.cpp:824
CheckUnderflow
static void CheckUnderflow(int &test, int &other, int mult)
Check for underflowing the map.
Definition viewport.cpp:3046
ViewportSortParentSpritesChecker
static bool ViewportSortParentSpritesChecker()
This fallback sprite checker always exists.
Definition viewport.cpp:1590
DrawGroundSpriteAt
void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32_t x, int32_t 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:556
VpStartDragging
void VpStartDragging(ViewportDragDropSelectionProcess process)
Drag over the map while holding the left mouse down.
Definition viewport.cpp:2832
UpdateTileSelection
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition viewport.cpp:2679
DrawSelectionSprite
static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part, int extra_offs_x=0, int extra_offs_y=0)
Draws sprites between ground sprite and everything above.
Definition viewport.cpp:897
MAX_TILE_EXTENT_BOTTOM
static const int MAX_TILE_EXTENT_BOTTOM
Maximum bottom extent of tile relative to north corner (worst case: SLOPE_STEEP_N).
Definition viewport.cpp:114
CheckClickOnViewportSign
static bool CheckClickOnViewportSign(const Viewport &vp, int x, int y, const ViewportSign *sign)
Test whether a sign is below the mouse.
Definition viewport.cpp:2270
SetViewportCatchmentStation
void SetViewportCatchmentStation(const Station *st, bool sel)
Select or deselect station for coverage area highlight.
Definition viewport.cpp:3713
SetViewportCatchmentTown
void SetViewportCatchmentTown(const Town *t, bool sel)
Select or deselect town for coverage area highlight.
Definition viewport.cpp:3805
SwapDirection
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:2925
InitializeWindowViewport
void InitializeWindowViewport(Window *w, int x, int y, int width, int height, std::variant< TileIndex, VehicleID > focus, ZoomLevel zoom)
Initialize viewport of the window for use.
Definition viewport.cpp:218
DrawGroundSprite
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:579
CalcRaildirsDrawstyle
static void CalcRaildirsDrawstyle(int x, int y, int method)
while dragging
Definition viewport.cpp:3070
Check2x1AutoRail
static HighLightStyle Check2x1AutoRail(int mode)
returns information about the 2x1 piece to be build.
Definition viewport.cpp:2881
SetViewportWaypointRect
void SetViewportWaypointRect(const Waypoint *wp, bool sel)
Select or deselect waypoint for rectangle area highlight.
Definition viewport.cpp:3782
ViewportDrawDirtyBlocks
static void ViewportDrawDirtyBlocks()
Draw/colour the blocks that have been redrawn.
Definition viewport.cpp:1756
HandleZoomMessage
void HandleZoomMessage(Window *w, const Viewport &vp, WidgetID widget_zoom_in, WidgetID widget_zoom_out)
Update the status of the zoom-buttons according to the zoom-level of the viewport.
Definition viewport.cpp:486
VpStartPlaceSizing
void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
highlighting tiles while only going over them with the mouse
Definition viewport.cpp:2798
_viewport_highlight_station_rect
const Station * _viewport_highlight_station_rect
Currently selected station for rectangle highlight.
Definition viewport.cpp:1012
ClampViewportToMap
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:1928
AddTileSpriteToDraw
static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32_t x, int32_t 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:507
ViewportAddLandscape
static void ViewportAddLandscape()
Add the landscape to the viewport, i.e.
Definition viewport.cpp:1210
AddStringToDraw
static std::string & AddStringToDraw(int x, int y, Colours colour, ViewportStringFlags flags, uint16_t width)
Add a string to draw to a viewport.
Definition viewport.cpp:870
_viewport_highlight_station
const Station * _viewport_highlight_station
Currently selected station for coverage area highlight.
Definition viewport.cpp:1011
_viewport_highlight_town
const Town * _viewport_highlight_town
Currently selected town for coverage area highlight.
Definition viewport.cpp:1015
UpdateViewportPosition
void UpdateViewportPosition(Window *w, uint32_t delta_ms)
Update the viewport position being displayed.
Definition viewport.cpp:1988
_viewport_highlight_waypoint
const Waypoint * _viewport_highlight_waypoint
Currently selected waypoint for coverage area highlight.
Definition viewport.cpp:1013
ScrollWindowTo
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:2546
viewport_cmd.h
Command definitions related to viewports.
viewport_func.h
Functions related to (drawing on) viewports.
TILE_HEIGHT_STEP
static const int TILE_HEIGHT_STEP
One Z unit tile height difference is displayed as 50m.
Definition viewport_func.h:21
viewport_sprite_sorter.h
Types related to sprite sorting.
VpSorterChecker
bool(* VpSorterChecker)()
Type for method for checking whether a viewport sprite sorter exists.
Definition viewport_sprite_sorter.h:43
VpSpriteSorter
void(* VpSpriteSorter)(ParentSpriteToSortVector *psd)
Type for the actual viewport sprite sorter.
Definition viewport_sprite_sorter.h:45
ViewportScrollTarget
ViewportScrollTarget
Target of the viewport scrolling GS method.
Definition viewport_type.h:152
VST_EVERYONE
@ VST_EVERYONE
All players.
Definition viewport_type.h:153
VST_COMPANY
@ VST_COMPANY
All players in specific company.
Definition viewport_type.h:154
VST_CLIENT
@ VST_CLIENT
Single player.
Definition viewport_type.h:155
ViewportPlaceMethod
ViewportPlaceMethod
Viewport place method (type of highlighted area and placed objects)
Definition viewport_type.h:96
VPM_FIX_Y
@ VPM_FIX_Y
drag only in Y axis
Definition viewport_type.h:99
VPM_Y_LIMITED
@ VPM_Y_LIMITED
Drag only in Y axis with limited size.
Definition viewport_type.h:105
VPM_X_AND_Y_LIMITED
@ VPM_X_AND_Y_LIMITED
area of land of limited size
Definition viewport_type.h:101
VPM_FIX_VERTICAL
@ VPM_FIX_VERTICAL
drag only in vertical direction
Definition viewport_type.h:103
VPM_X_LIMITED
@ VPM_X_LIMITED
Drag only in X axis with limited size.
Definition viewport_type.h:104
VPM_X_AND_Y
@ VPM_X_AND_Y
area of land in X and Y directions
Definition viewport_type.h:100
VPM_FIX_HORIZONTAL
@ VPM_FIX_HORIZONTAL
drag only in horizontal direction
Definition viewport_type.h:102
VPM_FIX_X
@ VPM_FIX_X
drag only in X axis
Definition viewport_type.h:98
VPM_SIGNALDIRS
@ VPM_SIGNALDIRS
similar to VMP_RAILDIRS, but with different cursor
Definition viewport_type.h:107
VPM_X_OR_Y
@ VPM_X_OR_Y
drag in X or Y direction
Definition viewport_type.h:97
VPM_RAILDIRS
@ VPM_RAILDIRS
all rail directions
Definition viewport_type.h:106
ZOOM_IN
@ ZOOM_IN
Zoom in (get more detailed view).
Definition viewport_type.h:81
ZOOM_OUT
@ ZOOM_OUT
Zoom out (get helicopter view).
Definition viewport_type.h:82
ViewportDragDropSelectionProcess
ViewportDragDropSelectionProcess
Drag and drop selection process, or, what to do with an area of land when you've selected it.
Definition viewport_type.h:115
ViewportStringFlag::ColourRect
@ ColourRect
Draw a colour rect around the sign.
ViewportStringFlag::Small
@ Small
Draw using the small font.
ViewportStringFlag::Shadow
@ Shadow
Draw an extra text shadow. Should only be used with ViewportStringFlag::Small, as normal font already...
ViewportStringFlag::TransparentRect
@ TransparentRect
Draw a transparent rect around the sign.
ViewportStringFlag::TextColour
@ TextColour
Draw text in colour.
waypoint_base.h
Base of waypoints.
waypoint_func.h
Functions related to waypoints.
ShowWaypointWindow
void ShowWaypointWindow(const Waypoint *wp)
Show the window for the given waypoint.
Definition waypoint_gui.cpp:232
DrawFrameRect
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:289
CloseWindowById
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1193
GetMainWindow
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1180
FindWindowFromPt
Window * FindWindowFromPt(int x, int y)
Do a search for a window at specific coordinates.
Definition window.cpp:1842
_special_mouse_mode
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition window.cpp:96
FindWindowById
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1151
SetWindowDirty
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3176
window_func.h
Window functions not directly related to making/drawing windows.
window_gui.h
Functions, definitions and such used only by the GUI.
FrameFlag::Transparent
@ Transparent
Makes the background transparent if set.
WSM_DRAGDROP
@ WSM_DRAGDROP
Drag&drop an object.
Definition window_gui.h:1042
WSM_DRAGGING
@ WSM_DRAGGING
Dragging mode (trees).
Definition window_gui.h:1045
WSM_PRESIZE
@ WSM_PRESIZE
Presizing mode (docks, tunnels).
Definition window_gui.h:1044
WSM_NONE
@ WSM_NONE
No special mouse mode.
Definition window_gui.h:1041
WSM_SIZING
@ WSM_SIZING
Sizing mode.
Definition window_gui.h:1043
WidgetID
int WidgetID
Widget ID.
Definition window_type.h:20
EventState
EventState
State of handling an event.
Definition window_type.h:780
ES_HANDLED
@ ES_HANDLED
The passed event is handled.
Definition window_type.h:781
ES_NOT_HANDLED
@ ES_NOT_HANDLED
The passed event is not handled.
Definition window_type.h:782
WindowClass
WindowClass
Window classes.
Definition window_type.h:49
WC_INVALID
@ WC_INVALID
Invalid window.
Definition window_type.h:735
WC_WAYPOINT_VIEW
@ WC_WAYPOINT_VIEW
Waypoint view; Window numbers:
Definition window_type.h:362
WC_STATION_VIEW
@ WC_STATION_VIEW
Station view; Window numbers:
Definition window_type.h:350
WC_MAIN_WINDOW
@ WC_MAIN_WINDOW
Main window; Window numbers:
Definition window_type.h:56
WC_TOWN_VIEW
@ WC_TOWN_VIEW
Town view; Window numbers:
Definition window_type.h:338
WC_TOOLTIPS
@ WC_TOOLTIPS
Tooltip window; Window numbers:
Definition window_type.h:121
WC_VEHICLE_VIEW
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition window_type.h:344
zoom_func.h
Functions related to zooming.
ScaleByZoom
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:22
UnScaleByZoomLower
int UnScaleByZoomLower(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min)
Definition zoom_func.h:67
UnScaleByZoom
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:34
ZoomLevel
ZoomLevel
All zoom levels we know.
Definition zoom_type.h:20
ZoomLevel::Begin
@ Begin
Begin for iteration.
ZoomLevel::Min
@ Min
Minimum zoom level.
ZoomLevel::End
@ End
End for iteration.
ZoomLevel::Out4x
@ Out4x
Zoomed 4 times out.