OpenTTD Source: src/viewport.cpp Source File

OpenTTD Source 15.0-beta1

viewport.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
63#include "stdafx.h"
64#include "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 "table/strings.h"
98#include "table/string_colours.h"
99
100#include "safeguards.h"
101
102 Point _tile_fract_coords;
103
104
105 ViewportSignKdtree _viewport_sign_kdtree{};
106static int _viewport_sign_maxwidth = 0;
107
108
109 static const int MAX_TILE_EXTENT_LEFT = ZOOM_BASE * TILE_PIXELS;
110 static const int MAX_TILE_EXTENT_RIGHT = ZOOM_BASE * TILE_PIXELS;
111 static const int MAX_TILE_EXTENT_TOP = ZOOM_BASE * MAX_BUILDING_PIXELS;
112 static const int MAX_TILE_EXTENT_BOTTOM = ZOOM_BASE * (TILE_PIXELS + 2 * TILE_HEIGHT);
113
114 struct StringSpriteToDraw {
115 std::string string;
116 StringID string_id;
117 Colours colour;
118 int32_t x;
119 int32_t y;
120 uint16_t width;
121};
122
123 struct TileSpriteToDraw {
124 SpriteID image;
125 PaletteID pal;
126 const SubSprite *sub;
127 int32_t x;
128 int32_t y;
129};
130
131 struct ChildScreenSpriteToDraw {
132 SpriteID image;
133 PaletteID pal;
134 const SubSprite *sub;
135 int32_t x;
136 int32_t y;
137 bool relative;
138 int next;
139};
140
142 enum FoundationPart {
143 FOUNDATION_PART_NONE = 0xFF,
144 FOUNDATION_PART_NORMAL = 0,
145 FOUNDATION_PART_HALFTILE = 1,
146 FOUNDATION_PART_END
147};
148
153 enum SpriteCombineMode {
154 SPRITE_COMBINE_NONE,
155 SPRITE_COMBINE_PENDING,
156 SPRITE_COMBINE_ACTIVE,
157};
158
159typedef std::vector<TileSpriteToDraw> TileSpriteToDrawVector;
160typedef std::vector<StringSpriteToDraw> StringSpriteToDrawVector;
161typedef std::vector<ParentSpriteToDraw> ParentSpriteToDrawVector;
162typedef std::vector<ChildScreenSpriteToDraw> ChildScreenSpriteToDrawVector;
163
164 constexpr int LAST_CHILD_NONE = -1;
165 constexpr int LAST_CHILD_PARENT = -2;
166
168 struct ViewportDrawer {
169 DrawPixelInfo dpi;
170
171 StringSpriteToDrawVector string_sprites_to_draw;
172 TileSpriteToDrawVector tile_sprites_to_draw;
173 ParentSpriteToDrawVector parent_sprites_to_draw;
174 ParentSpriteToSortVector parent_sprites_to_sort;
175 ChildScreenSpriteToDrawVector child_screen_sprites_to_draw;
176
177 int last_child;
178
179 SpriteCombineMode combine_sprites;
180
181 int foundation[FOUNDATION_PART_END];
182 FoundationPart foundation_part;
183 int last_foundation_child[FOUNDATION_PART_END];
184 Point foundation_offset[FOUNDATION_PART_END];
185};
186
187static bool MarkViewportDirty(const Viewport *vp, int left, int top, int right, int bottom);
188
189static ViewportDrawer _vd;
190
191 TileHighlightData _thd;
192static TileInfo _cur_ti;
193bool _draw_bounding_boxes = false;
194bool _draw_dirty_blocks = false;
195uint _dirty_block_colour = 0;
196static VpSpriteSorter _vp_sprite_sorter = nullptr;
197
198static Point MapXYZToViewport(const Viewport *vp, int x, int y, int z)
199{
200 Point p = RemapCoords(x, y, z);
201 p.x -= vp->virtual_width / 2;
202 p.y -= vp->virtual_height / 2;
203 return p;
204}
205
206void DeleteWindowViewport(Window *w)
207{
208 delete w->viewport;
209 w->viewport = nullptr;
210}
211
222 void InitializeWindowViewport(Window *w, int x, int y,
223 int width, int height, std::variant<TileIndex, VehicleID> focus, ZoomLevel zoom)
224{
225 assert(w->viewport == nullptr);
226
227 ViewportData *vp = new ViewportData();
228
229 vp->left = x + w->left;
230 vp->top = y + w->top;
231 vp->width = width;
232 vp->height = height;
233
234 vp->zoom = static_cast<ZoomLevel>(Clamp(zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max));
235
236 vp->virtual_width = ScaleByZoom(width, zoom);
237 vp->virtual_height = ScaleByZoom(height, zoom);
238
239 Point pt;
240
241 if (std::holds_alternative<VehicleID>(focus)) {
242 const Vehicle *veh;
243
244 vp->follow_vehicle = std::get<VehicleID>(focus);
245 veh = Vehicle::Get(vp->follow_vehicle);
246 pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
247 } else {
248 TileIndex tile = std::get<TileIndex>(focus);
249 if (tile == INVALID_TILE) {
250 /* No tile? Use center of main viewport. */
251 const Window *mw = GetMainWindow();
252
253 /* center on same place as main window (zoom is maximum, no adjustment needed) */
254 pt.x = mw->viewport->scrollpos_x + mw->viewport->virtual_width / 2;
255 pt.x -= vp->virtual_width / 2;
256 pt.y = mw->viewport->scrollpos_y + mw->viewport->virtual_height / 2;
257 pt.y -= vp->virtual_height / 2;
258 } else {
259 x = TileX(tile) * TILE_SIZE;
260 y = TileY(tile) * TILE_SIZE;
261 pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y));
262 }
263 vp->follow_vehicle = INVALID_VEHICLE;
264 }
265
266 vp->scrollpos_x = pt.x;
267 vp->scrollpos_y = pt.y;
268 vp->dest_scrollpos_x = pt.x;
269 vp->dest_scrollpos_y = pt.y;
270
271 vp->overlay = nullptr;
272
273 w->viewport = vp;
274 vp->virtual_left = 0;
275 vp->virtual_top = 0;
276}
277
278static Point _vp_move_offs;
279
280static void DoSetViewportPosition(Window::IteratorToFront it, int left, int top, int width, int height)
281{
282 for (; !it.IsEnd(); ++it) {
283 const Window *w = *it;
284 if (left + width > w->left &&
285 w->left + w->width > left &&
286 top + height > w->top &&
287 w->top + w->height > top) {
288
289 if (left < w->left) {
290 DoSetViewportPosition(it, left, top, w->left - left, height);
291 DoSetViewportPosition(it, left + (w->left - left), top, width - (w->left - left), height);
292 return;
293 }
294
295 if (left + width > w->left + w->width) {
296 DoSetViewportPosition(it, left, top, (w->left + w->width - left), height);
297 DoSetViewportPosition(it, left + (w->left + w->width - left), top, width - (w->left + w->width - left), height);
298 return;
299 }
300
301 if (top < w->top) {
302 DoSetViewportPosition(it, left, top, width, (w->top - top));
303 DoSetViewportPosition(it, left, top + (w->top - top), width, height - (w->top - top));
304 return;
305 }
306
307 if (top + height > w->top + w->height) {
308 DoSetViewportPosition(it, left, top, width, (w->top + w->height - top));
309 DoSetViewportPosition(it, left, top + (w->top + w->height - top), width, height - (w->top + w->height - top));
310 return;
311 }
312
313 return;
314 }
315 }
316
317 {
318 int xo = _vp_move_offs.x;
319 int yo = _vp_move_offs.y;
320
321 if (abs(xo) >= width || abs(yo) >= height) {
322 /* fully_outside */
323 RedrawScreenRect(left, top, left + width, top + height);
324 return;
325 }
326
327 GfxScroll(left, top, width, height, xo, yo);
328
329 if (xo > 0) {
330 RedrawScreenRect(left, top, xo + left, top + height);
331 left += xo;
332 width -= xo;
333 } else if (xo < 0) {
334 RedrawScreenRect(left + width + xo, top, left + width, top + height);
335 width += xo;
336 }
337
338 if (yo > 0) {
339 RedrawScreenRect(left, top, width + left, top + yo);
340 } else if (yo < 0) {
341 RedrawScreenRect(left, top + height + yo, width + left, top + height);
342 }
343 }
344}
345
346static void SetViewportPosition(Window *w, int x, int y)
347{
348 Viewport *vp = w->viewport;
349 int old_left = vp->virtual_left;
350 int old_top = vp->virtual_top;
351 int i;
352 int left, top, width, height;
353
354 vp->virtual_left = x;
355 vp->virtual_top = y;
356
357 /* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower)
358 * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL)
359 */
360 old_left = UnScaleByZoomLower(old_left, vp->zoom);
361 old_top = UnScaleByZoomLower(old_top, vp->zoom);
362 x = UnScaleByZoomLower(x, vp->zoom);
363 y = UnScaleByZoomLower(y, vp->zoom);
364
365 old_left -= x;
366 old_top -= y;
367
368 if (old_top == 0 && old_left == 0) return;
369
370 _vp_move_offs.x = old_left;
371 _vp_move_offs.y = old_top;
372
373 left = vp->left;
374 top = vp->top;
375 width = vp->width;
376 height = vp->height;
377
378 if (left < 0) {
379 width += left;
380 left = 0;
381 }
382
383 i = left + width - _screen.width;
384 if (i >= 0) width -= i;
385
386 if (width > 0) {
387 if (top < 0) {
388 height += top;
389 top = 0;
390 }
391
392 i = top + height - _screen.height;
393 if (i >= 0) height -= i;
394
395 if (height > 0) {
396 Window::IteratorToFront it(w);
397 ++it;
398 DoSetViewportPosition(it, left, top, width, height);
399 }
400 }
401}
402
411 Viewport *IsPtInWindowViewport(const Window *w, int x, int y)
412{
413 Viewport *vp = w->viewport;
414
415 if (vp != nullptr &&
416 IsInsideMM(x, vp->left, vp->left + vp->width) &&
417 IsInsideMM(y, vp->top, vp->top + vp->height))
418 return vp;
419
420 return nullptr;
421}
422
435 Point TranslateXYToTileCoord(const Viewport *vp, int x, int y, bool clamp_to_map)
436{
437 if (!IsInsideBS(x, vp->left, vp->width) || !IsInsideBS(y, vp->top, vp->height)) {
438 Point pt = { -1, -1 };
439 return pt;
440 }
441
442 return InverseRemapCoords2(
443 ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left,
444 ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top, clamp_to_map);
445}
446
447/* When used for zooming, check area below current coordinates (x,y)
448 * and return the tile of the zoomed out/in position (zoom_x, zoom_y)
449 * when you just want the tile, make x = zoom_x and y = zoom_y */
450static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y)
451{
452 Window *w;
453 Viewport *vp;
454 Point pt;
455
456 if ( (w = FindWindowFromPt(x, y)) != nullptr &&
457 (vp = IsPtInWindowViewport(w, x, y)) != nullptr)
458 return TranslateXYToTileCoord(vp, zoom_x, zoom_y);
459
460 pt.y = pt.x = -1;
461 return pt;
462}
463
464 Point GetTileBelowCursor()
465{
466 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
467}
468
469
470 Point GetTileZoomCenterWindow(bool in, Window * w)
471{
472 int x, y;
473 Viewport *vp = w->viewport;
474
475 if (in) {
476 x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2);
477 y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2);
478 } else {
479 x = vp->width - (_cursor.pos.x - vp->left);
480 y = vp->height - (_cursor.pos.y - vp->top);
481 }
482 /* Get the tile below the cursor and center on the zoomed-out center */
483 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top);
484}
485
494 void HandleZoomMessage(Window *w, const Viewport *vp, WidgetID widget_zoom_in, WidgetID widget_zoom_out)
495{
496 w->SetWidgetDisabledState(widget_zoom_in, vp->zoom <= _settings_client.gui.zoom_min);
497 w->SetWidgetDirty(widget_zoom_in);
498
499 w->SetWidgetDisabledState(widget_zoom_out, vp->zoom >= _settings_client.gui.zoom_max);
500 w->SetWidgetDirty(widget_zoom_out);
501}
502
515 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)
516{
517 assert((image & SPRITE_MASK) < MAX_SPRITES);
518
519 TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.emplace_back();
520 ts.image = image;
521 ts.pal = pal;
522 ts.sub = sub;
523 Point pt = RemapCoords(x, y, z);
524 ts.x = pt.x + extra_offs_x;
525 ts.y = pt.y + extra_offs_y;
526}
527
540 static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
541{
542 assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END));
543 assert(_vd.foundation[foundation_part] != -1);
544 Point offs = _vd.foundation_offset[foundation_part];
545
546 /* Change the active ChildSprite list to the one of the foundation */
547 AutoRestoreBackup backup(_vd.last_child, _vd.last_foundation_child[foundation_part]);
548 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub, false, false);
549}
550
564 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)
565{
566 /* Switch to first foundation part, if no foundation was drawn */
567 if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL;
568
569 if (_vd.foundation[_vd.foundation_part] != -1) {
570 Point pt = RemapCoords(x, y, z);
571 AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, pt.x + extra_offs_x * ZOOM_BASE, pt.y + extra_offs_y * ZOOM_BASE);
572 } else {
573 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);
574 }
575}
576
587 void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
588{
589 DrawGroundSpriteAt(image, pal, 0, 0, 0, sub, extra_offs_x, extra_offs_y);
590}
591
599 void OffsetGroundSprite(int x, int y)
600{
601 /* Switch to next foundation part */
602 switch (_vd.foundation_part) {
603 case FOUNDATION_PART_NONE:
604 _vd.foundation_part = FOUNDATION_PART_NORMAL;
605 break;
606 case FOUNDATION_PART_NORMAL:
607 _vd.foundation_part = FOUNDATION_PART_HALFTILE;
608 break;
609 default: NOT_REACHED();
610 }
611
612 /* _vd.last_child is LAST_CHILD_NONE if foundation sprite was clipped by the viewport bounds */
613 if (_vd.last_child != LAST_CHILD_NONE) _vd.foundation[_vd.foundation_part] = static_cast<uint>(_vd.parent_sprites_to_draw.size()) - 1;
614
615 _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_BASE;
616 _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_BASE;
617 _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child;
618}
619
631 static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub)
632{
633 Point pt = RemapCoords(x, y, z);
634 const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal);
635
636 if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width ||
637 pt.x + spr->x_offs + spr->width <= _vd.dpi.left ||
638 pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height ||
639 pt.y + spr->y_offs + spr->height <= _vd.dpi.top)
640 return;
641
642 const ParentSpriteToDraw &pstd = _vd.parent_sprites_to_draw.back();
643 AddChildSpriteScreen(image, pal, pt.x - pstd.left, pt.y - pstd.top, false, sub, false);
644}
645
671 void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
672{
673 int32_t left, right, top, bottom;
674
675 assert((image & SPRITE_MASK) < MAX_SPRITES);
676
677 /* make the sprites transparent with the right palette */
678 if (transparent) {
679 SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
680 pal = PALETTE_TO_TRANSPARENT;
681 }
682
683 if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) {
684 AddCombinedSprite(image, pal, x, y, z, sub);
685 return;
686 }
687
688 _vd.last_child = LAST_CHILD_NONE;
689
690 Point pt = RemapCoords(x, y, z);
691 int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
692
693 /* Compute screen extents of sprite */
694 if (image == SPR_EMPTY_BOUNDING_BOX) {
695 left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
696 right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1;
697 top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
698 bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1;
699 } else {
700 const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal);
701 left = tmp_left = (pt.x += spr->x_offs);
702 right = (pt.x + spr->width );
703 top = tmp_top = (pt.y += spr->y_offs);
704 bottom = (pt.y + spr->height);
705 }
706
707 if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
708 /* Compute maximal extents of sprite and its bounding box */
709 left = std::min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
710 right = std::max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
711 top = std::min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
712 bottom = std::max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
713 }
714
715 /* Do not add the sprite to the viewport, if it is outside */
716 if (left >= _vd.dpi.left + _vd.dpi.width ||
717 right <= _vd.dpi.left ||
718 top >= _vd.dpi.top + _vd.dpi.height ||
719 bottom <= _vd.dpi.top) {
720 return;
721 }
722
723 ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.emplace_back();
724 ps.x = tmp_x;
725 ps.y = tmp_y;
726
727 ps.left = tmp_left;
728 ps.top = tmp_top;
729
730 ps.image = image;
731 ps.pal = pal;
732 ps.sub = sub;
733 ps.xmin = x + bb_offset_x;
734 ps.xmax = x + std::max(bb_offset_x, w) - 1;
735
736 ps.ymin = y + bb_offset_y;
737 ps.ymax = y + std::max(bb_offset_y, h) - 1;
738
739 ps.zmin = z + bb_offset_z;
740 ps.zmax = z + std::max(bb_offset_z, dz) - 1;
741
742 ps.first_child = LAST_CHILD_NONE;
743
744 _vd.last_child = LAST_CHILD_PARENT;
745
746 if (_vd.combine_sprites == SPRITE_COMBINE_PENDING) _vd.combine_sprites = SPRITE_COMBINE_ACTIVE;
747}
748
767 void StartSpriteCombine()
768{
769 assert(_vd.combine_sprites == SPRITE_COMBINE_NONE);
770 _vd.combine_sprites = SPRITE_COMBINE_PENDING;
771}
772
777 void EndSpriteCombine()
778{
779 assert(_vd.combine_sprites != SPRITE_COMBINE_NONE);
780 _vd.combine_sprites = SPRITE_COMBINE_NONE;
781}
782
792 static bool IsInRangeInclusive(int begin, int end, int check)
793{
794 if (begin > end) Swap(begin, end);
795 return begin <= check && check <= end;
796}
797
804 bool IsInsideRotatedRectangle(int x, int y)
805{
806 int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle.
807 int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative!
808 int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny.
809 int b = ((x - _thd.pos.x) - (y - _thd.pos.y));
810
811 /* Check if a and b are between 0 and dist_a or dist_b respectively. */
812 return IsInRangeInclusive(dist_a, 0, a) && IsInRangeInclusive(dist_b, 0, b);
813}
814
827 void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale, bool relative)
828{
829 assert((image & SPRITE_MASK) < MAX_SPRITES);
830
831 /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */
832 if (_vd.last_child == LAST_CHILD_NONE) return;
833
834 /* make the sprites transparent with the right palette */
835 if (transparent) {
836 SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
837 pal = PALETTE_TO_TRANSPARENT;
838 }
839
840 int32_t child_id = static_cast<int32_t>(_vd.child_screen_sprites_to_draw.size());
841 if (_vd.last_child != LAST_CHILD_PARENT) {
842 _vd.child_screen_sprites_to_draw[_vd.last_child].next = child_id;
843 } else {
844 _vd.parent_sprites_to_draw.back().first_child = child_id;
845 }
846
847 ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.emplace_back();
848 cs.image = image;
849 cs.pal = pal;
850 cs.sub = sub;
851 cs.x = scale ? x * ZOOM_BASE : x;
852 cs.y = scale ? y * ZOOM_BASE : y;
853 cs.relative = relative;
854 cs.next = LAST_CHILD_NONE;
855
856 /* Append the sprite to the active ChildSprite list.
857 * If the active ParentSprite is a foundation, update last_foundation_child as well.
858 * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */
859 if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = child_id;
860 if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = child_id;
861 _vd.last_child = child_id;
862}
863
864static void AddStringToDraw(int x, int y, StringID string, Colours colour, uint16_t width)
865{
866 assert(width != 0);
867 StringSpriteToDraw &ss = _vd.string_sprites_to_draw.emplace_back();
868 ss.string = GetString(string);
869 ss.string_id = string;
870 ss.x = x;
871 ss.y = y;
872 ss.width = width;
873 ss.colour = colour;
874}
875
876
890 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)
891{
892 /* FIXME: This is not totally valid for some autorail highlights that extend over the edges of the tile. */
893 if (_vd.foundation[foundation_part] == -1) {
894 /* draw on real ground */
895 AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset, nullptr, extra_offs_x, extra_offs_y);
896 } else {
897 /* draw on top of foundation */
898 AddChildSpriteToFoundation(image, pal, nullptr, foundation_part, extra_offs_x, extra_offs_y - z_offset * ZOOM_BASE);
899 }
900}
901
908 static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal)
909{
910 if (!IsValidTile(ti->tile)) return;
911
912 SpriteID sel;
913 if (IsHalftileSlope(ti->tileh)) {
914 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
915 SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner;
916 DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE);
917
918 Corner opposite_corner = OppositeCorner(halftile_corner);
919 if (IsSteepSlope(ti->tileh)) {
920 sel = SPR_HALFTILE_SELECTION_DOWN;
921 } else {
922 sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT);
923 }
924 sel += opposite_corner;
925 } else {
926 sel = SPR_SELECT_TILE + SlopeToSpriteOffset(ti->tileh);
927 }
928 DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL);
929}
930
931static bool IsPartOfAutoLine(int px, int py)
932{
933 px -= _thd.selstart.x;
934 py -= _thd.selstart.y;
935
936 if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false;
937
938 switch (_thd.drawstyle & HT_DIR_MASK) {
939 case HT_DIR_X: return py == 0; // x direction
940 case HT_DIR_Y: return px == 0; // y direction
941 case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
942 case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
943 case HT_DIR_VL: return px == py || px == py + 16; // vertical left
944 case HT_DIR_VR: return px == py || px == py - 16; // vertical right
945 default:
946 NOT_REACHED();
947 }
948}
949
950/* [direction][side] */
951static const HighLightStyle _autorail_type[6][2] = {
952 { HT_DIR_X, HT_DIR_X },
953 { HT_DIR_Y, HT_DIR_Y },
954 { HT_DIR_HU, HT_DIR_HL },
955 { HT_DIR_HL, HT_DIR_HU },
956 { HT_DIR_VL, HT_DIR_VR },
957 { HT_DIR_VR, HT_DIR_VL }
958};
959
960#include "table/autorail.h"
961
968 static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
969{
970 SpriteID image;
971 PaletteID pal;
972 int offset;
973
974 FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
975 Slope autorail_tileh = RemoveHalftileSlope(ti->tileh);
976 if (IsHalftileSlope(ti->tileh)) {
977 static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
978 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
979 if (autorail_type != _lower_rail[halftile_corner]) {
980 foundation_part = FOUNDATION_PART_HALFTILE;
981 /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */
982 autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
983 }
984 }
985
986 offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
987 if (offset >= 0) {
988 image = SPR_AUTORAIL_BASE + offset;
989 pal = PAL_NONE;
990 } else {
991 image = SPR_AUTORAIL_BASE - offset;
992 pal = PALETTE_SEL_TILE_RED;
993 }
994
995 DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
996}
997
998enum TileHighlightType {
999 THT_NONE,
1000 THT_WHITE,
1001 THT_BLUE,
1002 THT_RED,
1003};
1004
1005 const Station *_viewport_highlight_station;
1006 const Waypoint *_viewport_highlight_waypoint;
1007 const Town *_viewport_highlight_town;
1008
1014 static TileHighlightType GetTileHighlightType(TileIndex t)
1015{
1016 if (_viewport_highlight_station != nullptr) {
1017 if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_WHITE;
1018 if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE;
1019 }
1020 if (_viewport_highlight_waypoint != nullptr) {
1021 if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_waypoint->index) return THT_BLUE;
1022 }
1023
1024 if (_viewport_highlight_town != nullptr) {
1025 if (IsTileType(t, MP_HOUSE)) {
1026 if (GetTownIndex(t) == _viewport_highlight_town->index) {
1027 TileHighlightType type = THT_RED;
1028 for (const Station *st : _viewport_highlight_town->stations_near) {
1029 if (st->owner != _current_company) continue;
1030 if (st->TileIsInCatchment(t)) return THT_BLUE;
1031 }
1032 return type;
1033 }
1034 } else if (IsTileType(t, MP_STATION)) {
1035 for (const Station *st : _viewport_highlight_town->stations_near) {
1036 if (st->owner != _current_company) continue;
1037 if (GetStationIndex(t) == st->index) return THT_WHITE;
1038 }
1039 }
1040 }
1041
1042 return THT_NONE;
1043}
1044
1050 static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht)
1051{
1052 switch (tht) {
1053 default:
1054 case THT_NONE: break;
1055 case THT_WHITE: DrawTileSelectionRect(ti, PAL_NONE); break;
1056 case THT_BLUE: DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); break;
1057 case THT_RED: DrawTileSelectionRect(ti, PALETTE_SEL_TILE_RED); break;
1058 }
1059}
1060
1065 static void HighlightTownLocalAuthorityTiles(const TileInfo *ti)
1066{
1067 /* Going through cases in order of computational time. */
1068
1069 if (_town_local_authority_kdtree.Count() == 0) return;
1070
1071 /* Tile belongs to town regardless of distance from town. */
1072 if (GetTileType(ti->tile) == MP_HOUSE) {
1073 if (!Town::GetByTile(ti->tile)->show_zone) return;
1074
1075 DrawTileSelectionRect(ti, PALETTE_CRASH);
1076 return;
1077 }
1078
1079 /* If the closest town in the highlighted list is far, we can stop searching. */
1080 TownID tid = _town_local_authority_kdtree.FindNearest(TileX(ti->tile), TileY(ti->tile));
1081 Town *closest_highlighted_town = Town::Get(tid);
1082
1083 if (DistanceManhattan(ti->tile, closest_highlighted_town->xy) >= _settings_game.economy.dist_local_authority) return;
1084
1085 /* Tile is inside of the local autrhority distance of a highlighted town,
1086 but it is possible that a non-highlighted town is even closer. */
1087 Town *closest_town = ClosestTownFromTile(ti->tile, _settings_game.economy.dist_local_authority);
1088
1089 if (closest_town->show_zone) {
1090 DrawTileSelectionRect(ti, PALETTE_CRASH);
1091 }
1092
1093}
1094
1099 static void DrawTileSelection(const TileInfo *ti)
1100{
1101 /* Highlight tiles insede local authority of selected towns. */
1102 HighlightTownLocalAuthorityTiles(ti);
1103
1104 /* Draw a red error square? */
1105 bool is_redsq = _thd.redsq == ti->tile;
1106 if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING);
1107
1108 TileHighlightType tht = GetTileHighlightType(ti->tile);
1109 DrawTileHighlightType(ti, tht);
1110
1111 /* No tile selection active? */
1112 if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return;
1113
1114 if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle
1115 if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner;
1116 return;
1117 }
1118
1119 /* Inside the inner area? */
1120 if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) &&
1121 IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) {
1122draw_inner:
1123 if (_thd.drawstyle & HT_RECT) {
1124 if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE);
1125 } else if (_thd.drawstyle & HT_POINT) {
1126 /* Figure out the Z coordinate for the single dot. */
1127 int z = 0;
1128 FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
1129 if (ti->tileh & SLOPE_N) {
1130 z += TILE_HEIGHT;
1131 if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT;
1132 }
1133 if (IsHalftileSlope(ti->tileh)) {
1134 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
1135 if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
1136 if (halftile_corner != CORNER_S) {
1137 foundation_part = FOUNDATION_PART_HALFTILE;
1138 if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
1139 }
1140 }
1141 DrawSelectionSprite(SPR_DOT, PAL_NONE, ti, z, foundation_part);
1142 } else if (_thd.drawstyle & HT_RAIL) {
1143 /* autorail highlight piece under cursor */
1144 HighLightStyle type = _thd.drawstyle & HT_DIR_MASK;
1145 assert(type < HT_DIR_END);
1146 DrawAutorailSelection(ti, _autorail_type[type][0]);
1147 } else if (IsPartOfAutoLine(ti->x, ti->y)) {
1148 /* autorail highlighting long line */
1149 HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK;
1150 uint side;
1151
1152 if (dir == HT_DIR_X || dir == HT_DIR_Y) {
1153 side = 0;
1154 } else {
1155 TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
1156 side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile)));
1157 }
1158
1159 DrawAutorailSelection(ti, _autorail_type[dir][side]);
1160 }
1161 return;
1162 }
1163
1164 /* Check if it's inside the outer area? */
1165 if (!is_redsq && (tht == THT_NONE || tht == THT_RED) && _thd.outersize.x > 0 &&
1166 IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) &&
1167 IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) {
1168 /* Draw a blue rect. */
1169 DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE);
1170 return;
1171 }
1172}
1173
1180 static int GetViewportY(Point tile)
1181{
1182 /* Each increment in X or Y direction moves down by half a tile, i.e. TILE_PIXELS / 2. */
1183 return (tile.y * (int)(TILE_PIXELS / 2) + tile.x * (int)(TILE_PIXELS / 2) - TilePixelHeightOutsideMap(tile.x, tile.y)) << ZOOM_BASE_SHIFT;
1184}
1185
1189 static void ViewportAddLandscape()
1190{
1191 assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height);
1192 assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width);
1193
1194 Point upper_left = InverseRemapCoords(_vd.dpi.left, _vd.dpi.top);
1195 Point upper_right = InverseRemapCoords(_vd.dpi.left + _vd.dpi.width, _vd.dpi.top);
1196
1197 /* Transformations between tile coordinates and viewport rows/columns: See vp_column_row
1198 * column = y - x
1199 * row = x + y
1200 * x = (row - column) / 2
1201 * y = (row + column) / 2
1202 * Note: (row, columns) pairs are only valid, if they are both even or both odd.
1203 */
1204
1205 /* Columns overlap with neighbouring columns by a half tile.
1206 * - Left column is column of upper_left (rounded down) and one column to the left.
1207 * - Right column is column of upper_right (rounded up) and one column to the right.
1208 * Note: Integer-division does not round down for negative numbers, so ensure rounding with another increment/decrement.
1209 */
1210 int left_column = (upper_left.y - upper_left.x) / (int)TILE_SIZE - 2;
1211 int right_column = (upper_right.y - upper_right.x) / (int)TILE_SIZE + 2;
1212
1213 int potential_bridge_height = ZOOM_BASE * TILE_HEIGHT * _settings_game.construction.max_bridge_height;
1214
1215 /* Rows overlap with neighbouring rows by a half tile.
1216 * The first row that could possibly be visible is the row above upper_left (if it is at height 0).
1217 * Due to integer-division not rounding down for negative numbers, we need another decrement.
1218 */
1219 int row = (upper_left.x + upper_left.y) / (int)TILE_SIZE - 2;
1220 bool last_row = false;
1221 for (; !last_row; row++) {
1222 last_row = true;
1223 for (int column = left_column; column <= right_column; column++) {
1224 /* Valid row/column? */
1225 if ((row + column) % 2 != 0) continue;
1226
1227 Point tilecoord;
1228 tilecoord.x = (row - column) / 2;
1229 tilecoord.y = (row + column) / 2;
1230 assert(column == tilecoord.y - tilecoord.x);
1231 assert(row == tilecoord.y + tilecoord.x);
1232
1233 TileType tile_type;
1234 _cur_ti.x = tilecoord.x * TILE_SIZE;
1235 _cur_ti.y = tilecoord.y * TILE_SIZE;
1236
1237 if (IsInsideBS(tilecoord.x, 0, Map::SizeX()) && IsInsideBS(tilecoord.y, 0, Map::SizeY())) {
1238 /* This includes the south border at Map::MaxX / Map::MaxY. When terraforming we still draw tile selections there. */
1239 _cur_ti.tile = TileXY(tilecoord.x, tilecoord.y);
1240 tile_type = GetTileType(_cur_ti.tile);
1241 } else {
1242 _cur_ti.tile = INVALID_TILE;
1243 tile_type = MP_VOID;
1244 }
1245
1246 if (tile_type != MP_VOID) {
1247 /* We are inside the map => paint landscape. */
1248 std::tie(_cur_ti.tileh, _cur_ti.z) = GetTilePixelSlope(_cur_ti.tile);
1249 } else {
1250 /* We are outside the map => paint black. */
1251 std::tie(_cur_ti.tileh, _cur_ti.z) = GetTilePixelSlopeOutsideMap(tilecoord.x, tilecoord.y);
1252 }
1253
1254 int viewport_y = GetViewportY(tilecoord);
1255
1256 if (viewport_y + MAX_TILE_EXTENT_BOTTOM < _vd.dpi.top) {
1257 /* The tile in this column is not visible yet.
1258 * Tiles in other columns may be visible, but we need more rows in any case. */
1259 last_row = false;
1260 continue;
1261 }
1262
1263 int min_visible_height = viewport_y - (_vd.dpi.top + _vd.dpi.height);
1264 bool tile_visible = min_visible_height <= 0;
1265
1266 if (tile_type != MP_VOID) {
1267 /* Is tile with buildings visible? */
1268 if (min_visible_height < MAX_TILE_EXTENT_TOP) tile_visible = true;
1269
1270 if (IsBridgeAbove(_cur_ti.tile)) {
1271 /* Is the bridge visible? */
1272 TileIndex bridge_tile = GetNorthernBridgeEnd(_cur_ti.tile);
1273 int bridge_height = ZOOM_BASE * (GetBridgePixelHeight(bridge_tile) - TilePixelHeight(_cur_ti.tile));
1274 if (min_visible_height < bridge_height + MAX_TILE_EXTENT_TOP) tile_visible = true;
1275 }
1276
1277 /* Would a higher bridge on a more southern tile be visible?
1278 * If yes, we need to loop over more rows to possibly find one. */
1279 if (min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
1280 } else {
1281 /* Outside of map. If we are on the north border of the map, there may still be a bridge visible,
1282 * so we need to loop over more rows to possibly find one. */
1283 if ((tilecoord.x <= 0 || tilecoord.y <= 0) && min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false;
1284 }
1285
1286 if (tile_visible) {
1287 last_row = false;
1288 _vd.foundation_part = FOUNDATION_PART_NONE;
1289 _vd.foundation[0] = -1;
1290 _vd.foundation[1] = -1;
1291 _vd.last_foundation_child[0] = LAST_CHILD_NONE;
1292 _vd.last_foundation_child[1] = LAST_CHILD_NONE;
1293
1294 _tile_type_procs[tile_type]->draw_tile_proc(&_cur_ti);
1295 if (_cur_ti.tile != INVALID_TILE) DrawTileSelection(&_cur_ti);
1296 }
1297 }
1298 }
1299}
1300
1311 void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, Colours colour)
1312{
1313 bool small = dpi->zoom >= small_from;
1314
1315 int left = dpi->left;
1316 int top = dpi->top;
1317 int right = left + dpi->width;
1318 int bottom = top + dpi->height;
1319
1320 int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, dpi->zoom);
1321 int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom);
1322
1323 if (bottom < sign->top ||
1324 top > sign->top + sign_height ||
1325 right < sign->center - sign_half_width ||
1326 left > sign->center + sign_half_width) {
1327 return;
1328 }
1329
1330 if (!small) {
1331 AddStringToDraw(sign->center - sign_half_width, sign->top, string_normal, colour, sign->width_normal);
1332 } else {
1333 int shadow_offset = 0;
1334 if (string_small_shadow != STR_NULL) {
1335 shadow_offset = 4;
1336 AddStringToDraw(sign->center - sign_half_width + shadow_offset, sign->top, string_small_shadow, INVALID_COLOUR, sign->width_small | 0x8000);
1337 }
1338 AddStringToDraw(sign->center - sign_half_width, sign->top - shadow_offset, string_small, colour, sign->width_small | 0x8000);
1339 }
1340}
1341
1342static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom)
1343{
1344 const int fh = std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL));
1345 const int max_tw = _viewport_sign_maxwidth / 2 + 1;
1346 const int expand_y = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + fh + WidgetDimensions::scaled.fullbevel.bottom, zoom);
1347 const int expand_x = ScaleByZoom(WidgetDimensions::scaled.fullbevel.left + max_tw + WidgetDimensions::scaled.fullbevel.right, zoom);
1348
1349 r.left -= expand_x;
1350 r.right += expand_x;
1351 r.top -= expand_y;
1352 r.bottom += expand_y;
1353
1354 return r;
1355}
1356
1357static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi)
1358{
1359 Rect search_rect{ dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height };
1360 search_rect = ExpandRectWithViewportSignMargins(search_rect, dpi->zoom);
1361
1362 bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && _game_mode != GM_MENU;
1363 bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && _game_mode != GM_MENU;
1364 bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES) && _game_mode != GM_MENU;
1365 bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS);
1366 bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
1367
1368 /* Collect all the items first and draw afterwards, to ensure layering */
1369 std::vector<const BaseStation *> stations;
1370 std::vector<const Town *> towns;
1371 std::vector<const Sign *> signs;
1372
1373 _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) {
1374 switch (item.type) {
1375 case ViewportSignKdtreeItem::VKI_STATION: {
1376 if (!show_stations) break;
1377 const BaseStation *st = BaseStation::Get(item.id.station);
1378
1379 /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */
1380 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
1381
1382 stations.push_back(st);
1383 break;
1384 }
1385
1386 case ViewportSignKdtreeItem::VKI_WAYPOINT: {
1387 if (!show_waypoints) break;
1388 const BaseStation *st = BaseStation::Get(item.id.station);
1389
1390 /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */
1391 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
1392
1393 stations.push_back(st);
1394 break;
1395 }
1396
1397 case ViewportSignKdtreeItem::VKI_TOWN:
1398 if (!show_towns) break;
1399 towns.push_back(Town::Get(item.id.town));
1400 break;
1401
1402 case ViewportSignKdtreeItem::VKI_SIGN: {
1403 if (!show_signs) break;
1404 const Sign *si = Sign::Get(item.id.sign);
1405
1406 /* Don't draw if sign is owned by another company and competitor signs should be hidden.
1407 * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt
1408 * companies can leave OWNER_NONE signs after them. */
1409 if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break;
1410
1411 signs.push_back(si);
1412 break;
1413 }
1414
1415 default:
1416 NOT_REACHED();
1417 }
1418 });
1419
1420 /* Layering order (bottom to top): Town names, signs, stations */
1421
1422 for (const auto *t : towns) {
1423 SetDParam(0, t->index);
1424 SetDParam(1, t->cache.population);
1425 ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &t->cache.sign,
1426 _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN,
1427 STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK);
1428 }
1429
1430 /* Do not draw signs nor station names if they are set invisible */
1431 if (IsInvisibilitySet(TO_SIGNS)) return;
1432
1433 for (const auto *si : signs) {
1434 SetDParam(0, si->index);
1435 ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &si->sign,
1436 STR_WHITE_SIGN,
1437 (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL,
1438 (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner]));
1439 }
1440
1441 for (const auto *st : stations) {
1442 SetDParam(0, st->index);
1443 SetDParam(1, st->facilities);
1444 if (Station::IsExpected(st)) {
1445 /* Station */
1446 ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &st->sign,
1447 STR_VIEWPORT_STATION, STR_VIEWPORT_STATION_TINY, STR_NULL,
1448 (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]);
1449 } else {
1450 /* Waypoint */
1451 ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &st->sign,
1452 STR_VIEWPORT_WAYPOINT, STR_VIEWPORT_WAYPOINT_TINY, STR_NULL,
1453 (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]);
1454 }
1455 }
1456}
1457
1458
1466 void ViewportSign::UpdatePosition(int center, int top, StringID str, StringID str_small)
1467{
1468 if (this->width_normal != 0) this->MarkDirty();
1469
1470 this->top = top;
1471
1472 std::string name = GetString(str);
1473 this->width_normal = WidgetDimensions::scaled.fullbevel.left + Align(GetStringBoundingBox(name).width, 2) + WidgetDimensions::scaled.fullbevel.right;
1474 this->center = center;
1475
1476 /* zoomed out version */
1477 if (str_small != STR_NULL) {
1478 name = GetString(str_small);
1479 }
1480 this->width_small = WidgetDimensions::scaled.fullbevel.left + Align(GetStringBoundingBox(name, FS_SMALL).width, 2) + WidgetDimensions::scaled.fullbevel.right;
1481
1482 this->MarkDirty();
1483}
1484
1491 void ViewportSign::MarkDirty(ZoomLevel maxzoom) const
1492{
1493 Rect zoomlevels[ZOOM_LVL_END];
1494
1495 /* We don't know which size will be drawn, so mark the largest area dirty. */
1496 const uint half_width = std::max(this->width_normal, this->width_small) / 2 + 1;
1497 const uint height = WidgetDimensions::scaled.fullbevel.top + std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL)) + WidgetDimensions::scaled.fullbevel.bottom + 1;
1498
1499 for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) {
1500 /* FIXME: This doesn't switch to width_small when appropriate. */
1501 zoomlevels[zoom].left = this->center - ScaleByZoom(half_width, zoom);
1502 zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom);
1503 zoomlevels[zoom].right = this->center + ScaleByZoom(half_width, zoom);
1504 zoomlevels[zoom].bottom = this->top + ScaleByZoom(height, zoom);
1505 }
1506
1507 for (const Window *w : Window::Iterate()) {
1508 Viewport *vp = w->viewport;
1509 if (vp != nullptr && vp->zoom <= maxzoom) {
1510 assert(vp->width != 0);
1511 Rect &zl = zoomlevels[vp->zoom];
1512 MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom);
1513 }
1514 }
1515}
1516
1517static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv)
1518{
1519 for (const TileSpriteToDraw &ts : *tstdv) {
1520 DrawSpriteViewport(ts.image, ts.pal, ts.x, ts.y, ts.sub);
1521 }
1522}
1523
1525 static bool ViewportSortParentSpritesChecker()
1526{
1527 return true;
1528}
1529
1531 static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
1532{
1533 if (psdv->size() < 2) return;
1534
1535 /* We rely on sprites being, for the most part, already ordered.
1536 * So we don't need to move many of them and can keep track of their
1537 * order efficiently by using stack. We always move sprites to the front
1538 * of the current position, i.e. to the top of the stack.
1539 * Also use special constants to indicate sorting state without
1540 * adding extra fields to ParentSpriteToDraw structure.
1541 */
1542 const uint32_t ORDER_COMPARED = UINT32_MAX; // Sprite was compared but we still need to compare the ones preceding it
1543 const uint32_t ORDER_RETURNED = UINT32_MAX - 1; // Makr sorted sprite in case there are other occurrences of it in the stack
1544 std::stack<ParentSpriteToDraw *> sprite_order;
1545 uint32_t next_order = 0;
1546
1547 std::forward_list<std::pair<int64_t, ParentSpriteToDraw *>> sprite_list; // We store sprites in a list sorted by xmin+ymin
1548
1549 /* Initialize sprite list and order. */
1550 for (auto p = psdv->rbegin(); p != psdv->rend(); p++) {
1551 sprite_list.emplace_front((*p)->xmin + (*p)->ymin, *p);
1552 sprite_order.push(*p);
1553 (*p)->order = next_order++;
1554 }
1555
1556 sprite_list.sort();
1557
1558 std::vector<ParentSpriteToDraw *> preceding; // Temporarily stores sprites that precede current and their position in the list
1559 auto preceding_prev = sprite_list.begin(); // Store iterator in case we need to delete a single preciding sprite
1560 auto out = psdv->begin(); // Iterator to output sorted sprites
1561
1562 while (!sprite_order.empty()) {
1563
1564 auto s = sprite_order.top();
1565 sprite_order.pop();
1566
1567 /* Sprite is already sorted, ignore it. */
1568 if (s->order == ORDER_RETURNED) continue;
1569
1570 /* Sprite was already compared, just need to output it. */
1571 if (s->order == ORDER_COMPARED) {
1572 *(out++) = s;
1573 s->order = ORDER_RETURNED;
1574 continue;
1575 }
1576
1577 preceding.clear();
1578
1579 /* We only need sprites with xmin <= s->xmax && ymin <= s->ymax && zmin <= s->zmax
1580 * So by iterating sprites with xmin + ymin <= s->xmax + s->ymax
1581 * we get all we need and some more that we filter out later.
1582 * We don't include zmin into the sum as there are usually more neighbors on x and y than z
1583 * so including it will actually increase the amount of false positives.
1584 * Also min coordinates can be > max so using max(xmin, xmax) + max(ymin, ymax)
1585 * to ensure that we iterate the current sprite as we need to remove it from the list.
1586 */
1587 auto ssum = std::max(s->xmax, s->xmin) + std::max(s->ymax, s->ymin);
1588 auto prev = sprite_list.before_begin();
1589 auto x = sprite_list.begin();
1590 while (x != sprite_list.end() && ((*x).first <= ssum)) {
1591 auto p = (*x).second;
1592 if (p == s) {
1593 /* We found the current sprite, remove it and move on. */
1594 x = sprite_list.erase_after(prev);
1595 continue;
1596 }
1597
1598 auto p_prev = prev;
1599 prev = x++;
1600
1601 if (s->xmax < p->xmin || s->ymax < p->ymin || s->zmax < p->zmin) continue;
1602 if (s->xmin <= p->xmax && // overlap in X?
1603 s->ymin <= p->ymax && // overlap in Y?
1604 s->zmin <= p->zmax) { // overlap in Z?
1605 if (s->xmin + s->xmax + s->ymin + s->ymax + s->zmin + s->zmax <=
1606 p->xmin + p->xmax + p->ymin + p->ymax + p->zmin + p->zmax) {
1607 continue;
1608 }
1609 }
1610 preceding.push_back(p);
1611 preceding_prev = p_prev;
1612 }
1613
1614 if (preceding.empty()) {
1615 /* No preceding sprites, add current one to the output */
1616 *(out++) = s;
1617 s->order = ORDER_RETURNED;
1618 continue;
1619 }
1620
1621 /* Optimization for the case when we only have 1 sprite to move. */
1622 if (preceding.size() == 1) {
1623 auto p = preceding[0];
1624 /* We can only output the preceding sprite if there can't be any other sprites preceding it. */
1625 if (p->xmax <= s->xmax && p->ymax <= s->ymax && p->zmax <= s->zmax) {
1626 p->order = ORDER_RETURNED;
1627 s->order = ORDER_RETURNED;
1628 sprite_list.erase_after(preceding_prev);
1629 *(out++) = p;
1630 *(out++) = s;
1631 continue;
1632 }
1633 }
1634
1635 /* Sort all preceding sprites by order and assign new orders in reverse (as original sorter did). */
1636 std::sort(preceding.begin(), preceding.end(), [](const ParentSpriteToDraw *a, const ParentSpriteToDraw *b) {
1637 return a->order > b->order;
1638 });
1639
1640 s->order = ORDER_COMPARED;
1641 sprite_order.push(s); // Still need to output so push it back for now
1642
1643 for (auto p: preceding) {
1644 p->order = next_order++;
1645 sprite_order.push(p);
1646 }
1647 }
1648}
1649
1650
1651static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv)
1652{
1653 for (const ParentSpriteToDraw *ps : *psd) {
1654 if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub);
1655
1656 int child_idx = ps->first_child;
1657 while (child_idx >= 0) {
1658 const ChildScreenSpriteToDraw *cs = csstdv->data() + child_idx;
1659 child_idx = cs->next;
1660 if (cs->relative) {
1661 DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub);
1662 } else {
1663 DrawSpriteViewport(cs->image, cs->pal, ps->x + cs->x, ps->y + cs->y, cs->sub);
1664 }
1665 }
1666 }
1667}
1668
1673 static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
1674{
1675 for (const ParentSpriteToDraw *ps : *psd) {
1676 Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner
1677 Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner
1678 Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner
1679 Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin ); // bottom front corner
1680
1681 DrawBox( pt1.x, pt1.y,
1682 pt2.x - pt1.x, pt2.y - pt1.y,
1683 pt3.x - pt1.x, pt3.y - pt1.y,
1684 pt4.x - pt1.x, pt4.y - pt1.y);
1685 }
1686}
1687
1691 static void ViewportDrawDirtyBlocks()
1692{
1693 Blitter *blitter = BlitterFactory::GetCurrentBlitter();
1694 const DrawPixelInfo *dpi = _cur_dpi;
1695 void *dst;
1696 int right = UnScaleByZoom(dpi->width, dpi->zoom);
1697 int bottom = UnScaleByZoom(dpi->height, dpi->zoom);
1698
1699 int colour = _string_colourmap[_dirty_block_colour & 0xF];
1700
1701 dst = dpi->dst_ptr;
1702
1703 uint8_t bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
1704 do {
1705 for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8_t)colour);
1706 dst = blitter->MoveTo(dst, 0, 1);
1707 } while (--bottom > 0);
1708}
1709
1710static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv)
1711{
1712 for (const StringSpriteToDraw &ss : *sstdv) {
1713 TextColour colour = TC_BLACK;
1714 bool small = HasBit(ss.width, 15);
1715 int w = GB(ss.width, 0, 15);
1716 int x = UnScaleByZoom(ss.x, zoom);
1717 int y = UnScaleByZoom(ss.y, zoom);
1718 int h = WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom;
1719
1720 if (ss.colour != INVALID_COLOUR) {
1721 if (IsTransparencySet(TO_SIGNS) && ss.string_id != STR_WHITE_SIGN) {
1722 /* Don't draw the rectangle.
1723 * Real colours need the TC_IS_PALETTE_COLOUR flag.
1724 * Otherwise colours from _string_colourmap are assumed. */
1725 colour = (TextColour)GetColourGradient(ss.colour, SHADE_LIGHTER) | TC_IS_PALETTE_COLOUR;
1726 } else {
1727 /* Draw the rectangle if 'transparent station signs' is off,
1728 * or if we are drawing a general text sign (STR_WHITE_SIGN). */
1729 DrawFrameRect(
1730 x, y, x + w - 1, y + h - 1, ss.colour,
1731 IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE
1732 );
1733 }
1734 }
1735
1736 DrawString(x + WidgetDimensions::scaled.fullbevel.left, x + w - 1 - WidgetDimensions::scaled.fullbevel.right, y + WidgetDimensions::scaled.fullbevel.top, ss.string, colour, SA_HOR_CENTER, false, small ? FS_SMALL : FS_NORMAL);
1737 }
1738}
1739
1740void ViewportDoDraw(const Viewport *vp, int left, int top, int right, int bottom)
1741{
1742 _vd.dpi.zoom = vp->zoom;
1743 int mask = ScaleByZoom(-1, vp->zoom);
1744
1745 _vd.combine_sprites = SPRITE_COMBINE_NONE;
1746
1747 _vd.dpi.width = (right - left) & mask;
1748 _vd.dpi.height = (bottom - top) & mask;
1749 _vd.dpi.left = left & mask;
1750 _vd.dpi.top = top & mask;
1751 _vd.dpi.pitch = _cur_dpi->pitch;
1752 _vd.last_child = LAST_CHILD_NONE;
1753
1754 int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
1755 int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
1756
1757 _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_cur_dpi->dst_ptr, x - _cur_dpi->left, y - _cur_dpi->top);
1758 AutoRestoreBackup dpi_backup(_cur_dpi, &_vd.dpi);
1759
1760 ViewportAddLandscape();
1761 ViewportAddVehicles(&_vd.dpi);
1762
1763 ViewportAddKdtreeSigns(&_vd.dpi);
1764
1765 DrawTextEffects(&_vd.dpi);
1766
1767 if (!_vd.tile_sprites_to_draw.empty()) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw);
1768
1769 for (auto &psd : _vd.parent_sprites_to_draw) {
1770 _vd.parent_sprites_to_sort.push_back(&psd);
1771 }
1772
1773 _vp_sprite_sorter(&_vd.parent_sprites_to_sort);
1774 ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw);
1775
1776 if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort);
1777 if (_draw_dirty_blocks) ViewportDrawDirtyBlocks();
1778
1779 DrawPixelInfo dp = _vd.dpi;
1780 ZoomLevel zoom = _vd.dpi.zoom;
1781 dp.zoom = ZOOM_LVL_MIN;
1782 dp.width = UnScaleByZoom(dp.width, zoom);
1783 dp.height = UnScaleByZoom(dp.height, zoom);
1784 _cur_dpi = &dp;
1785
1786 if (vp->overlay != nullptr && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) {
1787 /* translate to window coordinates */
1788 dp.left = x;
1789 dp.top = y;
1790 vp->overlay->Draw(&dp);
1791 }
1792
1793 if (!_vd.string_sprites_to_draw.empty()) {
1794 /* translate to world coordinates */
1795 dp.left = UnScaleByZoom(_vd.dpi.left, zoom);
1796 dp.top = UnScaleByZoom(_vd.dpi.top, zoom);
1797 ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw);
1798 }
1799
1800 _vd.string_sprites_to_draw.clear();
1801 _vd.tile_sprites_to_draw.clear();
1802 _vd.parent_sprites_to_draw.clear();
1803 _vd.parent_sprites_to_sort.clear();
1804 _vd.child_screen_sprites_to_draw.clear();
1805}
1806
1807static inline void ViewportDraw(const Viewport *vp, int left, int top, int right, int bottom)
1808{
1809 if (right <= vp->left || bottom <= vp->top) return;
1810
1811 if (left >= vp->left + vp->width) return;
1812
1813 if (left < vp->left) left = vp->left;
1814 if (right > vp->left + vp->width) right = vp->left + vp->width;
1815
1816 if (top >= vp->top + vp->height) return;
1817
1818 if (top < vp->top) top = vp->top;
1819 if (bottom > vp->top + vp->height) bottom = vp->top + vp->height;
1820
1821 ViewportDoDraw(vp,
1822 ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
1823 ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top,
1824 ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left,
1825 ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top
1826 );
1827}
1828
1832 void Window::DrawViewport() const
1833{
1834 PerformanceAccumulator framerate(PFE_DRAWWORLD);
1835
1836 DrawPixelInfo *dpi = _cur_dpi;
1837
1838 dpi->left += this->left;
1839 dpi->top += this->top;
1840
1841 ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
1842
1843 dpi->left -= this->left;
1844 dpi->top -= this->top;
1845}
1846
1857 static inline void ClampViewportToMap(const Viewport *vp, int *scroll_x, int *scroll_y)
1858{
1859 /* Centre of the viewport is hot spot. */
1860 Point pt = {
1861 *scroll_x + vp->virtual_width / 2,
1862 *scroll_y + vp->virtual_height / 2
1863 };
1864
1865 /* Find nearest tile that is within borders of the map. */
1866 bool clamped;
1867 pt = InverseRemapCoords2(pt.x, pt.y, true, &clamped);
1868
1869 if (clamped) {
1870 /* Convert back to viewport coordinates and remove centering. */
1871 pt = RemapCoords2(pt.x, pt.y);
1872 *scroll_x = pt.x - vp->virtual_width / 2;
1873 *scroll_y = pt.y - vp->virtual_height / 2;
1874 }
1875}
1876
1889 static void ClampSmoothScroll(uint32_t delta_ms, int64_t delta_hi, int64_t delta_lo, int &delta_hi_clamped, int &delta_lo_clamped)
1890{
1892 constexpr int PIXELS_PER_TILE = TILE_PIXELS * 2 * ZOOM_BASE;
1893
1894 assert(delta_hi != 0);
1895
1896 /* Move at most 75% of the distance every 30ms, for a smooth experience */
1897 int64_t delta_left = delta_hi * std::pow(0.75, delta_ms / 30.0);
1898 /* Move never more than 16 tiles per 30ms. */
1899 int max_scroll = Map::ScaleBySize1D(16 * PIXELS_PER_TILE * delta_ms / 30);
1900
1901 /* We never go over the max_scroll speed. */
1902 delta_hi_clamped = Clamp(delta_hi - delta_left, -max_scroll, max_scroll);
1903 /* The lower delta is in ratio of the higher delta, so we keep going straight at the destination. */
1904 delta_lo_clamped = delta_lo * delta_hi_clamped / delta_hi;
1905
1906 /* Ensure we always move (delta_hi can't be zero). */
1907 if (delta_hi_clamped == 0) {
1908 delta_hi_clamped = delta_hi > 0 ? 1 : -1;
1909 }
1910}
1911
1916 void UpdateViewportPosition(Window *w, uint32_t delta_ms)
1917{
1918 const Viewport *vp = w->viewport;
1919
1920 if (w->viewport->follow_vehicle != INVALID_VEHICLE) {
1921 const Vehicle *veh = Vehicle::Get(w->viewport->follow_vehicle);
1922 Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos);
1923
1924 w->viewport->scrollpos_x = pt.x;
1925 w->viewport->scrollpos_y = pt.y;
1926 SetViewportPosition(w, pt.x, pt.y);
1927 } else {
1928 /* Ensure the destination location is within the map */
1929 ClampViewportToMap(vp, &w->viewport->dest_scrollpos_x, &w->viewport->dest_scrollpos_y);
1930
1931 int delta_x = w->viewport->dest_scrollpos_x - w->viewport->scrollpos_x;
1932 int delta_y = w->viewport->dest_scrollpos_y - w->viewport->scrollpos_y;
1933
1934 int current_x = w->viewport->scrollpos_x;
1935 int current_y = w->viewport->scrollpos_y;
1936
1937 bool update_overlay = false;
1938 if (delta_x != 0 || delta_y != 0) {
1939 if (_settings_client.gui.smooth_scroll) {
1940 int delta_x_clamped;
1941 int delta_y_clamped;
1942
1943 if (abs(delta_x) > abs(delta_y)) {
1944 ClampSmoothScroll(delta_ms, delta_x, delta_y, delta_x_clamped, delta_y_clamped);
1945 } else {
1946 ClampSmoothScroll(delta_ms, delta_y, delta_x, delta_y_clamped, delta_x_clamped);
1947 }
1948
1949 w->viewport->scrollpos_x += delta_x_clamped;
1950 w->viewport->scrollpos_y += delta_y_clamped;
1951 } else {
1952 w->viewport->scrollpos_x = w->viewport->dest_scrollpos_x;
1953 w->viewport->scrollpos_y = w->viewport->dest_scrollpos_y;
1954 }
1955 update_overlay = (w->viewport->scrollpos_x == w->viewport->dest_scrollpos_x &&
1956 w->viewport->scrollpos_y == w->viewport->dest_scrollpos_y);
1957 }
1958
1959 ClampViewportToMap(vp, &w->viewport->scrollpos_x, &w->viewport->scrollpos_y);
1960
1961 /* When moving small amounts around the border we can get stuck, and
1962 * not actually move. In those cases, teleport to the destination. */
1963 if ((delta_x != 0 || delta_y != 0) && current_x == w->viewport->scrollpos_x && current_y == w->viewport->scrollpos_y) {
1964 w->viewport->scrollpos_x = w->viewport->dest_scrollpos_x;
1965 w->viewport->scrollpos_y = w->viewport->dest_scrollpos_y;
1966 }
1967
1968 SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y);
1969 if (update_overlay) RebuildViewportOverlay(w);
1970 }
1971}
1972
1983 static bool MarkViewportDirty(const Viewport *vp, int left, int top, int right, int bottom)
1984{
1985 /* Rounding wrt. zoom-out level */
1986 right += (1 << vp->zoom) - 1;
1987 bottom += (1 << vp->zoom) - 1;
1988
1989 right -= vp->virtual_left;
1990 if (right <= 0) return false;
1991
1992 bottom -= vp->virtual_top;
1993 if (bottom <= 0) return false;
1994
1995 left = std::max(0, left - vp->virtual_left);
1996
1997 if (left >= vp->virtual_width) return false;
1998
1999 top = std::max(0, top - vp->virtual_top);
2000
2001 if (top >= vp->virtual_height) return false;
2002
2003 AddDirtyBlock(
2004 UnScaleByZoomLower(left, vp->zoom) + vp->left,
2005 UnScaleByZoomLower(top, vp->zoom) + vp->top,
2006 UnScaleByZoom(right, vp->zoom) + vp->left + 1,
2007 UnScaleByZoom(bottom, vp->zoom) + vp->top + 1
2008 );
2009
2010 return true;
2011}
2012
2022 bool MarkAllViewportsDirty(int left, int top, int right, int bottom)
2023{
2024 bool dirty = false;
2025
2026 for (const Window *w : Window::Iterate()) {
2027 Viewport *vp = w->viewport;
2028 if (vp != nullptr) {
2029 assert(vp->width != 0);
2030 if (MarkViewportDirty(vp, left, top, right, bottom)) dirty = true;
2031 }
2032 }
2033
2034 return dirty;
2035}
2036
2037void ConstrainAllViewportsZoom()
2038{
2039 for (Window *w : Window::Iterate()) {
2040 if (w->viewport == nullptr) continue;
2041
2042 ZoomLevel zoom = static_cast<ZoomLevel>(Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max));
2043 if (zoom != w->viewport->zoom) {
2044 while (w->viewport->zoom < zoom) DoZoomInOutWindow(ZOOM_OUT, w);
2045 while (w->viewport->zoom > zoom) DoZoomInOutWindow(ZOOM_IN, w);
2046 }
2047 }
2048}
2049
2057 void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
2058{
2059 Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, tile_height_override * TILE_HEIGHT);
2060 MarkAllViewportsDirty(
2061 pt.x - MAX_TILE_EXTENT_LEFT,
2062 pt.y - MAX_TILE_EXTENT_TOP - ZOOM_BASE * TILE_HEIGHT * bridge_level_offset,
2063 pt.x + MAX_TILE_EXTENT_RIGHT,
2064 pt.y + MAX_TILE_EXTENT_BOTTOM);
2065}
2066
2074 static void SetSelectionTilesDirty()
2075{
2076 int x_size = _thd.size.x;
2077 int y_size = _thd.size.y;
2078
2079 if (!_thd.diagonal) { // Selecting in a straight rectangle (or a single square)
2080 int x_start = _thd.pos.x;
2081 int y_start = _thd.pos.y;
2082
2083 if (_thd.outersize.x != 0) {
2084 x_size += _thd.outersize.x;
2085 x_start += _thd.offs.x;
2086 y_size += _thd.outersize.y;
2087 y_start += _thd.offs.y;
2088 }
2089
2090 x_size -= TILE_SIZE;
2091 y_size -= TILE_SIZE;
2092
2093 assert(x_size >= 0);
2094 assert(y_size >= 0);
2095
2096 int x_end = Clamp(x_start + x_size, 0, Map::SizeX() * TILE_SIZE - TILE_SIZE);
2097 int y_end = Clamp(y_start + y_size, 0, Map::SizeY() * TILE_SIZE - TILE_SIZE);
2098
2099 x_start = Clamp(x_start, 0, Map::SizeX() * TILE_SIZE - TILE_SIZE);
2100 y_start = Clamp(y_start, 0, Map::SizeY() * TILE_SIZE - TILE_SIZE);
2101
2102 /* make sure everything is multiple of TILE_SIZE */
2103 assert((x_end | y_end | x_start | y_start) % TILE_SIZE == 0);
2104
2105 /* How it works:
2106 * Suppose we have to mark dirty rectangle of 3x4 tiles:
2107 * x
2108 * xxx
2109 * xxxxx
2110 * xxxxx
2111 * xxx
2112 * x
2113 * This algorithm marks dirty columns of tiles, so it is done in 3+4-1 steps:
2114 * 1) x 2) x
2115 * xxx Oxx
2116 * Oxxxx xOxxx
2117 * xxxxx Oxxxx
2118 * xxx xxx
2119 * x x
2120 * And so forth...
2121 */
2122
2123 int top_x = x_end; // coordinates of top dirty tile
2124 int top_y = y_start;
2125 int bot_x = top_x; // coordinates of bottom dirty tile
2126 int bot_y = top_y;
2127
2128 do {
2129 /* topmost dirty point */
2130 TileIndex top_tile = TileVirtXY(top_x, top_y);
2131 Point top = RemapCoords(top_x, top_y, GetTileMaxPixelZ(top_tile));
2132
2133 /* bottommost point */
2134 TileIndex bottom_tile = TileVirtXY(bot_x, bot_y);
2135 Point bot = RemapCoords(bot_x + TILE_SIZE, bot_y + TILE_SIZE, GetTilePixelZ(bottom_tile)); // bottommost point
2136
2137 /* the 'x' coordinate of 'top' and 'bot' is the same (and always in the same distance from tile middle),
2138 * tile height/slope affects only the 'y' on-screen coordinate! */
2139
2140 int l = top.x - TILE_PIXELS * ZOOM_BASE; // 'x' coordinate of left side of the dirty rectangle
2141 int t = top.y; // 'y' coordinate of top side of the dirty rectangle
2142 int r = top.x + TILE_PIXELS * ZOOM_BASE; // 'x' coordinate of right side of the dirty rectangle
2143 int b = bot.y; // 'y' coordinate of bottom side of the dirty rectangle
2144
2145 static const int OVERLAY_WIDTH = 4 * ZOOM_BASE; // part of selection sprites is drawn outside the selected area (in particular: terraforming)
2146
2147 /* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */
2148 MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH);
2149
2150 /* haven't we reached the topmost tile yet? */
2151 if (top_x != x_start) {
2152 top_x -= TILE_SIZE;
2153 } else {
2154 top_y += TILE_SIZE;
2155 }
2156
2157 /* the way the bottom tile changes is different when we reach the bottommost tile */
2158 if (bot_y != y_end) {
2159 bot_y += TILE_SIZE;
2160 } else {
2161 bot_x -= TILE_SIZE;
2162 }
2163 } while (bot_x >= top_x);
2164 } else { // Selecting in a 45 degrees rotated (diagonal) rectangle.
2165 /* a_size, b_size describe a rectangle with rotated coordinates */
2166 int a_size = x_size + y_size, b_size = x_size - y_size;
2167
2168 int interval_a = a_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE;
2169 int interval_b = b_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE;
2170
2171 for (int a = -interval_a; a != a_size + interval_a; a += interval_a) {
2172 for (int b = -interval_b; b != b_size + interval_b; b += interval_b) {
2173 uint x = (_thd.pos.x + (a + b) / 2) / TILE_SIZE;
2174 uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE;
2175
2176 if (x < Map::MaxX() && y < Map::MaxY()) {
2177 MarkTileDirtyByTile(TileXY(x, y));
2178 }
2179 }
2180 }
2181 }
2182}
2183
2184
2185void SetSelectionRed(bool b)
2186{
2187 _thd.make_square_red = b;
2188 SetSelectionTilesDirty();
2189}
2190
2199 static bool CheckClickOnViewportSign(const Viewport *vp, int x, int y, const ViewportSign *sign)
2200{
2201 bool small = (vp->zoom >= ZOOM_LVL_OUT_4X);
2202 int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom);
2203 int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, vp->zoom);
2204
2205 return y >= sign->top && y < sign->top + sign_height &&
2206 x >= sign->center - sign_half_width && x < sign->center + sign_half_width;
2207}
2208
2209
2217 static bool CheckClickOnViewportSign(const Viewport *vp, int x, int y)
2218{
2219 if (_game_mode == GM_MENU) return false;
2220
2221 x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left;
2222 y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top;
2223
2224 Rect search_rect{ x - 1, y - 1, x + 1, y + 1 };
2225 search_rect = ExpandRectWithViewportSignMargins(search_rect, vp->zoom);
2226
2227 bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && !IsInvisibilitySet(TO_SIGNS);
2228 bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && !IsInvisibilitySet(TO_SIGNS);
2229 bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES);
2230 bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS);
2231 bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
2232
2233 /* Topmost of each type that was hit */
2234 BaseStation *st = nullptr, *last_st = nullptr;
2235 Town *t = nullptr, *last_t = nullptr;
2236 Sign *si = nullptr, *last_si = nullptr;
2237
2238 /* See ViewportAddKdtreeSigns() for details on the search logic */
2239 _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) {
2240 switch (item.type) {
2241 case ViewportSignKdtreeItem::VKI_STATION:
2242 if (!show_stations) break;
2243 st = BaseStation::Get(item.id.station);
2244 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
2245 if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st;
2246 break;
2247
2248 case ViewportSignKdtreeItem::VKI_WAYPOINT:
2249 if (!show_waypoints) break;
2250 st = BaseStation::Get(item.id.station);
2251 if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break;
2252 if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st;
2253 break;
2254
2255 case ViewportSignKdtreeItem::VKI_TOWN:
2256 if (!show_towns) break;
2257 t = Town::Get(item.id.town);
2258 if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) last_t = t;
2259 break;
2260
2261 case ViewportSignKdtreeItem::VKI_SIGN:
2262 if (!show_signs) break;
2263 si = Sign::Get(item.id.sign);
2264 if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break;
2265 if (CheckClickOnViewportSign(vp, x, y, &si->sign)) last_si = si;
2266 break;
2267
2268 default:
2269 NOT_REACHED();
2270 }
2271 });
2272
2273 /* Select which hit to handle based on priority */
2274 if (last_st != nullptr) {
2275 if (Station::IsExpected(last_st)) {
2276 ShowStationViewWindow(last_st->index);
2277 } else {
2278 ShowWaypointWindow(Waypoint::From(last_st));
2279 }
2280 return true;
2281 } else if (last_t != nullptr) {
2282 ShowTownViewWindow(last_t->index);
2283 return true;
2284 } else if (last_si != nullptr) {
2285 HandleClickOnSign(last_si);
2286 return true;
2287 } else {
2288 return false;
2289 }
2290}
2291
2292
2293 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id)
2294{
2295 ViewportSignKdtreeItem item;
2296 item.type = VKI_STATION;
2297 item.id.station = id;
2298
2299 const Station *st = Station::Get(id);
2300 assert(st->sign.kdtree_valid);
2301 item.center = st->sign.center;
2302 item.top = st->sign.top;
2303
2304 /* Assume the sign can be a candidate for drawing, so measure its width */
2305 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, st->sign.width_normal, st->sign.width_small});
2306
2307 return item;
2308}
2309
2310 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id)
2311{
2312 ViewportSignKdtreeItem item;
2313 item.type = VKI_WAYPOINT;
2314 item.id.station = id;
2315
2316 const Waypoint *st = Waypoint::Get(id);
2317 assert(st->sign.kdtree_valid);
2318 item.center = st->sign.center;
2319 item.top = st->sign.top;
2320
2321 /* Assume the sign can be a candidate for drawing, so measure its width */
2322 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, st->sign.width_normal, st->sign.width_small});
2323
2324 return item;
2325}
2326
2327 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id)
2328{
2329 ViewportSignKdtreeItem item;
2330 item.type = VKI_TOWN;
2331 item.id.town = id;
2332
2333 const Town *town = Town::Get(id);
2334 assert(town->cache.sign.kdtree_valid);
2335 item.center = town->cache.sign.center;
2336 item.top = town->cache.sign.top;
2337
2338 /* Assume the sign can be a candidate for drawing, so measure its width */
2339 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, town->cache.sign.width_normal, town->cache.sign.width_small});
2340
2341 return item;
2342}
2343
2344 ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id)
2345{
2346 ViewportSignKdtreeItem item;
2347 item.type = VKI_SIGN;
2348 item.id.sign = id;
2349
2350 const Sign *sign = Sign::Get(id);
2351 assert(sign->sign.kdtree_valid);
2352 item.center = sign->sign.center;
2353 item.top = sign->sign.top;
2354
2355 /* Assume the sign can be a candidate for drawing, so measure its width */
2356 _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, sign->sign.width_normal, sign->sign.width_small});
2357
2358 return item;
2359}
2360
2361void RebuildViewportKdtree()
2362{
2363 /* Reset biggest size sign seen */
2364 _viewport_sign_maxwidth = 0;
2365
2366 std::vector<ViewportSignKdtreeItem> items;
2367 items.reserve(BaseStation::GetNumItems() + Town::GetNumItems() + Sign::GetNumItems());
2368
2369 for (const Station *st : Station::Iterate()) {
2370 if (st->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeStation(st->index));
2371 }
2372
2373 for (const Waypoint *wp : Waypoint::Iterate()) {
2374 if (wp->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeWaypoint(wp->index));
2375 }
2376
2377 for (const Town *town : Town::Iterate()) {
2378 if (town->cache.sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeTown(town->index));
2379 }
2380
2381 for (const Sign *sign : Sign::Iterate()) {
2382 if (sign->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeSign(sign->index));
2383 }
2384
2385 _viewport_sign_kdtree.Build(items.begin(), items.end());
2386}
2387
2388
2389static bool CheckClickOnLandscape(const Viewport *vp, int x, int y)
2390{
2391 Point pt = TranslateXYToTileCoord(vp, x, y);
2392
2393 if (pt.x != -1) return ClickTile(TileVirtXY(pt.x, pt.y));
2394 return true;
2395}
2396
2397static void PlaceObject()
2398{
2399 Point pt;
2400 Window *w;
2401
2402 pt = GetTileBelowCursor();
2403 if (pt.x == -1) return;
2404
2405 if ((_thd.place_mode & HT_DRAG_MASK) == HT_POINT) {
2406 pt.x += TILE_SIZE / 2;
2407 pt.y += TILE_SIZE / 2;
2408 }
2409
2410 _tile_fract_coords.x = pt.x & TILE_UNIT_MASK;
2411 _tile_fract_coords.y = pt.y & TILE_UNIT_MASK;
2412
2413 w = _thd.GetCallbackWnd();
2414 if (w != nullptr) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y));
2415}
2416
2417
2418bool HandleViewportClicked(const Viewport *vp, int x, int y)
2419{
2420 const Vehicle *v = CheckClickOnVehicle(vp, x, y);
2421
2422 if (_thd.place_mode & HT_VEHICLE) {
2423 if (v != nullptr && VehicleClicked(v)) return true;
2424 }
2425
2426 /* Vehicle placement mode already handled above. */
2427 if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
2428 PlaceObject();
2429 return true;
2430 }
2431
2432 if (CheckClickOnViewportSign(vp, x, y)) return true;
2433 bool result = CheckClickOnLandscape(vp, x, y);
2434
2435 if (v != nullptr) {
2436 Debug(misc, 2, "Vehicle {} (index {}) at {}", v->unitnumber, v->index, fmt::ptr(v));
2437 if (IsCompanyBuildableVehicleType(v)) {
2438 v = v->First();
2439 if (_ctrl_pressed && v->owner == _local_company) {
2440 StartStopVehicle(v, true);
2441 } else {
2442 ShowVehicleViewWindow(v);
2443 }
2444 }
2445 return true;
2446 }
2447 return result;
2448}
2449
2450void RebuildViewportOverlay(Window *w)
2451{
2452 if (w->viewport->overlay != nullptr &&
2453 w->viewport->overlay->GetCompanyMask() != 0 &&
2454 w->viewport->overlay->GetCargoMask() != 0) {
2455 w->viewport->overlay->SetDirty();
2456 w->SetDirty();
2457 }
2458}
2459
2469 bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant)
2470{
2471 /* The slope cannot be acquired outside of the map, so make sure we are always within the map. */
2472 if (z == -1) {
2473 if ( x >= 0 && x <= (int)Map::SizeX() * (int)TILE_SIZE - 1
2474 && y >= 0 && y <= (int)Map::SizeY() * (int)TILE_SIZE - 1) {
2475 z = GetSlopePixelZ(x, y);
2476 } else {
2477 z = TileHeightOutsideMap(x / (int)TILE_SIZE, y / (int)TILE_SIZE);
2478 }
2479 }
2480
2481 Point pt = MapXYZToViewport(w->viewport, x, y, z);
2482 w->viewport->follow_vehicle = INVALID_VEHICLE;
2483
2484 if (w->viewport->dest_scrollpos_x == pt.x && w->viewport->dest_scrollpos_y == pt.y) return false;
2485
2486 if (instant) {
2487 w->viewport->scrollpos_x = pt.x;
2488 w->viewport->scrollpos_y = pt.y;
2489 RebuildViewportOverlay(w);
2490 }
2491
2492 w->viewport->dest_scrollpos_x = pt.x;
2493 w->viewport->dest_scrollpos_y = pt.y;
2494 return true;
2495}
2496
2504 bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
2505{
2506 return ScrollWindowTo(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, -1, w, instant);
2507}
2508
2515 bool ScrollMainWindowToTile(TileIndex tile, bool instant)
2516{
2517 return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, instant);
2518}
2519
2524 void SetRedErrorSquare(TileIndex tile)
2525{
2526 TileIndex old;
2527
2528 old = _thd.redsq;
2529 _thd.redsq = tile;
2530
2531 if (tile != old) {
2532 if (tile != INVALID_TILE) MarkTileDirtyByTile(tile);
2533 if (old != INVALID_TILE) MarkTileDirtyByTile(old);
2534 }
2535}
2536
2542 void SetTileSelectSize(int w, int h)
2543{
2544 _thd.new_size.x = w * TILE_SIZE;
2545 _thd.new_size.y = h * TILE_SIZE;
2546 _thd.new_outersize.x = 0;
2547 _thd.new_outersize.y = 0;
2548}
2549
2550void SetTileSelectBigSize(int ox, int oy, int sx, int sy)
2551{
2552 _thd.offs.x = ox * TILE_SIZE;
2553 _thd.offs.y = oy * TILE_SIZE;
2554 _thd.new_outersize.x = sx * TILE_SIZE;
2555 _thd.new_outersize.y = sy * TILE_SIZE;
2556}
2557
2559 static HighLightStyle GetAutorailHT(int x, int y)
2560{
2561 return HT_RAIL | _autorail_piece[x & TILE_UNIT_MASK][y & TILE_UNIT_MASK];
2562}
2563
2567 void TileHighlightData::Reset()
2568{
2569 this->pos.x = 0;
2570 this->pos.y = 0;
2571 this->new_pos.x = 0;
2572 this->new_pos.y = 0;
2573}
2574
2579 bool TileHighlightData::IsDraggingDiagonal()
2580{
2581 return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down;
2582}
2583
2588 Window *TileHighlightData::GetCallbackWnd()
2589{
2590 return FindWindowById(this->window_class, this->window_number);
2591}
2592
2593
2594
2602 void UpdateTileSelection()
2603{
2604 int x1;
2605 int y1;
2606
2607 if (_thd.freeze) return;
2608
2609 HighLightStyle new_drawstyle = HT_NONE;
2610 bool new_diagonal = false;
2611
2612 if ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL) {
2613 x1 = _thd.selend.x;
2614 y1 = _thd.selend.y;
2615 if (x1 != -1) {
2616 int x2 = _thd.selstart.x & ~TILE_UNIT_MASK;
2617 int y2 = _thd.selstart.y & ~TILE_UNIT_MASK;
2618 x1 &= ~TILE_UNIT_MASK;
2619 y1 &= ~TILE_UNIT_MASK;
2620
2621 if (_thd.IsDraggingDiagonal()) {
2622 new_diagonal = true;
2623 } else {
2624 if (x1 >= x2) Swap(x1, x2);
2625 if (y1 >= y2) Swap(y1, y2);
2626 }
2627 _thd.new_pos.x = x1;
2628 _thd.new_pos.y = y1;
2629 _thd.new_size.x = x2 - x1;
2630 _thd.new_size.y = y2 - y1;
2631 if (!new_diagonal) {
2632 _thd.new_size.x += TILE_SIZE;
2633 _thd.new_size.y += TILE_SIZE;
2634 }
2635 new_drawstyle = _thd.next_drawstyle;
2636 }
2637 } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
2638 Point pt = GetTileBelowCursor();
2639 x1 = pt.x;
2640 y1 = pt.y;
2641 if (x1 != -1) {
2642 switch (_thd.place_mode & HT_DRAG_MASK) {
2643 case HT_RECT:
2644 new_drawstyle = HT_RECT;
2645 break;
2646 case HT_POINT:
2647 new_drawstyle = HT_POINT;
2648 x1 += TILE_SIZE / 2;
2649 y1 += TILE_SIZE / 2;
2650 break;
2651 case HT_RAIL:
2652 /* Draw one highlighted tile in any direction */
2653 new_drawstyle = GetAutorailHT(pt.x, pt.y);
2654 break;
2655 case HT_LINE:
2656 switch (_thd.place_mode & HT_DIR_MASK) {
2657 case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break;
2658 case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break;
2659
2660 case HT_DIR_HU:
2661 case HT_DIR_HL:
2662 new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL;
2663 break;
2664
2665 case HT_DIR_VL:
2666 case HT_DIR_VR:
2667 new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
2668 break;
2669
2670 default: NOT_REACHED();
2671 }
2672 _thd.selstart.x = x1 & ~TILE_UNIT_MASK;
2673 _thd.selstart.y = y1 & ~TILE_UNIT_MASK;
2674 break;
2675 default:
2676 NOT_REACHED();
2677 }
2678 _thd.new_pos.x = x1 & ~TILE_UNIT_MASK;
2679 _thd.new_pos.y = y1 & ~TILE_UNIT_MASK;
2680 }
2681 }
2682
2683 /* redraw selection */
2684 if (_thd.drawstyle != new_drawstyle ||
2685 _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
2686 _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y ||
2687 _thd.outersize.x != _thd.new_outersize.x ||
2688 _thd.outersize.y != _thd.new_outersize.y ||
2689 _thd.diagonal != new_diagonal) {
2690 /* Clear the old tile selection? */
2691 if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
2692
2693 _thd.drawstyle = new_drawstyle;
2694 _thd.pos = _thd.new_pos;
2695 _thd.size = _thd.new_size;
2696 _thd.outersize = _thd.new_outersize;
2697 _thd.diagonal = new_diagonal;
2698 _thd.dirty = 0xff;
2699
2700 /* Draw the new tile selection? */
2701 if ((new_drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
2702 }
2703}
2704
2710 static inline void ShowMeasurementTooltips(StringID str, uint paramcount)
2711{
2712 if (!_settings_client.gui.measure_tooltip) return;
2713 GuiShowTooltips(_thd.GetCallbackWnd(), str, TCC_EXIT_VIEWPORT, paramcount);
2714}
2715
2716static void HideMeasurementTooltips()
2717{
2718 CloseWindowById(WC_TOOLTIPS, 0);
2719}
2720
2722 void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
2723{
2724 _thd.select_method = method;
2725 _thd.select_proc = process;
2726 _thd.selend.x = TileX(tile) * TILE_SIZE;
2727 _thd.selstart.x = TileX(tile) * TILE_SIZE;
2728 _thd.selend.y = TileY(tile) * TILE_SIZE;
2729 _thd.selstart.y = TileY(tile) * TILE_SIZE;
2730
2731 /* Needed so several things (road, autoroad, bridges, ...) are placed correctly.
2732 * In effect, placement starts from the centre of a tile
2733 */
2734 if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) {
2735 _thd.selend.x += TILE_SIZE / 2;
2736 _thd.selend.y += TILE_SIZE / 2;
2737 _thd.selstart.x += TILE_SIZE / 2;
2738 _thd.selstart.y += TILE_SIZE / 2;
2739 }
2740
2741 HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
2742 if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) {
2743 _thd.place_mode = HT_SPECIAL | others;
2744 _thd.next_drawstyle = HT_RECT | others;
2745 } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) {
2746 _thd.place_mode = HT_SPECIAL | others;
2747 _thd.next_drawstyle = _thd.drawstyle | others;
2748 } else {
2749 _thd.place_mode = HT_SPECIAL | others;
2750 _thd.next_drawstyle = HT_POINT | others;
2751 }
2752 _special_mouse_mode = WSM_SIZING;
2753}
2754
2756 void VpStartDragging(ViewportDragDropSelectionProcess process)
2757{
2758 _thd.select_method = VPM_X_AND_Y;
2759 _thd.select_proc = process;
2760 _thd.selstart.x = 0;
2761 _thd.selstart.y = 0;
2762 _thd.next_drawstyle = HT_RECT;
2763
2764 _special_mouse_mode = WSM_DRAGGING;
2765}
2766
2767void VpSetPlaceSizingLimit(int limit)
2768{
2769 _thd.sizelimit = limit;
2770}
2771
2777 void VpSetPresizeRange(TileIndex from, TileIndex to)
2778{
2779 uint64_t distance = DistanceManhattan(from, to) + 1;
2780
2781 _thd.selend.x = TileX(to) * TILE_SIZE;
2782 _thd.selend.y = TileY(to) * TILE_SIZE;
2783 _thd.selstart.x = TileX(from) * TILE_SIZE;
2784 _thd.selstart.y = TileY(from) * TILE_SIZE;
2785 _thd.next_drawstyle = HT_RECT;
2786
2787 /* show measurement only if there is any length to speak of */
2788 if (distance > 1) {
2789 SetDParam(0, distance);
2790 ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1);
2791 } else {
2792 HideMeasurementTooltips();
2793 }
2794}
2795
2796static void VpStartPreSizing()
2797{
2798 _thd.selend.x = -1;
2799 _special_mouse_mode = WSM_PRESIZE;
2800}
2801
2806 static HighLightStyle Check2x1AutoRail(int mode)
2807{
2808 int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
2809 int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK);
2810 int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
2811 int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK);
2812
2813 switch (mode) {
2814 default: NOT_REACHED();
2815 case 0: // end piece is lower right
2816 if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
2817 if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
2818 return HT_DIR_Y;
2819
2820 case 1:
2821 if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
2822 if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
2823 return HT_DIR_Y;
2824
2825 case 2:
2826 if (fxmy > 3 && sxmy < -3) return HT_DIR_VL;
2827 if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL;
2828 return HT_DIR_X;
2829
2830 case 3:
2831 if (fxmy < -3 && sxmy > 3) return HT_DIR_VR;
2832 if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU;
2833 return HT_DIR_X;
2834 }
2835}
2836
2850 static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile)
2851{
2852 uint start_x = TileX(start_tile);
2853 uint start_y = TileY(start_tile);
2854 uint end_x = TileX(end_tile);
2855 uint end_y = TileY(end_tile);
2856
2857 switch (style & HT_DRAG_MASK) {
2858 case HT_RAIL:
2859 case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y));
2860
2861 case HT_RECT:
2862 case HT_POINT: return (end_x != start_x && end_y < start_y);
2863 default: NOT_REACHED();
2864 }
2865
2866 return false;
2867}
2868
2884 static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile)
2885{
2886 bool swap = SwapDirection(style, start_tile, end_tile);
2887 uint h0, h1; // Start height and end height.
2888
2889 if (start_tile == end_tile) return 0;
2890 if (swap) Swap(start_tile, end_tile);
2891
2892 switch (style & HT_DRAG_MASK) {
2893 case HT_RECT:
2894 /* In the case of an area we can determine whether we were dragging south or
2895 * east by checking the X-coordinates of the tiles */
2896 if (TileX(end_tile) > TileX(start_tile)) {
2897 /* Dragging south does not need to change the start tile. */
2898 end_tile = TileAddByDir(end_tile, DIR_S);
2899 } else {
2900 /* Dragging east. */
2901 start_tile = TileAddByDir(start_tile, DIR_SW);
2902 end_tile = TileAddByDir(end_tile, DIR_SE);
2903 }
2904 [[fallthrough]];
2905
2906 case HT_POINT:
2907 h0 = TileHeight(start_tile);
2908 h1 = TileHeight(end_tile);
2909 break;
2910 default: { // All other types, this is mostly only line/autorail
2911 static const HighLightStyle flip_style_direction[] = {
2912 HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL
2913 };
2914 static const std::pair<TileIndexDiffC, TileIndexDiffC> start_heightdiff_line_by_dir[] = {
2915 { {1, 0}, {1, 1} }, // HT_DIR_X
2916 { {0, 1}, {1, 1} }, // HT_DIR_Y
2917 { {1, 0}, {0, 0} }, // HT_DIR_HU
2918 { {1, 0}, {1, 1} }, // HT_DIR_HL
2919 { {1, 0}, {1, 1} }, // HT_DIR_VL
2920 { {0, 1}, {1, 1} }, // HT_DIR_VR
2921 };
2922 static const std::pair<TileIndexDiffC, TileIndexDiffC> end_heightdiff_line_by_dir[] = {
2923 { {0, 1}, {0, 0} }, // HT_DIR_X
2924 { {1, 0}, {0, 0} }, // HT_DIR_Y
2925 { {0, 1}, {0, 0} }, // HT_DIR_HU
2926 { {1, 1}, {0, 1} }, // HT_DIR_HL
2927 { {1, 0}, {0, 0} }, // HT_DIR_VL
2928 { {0, 0}, {0, 1} }, // HT_DIR_VR
2929 };
2930 static_assert(std::size(start_heightdiff_line_by_dir) == HT_DIR_END);
2931 static_assert(std::size(end_heightdiff_line_by_dir) == HT_DIR_END);
2932
2933 distance %= 2; // we're only interested if the distance is even or uneven
2934 style &= HT_DIR_MASK;
2935 assert(style < HT_DIR_END);
2936
2937 /* To handle autorail, we do some magic to be able to use a lookup table.
2938 * Firstly if we drag the other way around, we switch start&end, and if needed
2939 * also flip the drag-position. Eg if it was on the left, and the distance is even
2940 * that means the end, which is now the start is on the right */
2941 if (swap && distance == 0) style = flip_style_direction[style];
2942
2943 /* Lambda to help calculating the height at one side of the line. */
2944 auto get_height = [](auto &tile, auto &heightdiffs) {
2945 return std::max(
2946 TileHeight(TileAdd(tile, ToTileIndexDiff(heightdiffs.first))),
2947 TileHeight(TileAdd(tile, ToTileIndexDiff(heightdiffs.second))));
2948 };
2949
2950 /* Use lookup table for start-tile based on HighLightStyle direction */
2951 h0 = get_height(start_tile, start_heightdiff_line_by_dir[style]);
2952
2953 /* Use lookup table for end-tile based on HighLightStyle direction
2954 * flip around side (lower/upper, left/right) based on distance */
2955 if (distance == 0) style = flip_style_direction[style];
2956 h1 = get_height(end_tile, end_heightdiff_line_by_dir[style]);
2957 break;
2958 }
2959 }
2960
2961 if (swap) Swap(h0, h1);
2962 return (int)(h1 - h0) * TILE_HEIGHT_STEP;
2963}
2964
2965static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
2966
2973 static void CheckUnderflow(int &test, int &other, int mult)
2974{
2975 if (test >= 0) return;
2976
2977 other += mult * test;
2978 test = 0;
2979}
2980
2988 static void CheckOverflow(int &test, int &other, int max, int mult)
2989{
2990 if (test <= max) return;
2991
2992 other += mult * (test - max);
2993 test = max;
2994}
2995
2997 static void CalcRaildirsDrawstyle(int x, int y, int method)
2998{
2999 HighLightStyle b;
3000
3001 int dx = _thd.selstart.x - (_thd.selend.x & ~TILE_UNIT_MASK);
3002 int dy = _thd.selstart.y - (_thd.selend.y & ~TILE_UNIT_MASK);
3003 uint w = abs(dx) + TILE_SIZE;
3004 uint h = abs(dy) + TILE_SIZE;
3005
3006 if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) {
3007 /* We 'force' a selection direction; first four rail buttons. */
3008 method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS);
3009 int raw_dx = _thd.selstart.x - _thd.selend.x;
3010 int raw_dy = _thd.selstart.y - _thd.selend.y;
3011 switch (method) {
3012 case VPM_FIX_X:
3013 b = HT_LINE | HT_DIR_Y;
3014 x = _thd.selstart.x;
3015 break;
3016
3017 case VPM_FIX_Y:
3018 b = HT_LINE | HT_DIR_X;
3019 y = _thd.selstart.y;
3020 break;
3021
3022 case VPM_FIX_HORIZONTAL:
3023 if (dx == -dy) {
3024 /* We are on a straight horizontal line. Determine the 'rail'
3025 * to build based the sub tile location. */
3026 b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
3027 } else {
3028 /* We are not on a straight line. Determine the rail to build
3029 * based on whether we are above or below it. */
3030 b = dx + dy >= (int)TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL;
3031
3032 /* Calculate where a horizontal line through the start point and
3033 * a vertical line from the selected end point intersect and
3034 * use that point as the end point. */
3035 int offset = (raw_dx - raw_dy) / 2;
3036 x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK);
3037 y = _thd.selstart.y + (offset & ~TILE_UNIT_MASK);
3038
3039 /* 'Build' the last half rail tile if needed */
3040 if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) {
3041 if (dx + dy >= (int)TILE_SIZE) {
3042 x += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE;
3043 } else {
3044 y += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE;
3045 }
3046 }
3047
3048 /* Make sure we do not overflow the map! */
3049 CheckUnderflow(x, y, 1);
3050 CheckUnderflow(y, x, 1);
3051 CheckOverflow(x, y, (Map::MaxX() - 1) * TILE_SIZE, 1);
3052 CheckOverflow(y, x, (Map::MaxY() - 1) * TILE_SIZE, 1);
3053 assert(x >= 0 && y >= 0 && x <= (int)(Map::MaxX() * TILE_SIZE) && y <= (int)(Map::MaxY() * TILE_SIZE));
3054 }
3055 break;
3056
3057 case VPM_FIX_VERTICAL:
3058 if (dx == dy) {
3059 /* We are on a straight vertical line. Determine the 'rail'
3060 * to build based the sub tile location. */
3061 b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3062 } else {
3063 /* We are not on a straight line. Determine the rail to build
3064 * based on whether we are left or right from it. */
3065 b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3066
3067 /* Calculate where a vertical line through the start point and
3068 * a horizontal line from the selected end point intersect and
3069 * use that point as the end point. */
3070 int offset = (raw_dx + raw_dy + (int)TILE_SIZE) / 2;
3071 x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK);
3072 y = _thd.selstart.y - (offset & ~TILE_UNIT_MASK);
3073
3074 /* 'Build' the last half rail tile if needed */
3075 if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) {
3076 if (dx - dy < 0) {
3077 y += (dx > dy) ? (int)TILE_SIZE : -(int)TILE_SIZE;
3078 } else {
3079 x += (dx < dy) ? (int)TILE_SIZE : -(int)TILE_SIZE;
3080 }
3081 }
3082
3083 /* Make sure we do not overflow the map! */
3084 CheckUnderflow(x, y, -1);
3085 CheckUnderflow(y, x, -1);
3086 CheckOverflow(x, y, (Map::MaxX() - 1) * TILE_SIZE, -1);
3087 CheckOverflow(y, x, (Map::MaxY() - 1) * TILE_SIZE, -1);
3088 assert(x >= 0 && y >= 0 && x <= (int)(Map::MaxX() * TILE_SIZE) && y <= (int)(Map::MaxY() * TILE_SIZE));
3089 }
3090 break;
3091
3092 default:
3093 NOT_REACHED();
3094 }
3095 } else if (TileVirtXY(_thd.selstart.x, _thd.selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile
3096 if (method & VPM_RAILDIRS) {
3097 b = GetAutorailHT(x, y);
3098 } else { // rect for autosignals on one tile
3099 b = HT_RECT;
3100 }
3101 } else if (h == TILE_SIZE) { // Is this in X direction?
3102 if (dx == (int)TILE_SIZE) { // 2x1 special handling
3103 b = (Check2x1AutoRail(3)) | HT_LINE;
3104 } else if (dx == -(int)TILE_SIZE) {
3105 b = (Check2x1AutoRail(2)) | HT_LINE;
3106 } else {
3107 b = HT_LINE | HT_DIR_X;
3108 }
3109 y = _thd.selstart.y;
3110 } else if (w == TILE_SIZE) { // Or Y direction?
3111 if (dy == (int)TILE_SIZE) { // 2x1 special handling
3112 b = (Check2x1AutoRail(1)) | HT_LINE;
3113 } else if (dy == -(int)TILE_SIZE) { // 2x1 other direction
3114 b = (Check2x1AutoRail(0)) | HT_LINE;
3115 } else {
3116 b = HT_LINE | HT_DIR_Y;
3117 }
3118 x = _thd.selstart.x;
3119 } else if (w > h * 2) { // still count as x dir?
3120 b = HT_LINE | HT_DIR_X;
3121 y = _thd.selstart.y;
3122 } else if (h > w * 2) { // still count as y dir?
3123 b = HT_LINE | HT_DIR_Y;
3124 x = _thd.selstart.x;
3125 } else { // complicated direction
3126 int d = w - h;
3127 _thd.selend.x = _thd.selend.x & ~TILE_UNIT_MASK;
3128 _thd.selend.y = _thd.selend.y & ~TILE_UNIT_MASK;
3129
3130 /* four cases. */
3131 if (x > _thd.selstart.x) {
3132 if (y > _thd.selstart.y) {
3133 /* south */
3134 if (d == 0) {
3135 b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3136 } else if (d >= 0) {
3137 x = _thd.selstart.x + h;
3138 b = HT_LINE | HT_DIR_VL;
3139 } else {
3140 y = _thd.selstart.y + w;
3141 b = HT_LINE | HT_DIR_VR;
3142 }
3143 } else {
3144 /* west */
3145 if (d == 0) {
3146 b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
3147 } else if (d >= 0) {
3148 x = _thd.selstart.x + h;
3149 b = HT_LINE | HT_DIR_HL;
3150 } else {
3151 y = _thd.selstart.y - w;
3152 b = HT_LINE | HT_DIR_HU;
3153 }
3154 }
3155 } else {
3156 if (y > _thd.selstart.y) {
3157 /* east */
3158 if (d == 0) {
3159 b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
3160 } else if (d >= 0) {
3161 x = _thd.selstart.x - h;
3162 b = HT_LINE | HT_DIR_HU;
3163 } else {
3164 y = _thd.selstart.y + w;
3165 b = HT_LINE | HT_DIR_HL;
3166 }
3167 } else {
3168 /* north */
3169 if (d == 0) {
3170 b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
3171 } else if (d >= 0) {
3172 x = _thd.selstart.x - h;
3173 b = HT_LINE | HT_DIR_VR;
3174 } else {
3175 y = _thd.selstart.y - w;
3176 b = HT_LINE | HT_DIR_VL;
3177 }
3178 }
3179 }
3180 }
3181
3182 if (_settings_client.gui.measure_tooltip) {
3183 TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
3184 TileIndex t1 = TileVirtXY(x, y);
3185 uint distance = DistanceManhattan(t0, t1) + 1;
3186 uint8_t index = 0;
3187
3188 if (distance != 1) {
3189 int heightdiff = CalcHeightdiff(b, distance, t0, t1);
3190 /* If we are showing a tooltip for horizontal or vertical drags,
3191 * 2 tiles have a length of 1. To bias towards the ceiling we add
3192 * one before division. It feels more natural to count 3 lengths as 2 */
3193 if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) {
3194 distance = CeilDiv(distance, 2);
3195 }
3196
3197 SetDParam(index++, distance);
3198 if (heightdiff != 0) SetDParam(index++, heightdiff);
3199 }
3200
3201 ShowMeasurementTooltips(measure_strings_length[index], index);
3202 }
3203
3204 _thd.selend.x = x;
3205 _thd.selend.y = y;
3206 _thd.next_drawstyle = b;
3207}
3208
3216 void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method)
3217{
3218 int sx, sy;
3219 HighLightStyle style;
3220
3221 if (x == -1) {
3222 _thd.selend.x = -1;
3223 return;
3224 }
3225
3226 /* Special handling of drag in any (8-way) direction */
3227 if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) {
3228 _thd.selend.x = x;
3229 _thd.selend.y = y;
3230 CalcRaildirsDrawstyle(x, y, method);
3231 return;
3232 }
3233
3234 /* Needed so level-land is placed correctly */
3235 if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_POINT) {
3236 x += TILE_SIZE / 2;
3237 y += TILE_SIZE / 2;
3238 }
3239
3240 sx = _thd.selstart.x;
3241 sy = _thd.selstart.y;
3242
3243 int limit = 0;
3244
3245 switch (method) {
3246 case VPM_X_OR_Y: // drag in X or Y direction
3247 if (abs(sy - y) < abs(sx - x)) {
3248 y = sy;
3249 style = HT_DIR_X;
3250 } else {
3251 x = sx;
3252 style = HT_DIR_Y;
3253 }
3254 goto calc_heightdiff_single_direction;
3255
3256 case VPM_X_LIMITED: // Drag in X direction (limited size).
3257 limit = (_thd.sizelimit - 1) * TILE_SIZE;
3258 [[fallthrough]];
3259
3260 case VPM_FIX_X: // drag in Y direction
3261 x = sx;
3262 style = HT_DIR_Y;
3263 goto calc_heightdiff_single_direction;
3264
3265 case VPM_Y_LIMITED: // Drag in Y direction (limited size).
3266 limit = (_thd.sizelimit - 1) * TILE_SIZE;
3267 [[fallthrough]];
3268
3269 case VPM_FIX_Y: // drag in X direction
3270 y = sy;
3271 style = HT_DIR_X;
3272
3273calc_heightdiff_single_direction:;
3274 if (limit > 0) {
3275 x = sx + Clamp(x - sx, -limit, limit);
3276 y = sy + Clamp(y - sy, -limit, limit);
3277 }
3278 if (_settings_client.gui.measure_tooltip) {
3279 TileIndex t0 = TileVirtXY(sx, sy);
3280 TileIndex t1 = TileVirtXY(x, y);
3281 uint distance = DistanceManhattan(t0, t1) + 1;
3282 uint8_t index = 0;
3283
3284 if (distance != 1) {
3285 /* With current code passing a HT_LINE style to calculate the height
3286 * difference is enough. However if/when a point-tool is created
3287 * with this method, function should be called with new_style (below)
3288 * instead of HT_LINE | style case HT_POINT is handled specially
3289 * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
3290 int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1);
3291
3292 SetDParam(index++, distance);
3293 if (heightdiff != 0) SetDParam(index++, heightdiff);
3294 }
3295
3296 ShowMeasurementTooltips(measure_strings_length[index], index);
3297 }
3298 break;
3299
3300 case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area.
3301 limit = (_thd.sizelimit - 1) * TILE_SIZE;
3302 x = sx + Clamp(x - sx, -limit, limit);
3303 y = sy + Clamp(y - sy, -limit, limit);
3304 [[fallthrough]];
3305
3306 case VPM_X_AND_Y: // drag an X by Y area
3307 if (_settings_client.gui.measure_tooltip) {
3308 static const StringID measure_strings_area[] = {
3309 STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
3310 };
3311
3312 TileIndex t0 = TileVirtXY(sx, sy);
3313 TileIndex t1 = TileVirtXY(x, y);
3314 uint dx = Delta(TileX(t0), TileX(t1)) + 1;
3315 uint dy = Delta(TileY(t0), TileY(t1)) + 1;
3316 uint8_t index = 0;
3317
3318 /* If dragging an area (eg dynamite tool) and it is actually a single
3319 * row/column, change the type to 'line' to get proper calculation for height */
3320 style = (HighLightStyle)_thd.next_drawstyle;
3321 if (_thd.IsDraggingDiagonal()) {
3322 /* Determine the "area" of the diagonal dragged selection.
3323 * We assume the area is the number of tiles along the X
3324 * edge and the number of tiles along the Y edge. However,
3325 * multiplying these two numbers does not give the exact
3326 * number of tiles; basically we are counting the black
3327 * squares on a chess board and ignore the white ones to
3328 * make the tile counts at the edges match up. There is no
3329 * other way to make a proper count though.
3330 *
3331 * First convert to the rotated coordinate system. */
3332 int dist_x = TileX(t0) - TileX(t1);
3333 int dist_y = TileY(t0) - TileY(t1);
3334 int a_max = dist_x + dist_y;
3335 int b_max = dist_y - dist_x;
3336
3337 /* Now determine the size along the edge, but due to the
3338 * chess board principle this counts double. */
3339 a_max = abs(a_max + (a_max > 0 ? 2 : -2)) / 2;
3340 b_max = abs(b_max + (b_max > 0 ? 2 : -2)) / 2;
3341
3342 /* We get a 1x1 on normal 2x1 rectangles, due to it being
3343 * a seen as two sides. As the result for actual building
3344 * will be the same as non-diagonal dragging revert to that
3345 * behaviour to give it a more normally looking size. */
3346 if (a_max != 1 || b_max != 1) {
3347 dx = a_max;
3348 dy = b_max;
3349 }
3350 } else if (style & HT_RECT) {
3351 if (dx == 1) {
3352 style = HT_LINE | HT_DIR_Y;
3353 } else if (dy == 1) {
3354 style = HT_LINE | HT_DIR_X;
3355 }
3356 }
3357
3358 if (dx != 1 || dy != 1) {
3359 int heightdiff = CalcHeightdiff(style, 0, t0, t1);
3360
3361 SetDParam(index++, dx - (style & HT_POINT ? 1 : 0));
3362 SetDParam(index++, dy - (style & HT_POINT ? 1 : 0));
3363 if (heightdiff != 0) SetDParam(index++, heightdiff);
3364 }
3365
3366 ShowMeasurementTooltips(measure_strings_area[index], index);
3367 }
3368 break;
3369
3370 default: NOT_REACHED();
3371 }
3372
3373 _thd.selend.x = x;
3374 _thd.selend.y = y;
3375}
3376
3381 EventState VpHandlePlaceSizingDrag()
3382{
3383 if (_special_mouse_mode != WSM_SIZING && _special_mouse_mode != WSM_DRAGGING) return ES_NOT_HANDLED;
3384
3385 /* stop drag mode if the window has been closed */
3386 Window *w = _thd.GetCallbackWnd();
3387 if (w == nullptr) {
3388 ResetObjectToPlace();
3389 return ES_HANDLED;
3390 }
3391
3392 /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
3393 if (_left_button_down) {
3394 if (_special_mouse_mode == WSM_DRAGGING) {
3395 /* Only register a drag event when the mouse moved. */
3396 if (_thd.new_pos.x == _thd.selstart.x && _thd.new_pos.y == _thd.selstart.y) return ES_HANDLED;
3397 _thd.selstart.x = _thd.new_pos.x;
3398 _thd.selstart.y = _thd.new_pos.y;
3399 }
3400
3401 w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
3402 return ES_HANDLED;
3403 }
3404
3405 /* Mouse button released. */
3406 _special_mouse_mode = WSM_NONE;
3407 if (_special_mouse_mode == WSM_DRAGGING) return ES_HANDLED;
3408
3409 /* Keep the selected tool, but reset it to the original mode. */
3410 HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
3411 if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) {
3412 _thd.place_mode = HT_RECT | others;
3413 } else if (_thd.select_method & VPM_SIGNALDIRS) {
3414 _thd.place_mode = HT_RECT | others;
3415 } else if (_thd.select_method & VPM_RAILDIRS) {
3416 _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others);
3417 } else {
3418 _thd.place_mode = HT_POINT | others;
3419 }
3420 SetTileSelectSize(1, 1);
3421
3422 HideMeasurementTooltips();
3423 w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
3424
3425 return ES_HANDLED;
3426}
3427
3435 void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
3436{
3437 SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number);
3438}
3439
3440#include "table/animcursors.h"
3441
3450 void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
3451{
3452 if (_thd.window_class != WC_INVALID) {
3453 /* Undo clicking on button and drag & drop */
3454 Window *w = _thd.GetCallbackWnd();
3455 /* Call the abort function, but set the window class to something
3456 * that will never be used to avoid infinite loops. Setting it to
3457 * the 'next' window class must not be done because recursion into
3458 * this function might in some cases reset the newly set object to
3459 * place or not properly reset the original selection. */
3460 _thd.window_class = WC_INVALID;
3461 if (w != nullptr) {
3462 w->OnPlaceObjectAbort();
3463 HideMeasurementTooltips();
3464 }
3465 }
3466
3467 /* Mark the old selection dirty, in case the selection shape or colour changes */
3468 if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty();
3469
3470 SetTileSelectSize(1, 1);
3471
3472 _thd.make_square_red = false;
3473
3474 if (mode == HT_DRAG) { // HT_DRAG is for dragdropping trains in the depot window
3475 mode = HT_NONE;
3476 _special_mouse_mode = WSM_DRAGDROP;
3477 } else {
3478 _special_mouse_mode = WSM_NONE;
3479 }
3480
3481 _thd.place_mode = mode;
3482 _thd.window_class = window_class;
3483 _thd.window_number = window_num;
3484
3485 if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode
3486 VpStartPreSizing();
3487 }
3488
3489 if ((icon & ANIMCURSOR_FLAG) != 0) {
3490 SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]);
3491 } else {
3492 SetMouseCursor(icon, pal);
3493 }
3494
3495}
3496
3498 void ResetObjectToPlace()
3499{
3500 SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
3501}
3502
3503 Point GetViewportStationMiddle(const Viewport *vp, const Station *st)
3504{
3505 int x = TileX(st->xy) * TILE_SIZE;
3506 int y = TileY(st->xy) * TILE_SIZE;
3507 int z = GetSlopePixelZ(Clamp(x, 0, Map::SizeX() * TILE_SIZE - 1), Clamp(y, 0, Map::SizeY() * TILE_SIZE - 1));
3508
3509 Point p = RemapCoords(x, y, z);
3510 p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left;
3511 p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top;
3512 return p;
3513}
3514
3516 struct ViewportSSCSS {
3517 VpSorterChecker fct_checker;
3518 VpSpriteSorter fct_sorter;
3519};
3520
3522 static ViewportSSCSS _vp_sprite_sorters[] = {
3523#ifdef WITH_SSE
3524 { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
3525#endif
3526 { &ViewportSortParentSpritesChecker, &ViewportSortParentSprites }
3527};
3528
3530 void InitializeSpriteSorter()
3531{
3532 for (const auto &sprite_sorter : _vp_sprite_sorters) {
3533 if (sprite_sorter.fct_checker()) {
3534 _vp_sprite_sorter = sprite_sorter.fct_sorter;
3535 break;
3536 }
3537 }
3538 assert(_vp_sprite_sorter != nullptr);
3539}
3540
3549 CommandCost CmdScrollViewport(DoCommandFlag flags, TileIndex tile, ViewportScrollTarget target, uint32_t ref)
3550{
3551 if (_current_company != OWNER_DEITY) return CMD_ERROR;
3552 switch (target) {
3553 case VST_EVERYONE:
3554 break;
3555 case VST_COMPANY:
3556 if (_local_company != (CompanyID)ref) return CommandCost();
3557 break;
3558 case VST_CLIENT:
3559 if (_network_own_client_id != (ClientID)ref) return CommandCost();
3560 break;
3561 default:
3562 return CMD_ERROR;
3563 }
3564
3565 if (flags & DC_EXEC) {
3566 ResetObjectToPlace();
3567 ScrollMainWindowToTile(tile);
3568 }
3569 return CommandCost();
3570}
3571
3572void MarkCatchmentTilesDirty()
3573{
3574 if (_viewport_highlight_town != nullptr) {
3575 MarkWholeScreenDirty();
3576 return;
3577 }
3578 if (_viewport_highlight_station != nullptr) {
3579 if (_viewport_highlight_station->catchment_tiles.tile == INVALID_TILE) {
3580 MarkWholeScreenDirty();
3581 _viewport_highlight_station = nullptr;
3582 } else {
3583 BitmapTileIterator it(_viewport_highlight_station->catchment_tiles);
3584 for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
3585 MarkTileDirtyByTile(tile);
3586 }
3587 }
3588 }
3589 if (_viewport_highlight_waypoint != nullptr) {
3590 if (!_viewport_highlight_waypoint->IsInUse()) {
3591 _viewport_highlight_waypoint = nullptr;
3592 }
3593 MarkWholeScreenDirty();
3594 }
3595}
3596
3597static void SetWindowDirtyForViewportCatchment()
3598{
3599 if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index);
3600 if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index);
3601 if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index);
3602}
3603
3604static void ClearViewportCatchment()
3605{
3606 MarkCatchmentTilesDirty();
3607 _viewport_highlight_station = nullptr;
3608 _viewport_highlight_waypoint = nullptr;
3609 _viewport_highlight_town = nullptr;
3610}
3611
3618 void SetViewportCatchmentStation(const Station *st, bool sel)
3619{
3620 SetWindowDirtyForViewportCatchment();
3621 if (sel && _viewport_highlight_station != st) {
3622 ClearViewportCatchment();
3623 _viewport_highlight_station = st;
3624 MarkCatchmentTilesDirty();
3625 } else if (!sel && _viewport_highlight_station == st) {
3626 MarkCatchmentTilesDirty();
3627 _viewport_highlight_station = nullptr;
3628 }
3629 if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index);
3630}
3631
3638 void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel)
3639{
3640 SetWindowDirtyForViewportCatchment();
3641 if (sel && _viewport_highlight_waypoint != wp) {
3642 ClearViewportCatchment();
3643 _viewport_highlight_waypoint = wp;
3644 MarkCatchmentTilesDirty();
3645 } else if (!sel && _viewport_highlight_waypoint == wp) {
3646 MarkCatchmentTilesDirty();
3647 _viewport_highlight_waypoint = nullptr;
3648 }
3649 if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index);
3650}
3651
3658 void SetViewportCatchmentTown(const Town *t, bool sel)
3659{
3660 SetWindowDirtyForViewportCatchment();
3661 if (sel && _viewport_highlight_town != t) {
3662 ClearViewportCatchment();
3663 _viewport_highlight_town = t;
3664 MarkWholeScreenDirty();
3665 } else if (!sel && _viewport_highlight_town == t) {
3666 _viewport_highlight_town = nullptr;
3667 MarkWholeScreenDirty();
3668 }
3669 if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index);
3670}
animcursors.h
This file defines all the the animated cursors.
_animcursors
static const AnimCursor *const _animcursors[]
This is an array of pointers to all the animated cursor definitions we have above.
Definition animcursors.h:85
autorail.h
Highlight/sprite information for autorail.
backup_type.hpp
Class for backupping variables and making sure they are restored later.
HasBit
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
GB
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Definition bitmath_func.hpp:32
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
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:138
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, uint8_t colour)=0
Draw a pixel with a given colour on the video-buffer.
CommandCost
Common return value for all commands.
Definition command_type.h:23
Kdtree
K-dimensional tree, specialised for 2-dimensional space.
Definition kdtree.hpp:35
Kdtree::Build
void Build(It begin, It end)
Clear and rebuild the tree from a new sequence of elements,.
Definition kdtree.hpp:362
Kdtree::Count
size_t Count() const
Get number of elements stored in tree.
Definition kdtree.hpp:430
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:459
Kdtree::FindNearest
T FindNearest(CoordT x, CoordT y) const
Find the element closest to given coordinate, in Manhattan distance.
Definition kdtree.hpp:441
PerformanceAccumulator
RAII class for measuring multi-step elements of performance.
Definition framerate_type.h:114
WidgetDimensions
Definition window_gui.h:34
WidgetDimensions::scaled
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:28
WidgetDimensions::fullbevel
RectPadding fullbevel
Always-scaled bevel thickness.
Definition window_gui.h:41
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
DoCommandFlag
List of flags for a command.
Definition command_type.h:374
DC_EXEC
@ DC_EXEC
execute the given command
Definition command_type.h:376
company_base.h
Definition of stuff that is very close to a company, like the company struct itself.
_company_colours
Colours _company_colours[MAX_COMPANIES]
NOSAVE: can be determined from company structs.
Definition company_cmd.cpp:54
_local_company
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition company_cmd.cpp:52
_current_company
CompanyID _current_company
Company currently doing an action.
Definition company_cmd.cpp:53
company_func.h
Functions related to companies.
Owner
Owner
Enum for all companies/owners.
Definition company_type.h:18
OWNER_DEITY
@ OWNER_DEITY
The object is owned by a superuser / goal script.
Definition company_type.h:27
OWNER_NONE
@ OWNER_NONE
The tile has no ownership.
Definition company_type.h:25
Debug
#define Debug(category, level, format_string,...)
Ouptut 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
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:77
framerate_type.h
Types for recording game performance data.
PFE_DRAWWORLD
@ PFE_DRAWWORLD
Time spent drawing world viewports in GUI.
Definition framerate_type.h:58
SetMouseCursor
void SetMouseCursor(CursorID sprite, PaletteID pal)
Assign a single non-animated sprite to the cursor.
Definition gfx.cpp:1686
_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:851
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:657
_ctrl_pressed
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
DrawSpriteViewport
void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
Draw a sprite in a viewport.
Definition gfx.cpp:960
SetAnimatedMouseCursor
void SetAnimatedMouseCursor(const AnimCursor *table)
Assign an animation to the cursor.
Definition gfx.cpp:1699
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:418
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
SpriteType::Normal
@ Normal
The most basic (normal) sprite.
SA_HOR_CENTER
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:344
CursorID
uint32_t CursorID
The number of the cursor (sprite)
Definition gfx_type.h:20
FS_SMALL
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:210
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:209
PaletteID
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:19
TextColour
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:260
TC_IS_PALETTE_COLOUR
@ TC_IS_PALETTE_COLOUR
Colour value is already a real palette colour index, not an index of a StringColour.
Definition gfx_type.h:283
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:2022
Window::SetDirty
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:940
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:1486
MarkWholeScreenDirty
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1529
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:1983
RedrawScreenRect
void RedrawScreenRect(int left, int top, int right, int bottom)
Repaints a specific rectangle of the screen.
Definition gfx.cpp:1371
ViewportSign::MarkDirty
void MarkDirty(ZoomLevel maxzoom=ZOOM_LVL_MAX) const
Mark the sign dirty in all viewports.
Definition viewport.cpp:1491
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:2057
SetSelectionTilesDirty
static void SetSelectionTilesDirty()
Marks the selected tiles as dirty.
Definition viewport.cpp:2074
_tile_type_procs
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition landscape.cpp:65
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:111
GetSlopePixelZ
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition landscape.cpp:303
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:79
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:95
InverseRemapCoords
Point InverseRemapCoords(int x, int y)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition landscape.h:109
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:146
TileAddByDir
TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition map_func.h:596
TileXY
static debug_inline TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:373
ToTileIndexDiff
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:440
TileAdd
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:454
TileY
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:425
TileX
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:415
TileVirtXY
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:404
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
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:320
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
IsInsideMM
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition math_func.hpp:268
Swap
constexpr void Swap(T &a, T &b)
Type safe swap operation.
Definition math_func.hpp:283
GuiShowTooltips
void GuiShowTooltips(Window *parent, StringID str, TooltipCloseCondition close_tooltip, uint paramcount)
Shows a tooltip.
Definition misc_gui.cpp:740
_network_own_client_id
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:70
network_func.h
Network functions used by other parts of OpenTTD.
ClientID
ClientID
'Unique' identifier to be given to clients
Definition network_type.h:49
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
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:314
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:57
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
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:556
SignID
uint16_t SignID
The type of the IDs of signs.
Definition signs_type.h:14
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
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
Corner
Corner
Enumeration of tile corners.
Definition slope_type.h:22
ScrollMainWindowTo
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
Definition smallmap_gui.cpp:2077
MAX_SPRITES
static constexpr uint32_t MAX_SPRITES
Masks needed for sprite operations.
Definition sprites.h:1555
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:1569
ANIMCURSOR_FLAG
static const CursorID ANIMCURSOR_FLAG
Flag for saying a cursor sprite is an animated cursor.
Definition sprites.h:1507
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:1570
SPRITE_MASK
static constexpr uint32_t SPRITE_MASK
The mask to for the main sprite.
Definition sprites.h:1556
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:1547
PALETTE_CRASH
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1605
SPR_CURSOR_MOUSE
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition sprites.h:1390
PALETTE_SEL_TILE_BLUE
static const PaletteID PALETTE_SEL_TILE_BLUE
This draws a blueish square (catchment areas for example)
Definition sprites.h:1571
PALETTE_TO_TRANSPARENT
static const PaletteID PALETTE_TO_TRANSPARENT
This sets the sprite to transparent.
Definition sprites.h:1602
station_base.h
Base classes/functions for stations.
ShowStationViewWindow
void ShowStationViewWindow(StationID station)
Opens StationViewWindow for given station.
Definition station_gui.cpp:2176
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 const uint8_t _string_colourmap[17]
Colour mapping for TextColour.
Definition string_colours.h:11
SetDParam
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:333
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:16
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:59
BaseStation::xy
TileIndex xy
Base tile of the station.
Definition base_station_base.h:60
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:177
BaseStation::sign
TrackedViewportSign sign
NOSAVE: Dimensions of sign.
Definition base_station_base.h:61
ChildScreenSpriteToDraw
Definition viewport.cpp:131
ChildScreenSpriteToDraw::next
int next
next child to draw (-1 at the end)
Definition viewport.cpp:138
ChildScreenSpriteToDraw::sub
const SubSprite * sub
only draw a rectangular part of the sprite
Definition viewport.cpp:134
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition settings_type.h:610
ConstructionSettings::max_bridge_height
uint8_t max_bridge_height
maximum height of bridges
Definition settings_type.h:386
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:518
GUISettings::population_in_label
bool population_in_label
show the population of a town in its label?
Definition settings_type.h:175
GUISettings::measure_tooltip
bool measure_tooltip
show a permanent tooltip when dragging tools
Definition settings_type.h:155
GUISettings::zoom_min
ZoomLevel zoom_min
minimum zoom out level
Definition settings_type.h:165
GUISettings::smooth_scroll
bool smooth_scroll
smooth scroll viewports
Definition settings_type.h:154
GUISettings::zoom_max
ZoomLevel zoom_max
maximum zoom out level
Definition settings_type.h:166
GameSettings::economy
EconomySettings economy
settings to change the economy
Definition settings_type.h:602
GameSettings::construction
ConstructionSettings construction
construction of things in-game
Definition settings_type.h:594
Map::SizeY
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:279
Map::SizeX
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition map_func.h:270
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:341
Map::MaxY
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:306
Map::MaxX
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:297
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:17
ParentSpriteToDraw::sub
const SubSprite * sub
only draw a rectangular part of the sprite
Definition viewport_sprite_sorter.h:32
ParentSpriteToDraw::zmin
int32_t zmin
minimal world Z coordinate of bounding box
Definition viewport_sprite_sorter.h:21
ParentSpriteToDraw::image
SpriteID image
sprite to draw
Definition viewport_sprite_sorter.h:30
ParentSpriteToDraw::xmax
int32_t xmax
maximal world X coordinate of bounding box
Definition viewport_sprite_sorter.h:25
ParentSpriteToDraw::ymax
int32_t ymax
maximal world Y coordinate of bounding box
Definition viewport_sprite_sorter.h:26
ParentSpriteToDraw::x
int32_t x
screen X coordinate of sprite
Definition viewport_sprite_sorter.h:22
ParentSpriteToDraw::y
int32_t y
screen Y coordinate of sprite
Definition viewport_sprite_sorter.h:28
ParentSpriteToDraw::first_child
int32_t first_child
the first child to draw.
Definition viewport_sprite_sorter.h:37
ParentSpriteToDraw::zmax
int32_t zmax
maximal world Z coordinate of bounding box
Definition viewport_sprite_sorter.h:27
ParentSpriteToDraw::xmin
int32_t xmin
minimal world X coordinate of bounding box
Definition viewport_sprite_sorter.h:19
ParentSpriteToDraw::ymin
int32_t ymin
minimal world Y coordinate of bounding box
Definition viewport_sprite_sorter.h:20
ParentSpriteToDraw::pal
PaletteID pal
palette to use
Definition viewport_sprite_sorter.h:31
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:34
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:35
Point
Coordinates of a point in 2D.
Definition geometry_type.hpp:21
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:238
Pool::PoolItem<&_station_pool >::GetNumItems
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition pool_type.hpp:369
Pool::PoolItem<&_vehicle_pool >::Get
static Titem * Get(size_t index)
Returns Titem with given index.
Definition pool_type.hpp:339
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition geometry_type.hpp:75
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:235
SpecializedStation< Station, false >::Get
static Station * Get(size_t index)
Gets station with given index.
Definition base_station_base.h:254
SpecializedStation< Waypoint, true >::From
static Waypoint * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
Definition base_station_base.h:283
Sprite
Data structure describing a sprite.
Definition spritecache.h:17
Sprite::width
uint16_t width
Width of the sprite.
Definition spritecache.h:19
Sprite::height
uint16_t height
Height of the sprite.
Definition spritecache.h:18
Sprite::y_offs
int16_t y_offs
Number of pixels to shift the sprite downwards.
Definition spritecache.h:21
Sprite::x_offs
int16_t x_offs
Number of pixels to shift the sprite to the right.
Definition spritecache.h:20
Station
Station data structure.
Definition station_base.h:439
Station::catchment_tiles
BitmapTileArea catchment_tiles
NOSAVE: Set of individual tiles covered by catchment area.
Definition station_base.h:459
StringSpriteToDraw
Definition viewport.cpp:114
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:231
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:2588
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:2579
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:2567
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:43
TileInfo::z
int z
Height.
Definition tile_cmd.h:48
TileInfo::x
int x
X position of the tile in unit coordinates.
Definition tile_cmd.h:44
TileInfo::tileh
Slope tileh
Slope of the tile.
Definition tile_cmd.h:46
TileInfo::tile
TileIndex tile
Tile index.
Definition tile_cmd.h:47
TileInfo::y
int y
Y position of the tile in unit coordinates.
Definition tile_cmd.h:45
TileSpriteToDraw
Definition viewport.cpp:123
TileSpriteToDraw::y
int32_t y
screen Y coordinate of sprite
Definition viewport.cpp:128
TileSpriteToDraw::x
int32_t x
screen X coordinate of sprite
Definition viewport.cpp:127
TileSpriteToDraw::sub
const SubSprite * sub
only draw a rectangular part of the sprite
Definition viewport.cpp:126
TileTypeProcs::draw_tile_proc
DrawTileProc * draw_tile_proc
Called to render the tile and its contents to the screen.
Definition tile_cmd.h:159
TownCache::sign
TrackedViewportSign sign
Location of name sign, UpdateVirtCoord updates this.
Definition town.h:45
Town
Town data structure.
Definition town.h:54
Town::xy
TileIndex xy
town center tile
Definition town.h:55
Town::cache
TownCache cache
Container for all cacheable data.
Definition town.h:57
Town::show_zone
bool show_zone
NOSAVE: mark town to show the local authority zone in the viewports.
Definition town.h:104
Town::stations_near
StationList stations_near
NOSAVE: List of nearby stations.
Definition town.h:91
TrackedViewportSign::kdtree_valid
bool kdtree_valid
Are the sign data valid for use with the _viewport_sign_kdtree?
Definition viewport_type.h:52
Vehicle
Vehicle data structure.
Definition vehicle_base.h:244
Vehicle::z_pos
int32_t z_pos
z coordinate.
Definition vehicle_base.h:306
Vehicle::First
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Definition vehicle_base.h:645
Vehicle::y_pos
int32_t y_pos
y coordinate.
Definition vehicle_base.h:305
Vehicle::x_pos
int32_t x_pos
x coordinate.
Definition vehicle_base.h:304
Vehicle::owner
Owner owner
Which company owns the vehicle?
Definition vehicle_base.h:309
Vehicle::unitnumber
UnitID unitnumber
unit number, for display purposes only
Definition vehicle_base.h:326
ViewportData
Data structure for a window viewport.
Definition window_gui.h:252
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:257
ViewportData::scrollpos_y
int32_t scrollpos_y
Currently shown y coordinate (virtual screen coordinate of topleft corner of the viewport).
Definition window_gui.h:255
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:256
ViewportData::follow_vehicle
VehicleID follow_vehicle
VehicleID to follow if following a vehicle, INVALID_VEHICLE otherwise.
Definition window_gui.h:253
ViewportData::scrollpos_x
int32_t scrollpos_x
Currently shown x coordinate (virtual screen coordinate of topleft corner of the viewport).
Definition window_gui.h:254
ViewportDrawer
Data structure storing rendering information.
Definition viewport.cpp:168
ViewportDrawer::foundation
int foundation[FOUNDATION_PART_END]
Foundation sprites (index into parent_sprites_to_draw).
Definition viewport.cpp:181
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:183
ViewportDrawer::parent_sprites_to_sort
ParentSpriteToSortVector parent_sprites_to_sort
Parent sprite pointer array used for sorting.
Definition viewport.cpp:174
ViewportDrawer::foundation_offset
Point foundation_offset[FOUNDATION_PART_END]
Pixel offset for ground sprites on the foundations.
Definition viewport.cpp:184
ViewportDrawer::combine_sprites
SpriteCombineMode combine_sprites
Current mode of "sprite combining".
Definition viewport.cpp:179
ViewportDrawer::foundation_part
FoundationPart foundation_part
Currently active foundation for ground sprite drawing.
Definition viewport.cpp:182
ViewportSSCSS
Helper class for getting the best sprite sorter.
Definition viewport.cpp:3516
ViewportSSCSS::fct_checker
VpSorterChecker fct_checker
The check function.
Definition viewport.cpp:3517
ViewportSSCSS::fct_sorter
VpSpriteSorter fct_sorter
The sorting function.
Definition viewport.cpp:3518
ViewportSignKdtreeItem
Definition viewport_kdtree.h:19
ViewportSign
Location information about a sign as seen on the viewport.
Definition viewport_type.h:38
ViewportSign::center
int32_t center
The center position of the sign.
Definition viewport_type.h:39
ViewportSign::width_small
uint16_t width_small
The width when zoomed out (small font)
Definition viewport_type.h:42
ViewportSign::width_normal
uint16_t width_normal
The width when not zoomed out (normal font)
Definition viewport_type.h:41
ViewportSign::UpdatePosition
void UpdatePosition(int center, int top, StringID str, StringID str_small=STR_NULL)
Update the position of the viewport sign.
Definition viewport.cpp:1466
ViewportSign::top
int32_t top
The top of the sign.
Definition viewport_type.h:40
Viewport
Data structure for viewport, display of a part of the world.
Definition viewport_type.h:22
Viewport::top
int top
Screen coordinate top edge of the viewport.
Definition viewport_type.h:24
Viewport::width
int width
Screen width of the viewport.
Definition viewport_type.h:25
Viewport::zoom
ZoomLevel zoom
The zoom level of the viewport.
Definition viewport_type.h:33
Viewport::virtual_top
int virtual_top
Virtual top coordinate.
Definition viewport_type.h:29
Viewport::virtual_left
int virtual_left
Virtual left coordinate.
Definition viewport_type.h:28
Viewport::virtual_width
int virtual_width
width << zoom
Definition viewport_type.h:30
Viewport::left
int left
Screen coordinate left edge of the viewport.
Definition viewport_type.h:23
Viewport::height
int height
Screen height of the viewport.
Definition viewport_type.h:26
Viewport::virtual_height
int virtual_height
height << zoom
Definition viewport_type.h:31
Waypoint
Representation of a waypoint.
Definition waypoint_base.h:23
Window::WindowIterator
Iterator to iterate all valid Windows.
Definition window_gui.h:868
Window
Data structure for an opened window.
Definition window_gui.h:273
Window::SetWidgetDirty
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:551
Window::OnPlaceObjectAbort
virtual void OnPlaceObjectAbort()
The user cancelled a tile highlight mode that has been set.
Definition window_gui.h:815
Window::window_class
WindowClass window_class
Window class.
Definition window_gui.h:301
Window::viewport
ViewportData * viewport
Pointer to viewport data, if present.
Definition window_gui.h:318
Window::DrawViewport
void DrawViewport() const
Draw the viewport of this window.
Definition viewport.cpp:1832
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:794
Window::left
int left
x position of left edge of the window
Definition window_gui.h:309
Window::top
int top
y position of top edge of the window
Definition window_gui.h:310
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:836
Window::GetWidget
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:977
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:825
Window::SetWidgetDisabledState
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:387
Window::Iterate
AllWindows< false > Iterate
Iterate all windows in whatever order is easiest.
Definition window_gui.h:927
Window::height
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
Window::width
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
Window::window_number
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
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
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
GetTileType
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
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
IsTileType
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
TileHeight
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
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_PIXELS
static const uint TILE_PIXELS
Pixel distance between tile columns/rows in ZOOM_BASE.
Definition tile_type.h:17
MAX_BUILDING_PIXELS
static const 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
TILE_HEIGHT
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
TILE_SIZE
static const uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
TILE_UNIT_MASK
static const uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
INVALID_TILE
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
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:3896
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
TO_SIGNS
@ TO_SIGNS
signs
Definition transparency.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:48
_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:59
ViewportAddVehicles
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition vehicle.cpp:1154
CheckClickOnVehicle
Vehicle * CheckClickOnVehicle(const Viewport *vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition vehicle.cpp:1248
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:91
ShowVehicleViewWindow
void ShowVehicleViewWindow(const Vehicle *v)
Shows the vehicle view window of the given vehicle.
Definition vehicle_gui.cpp:3504
VehicleClicked
bool VehicleClicked(const Vehicle *v)
Dispatch a "vehicle selected" event if any window waits for it.
Definition vehicle_gui.cpp:3514
StartStopVehicle
void StartStopVehicle(const Vehicle *v, bool texteffect)
Executes CMD_START_STOP_VEHICLE for given vehicle.
Definition vehicle_gui.cpp:3003
vehicle_gui.h
Functions related to the vehicle's GUIs.
INVALID_VEHICLE
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition vehicle_type.h:54
HighlightTownLocalAuthorityTiles
static void HighlightTownLocalAuthorityTiles(const TileInfo *ti)
Highlights tiles insede local authority of selected towns.
Definition viewport.cpp:1065
CheckOverflow
static void CheckOverflow(int &test, int &other, int max, int mult)
Check for overflowing the map.
Definition viewport.cpp:2988
ScrollWindowToTile
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
Definition viewport.cpp:2504
CmdScrollViewport
CommandCost CmdScrollViewport(DoCommandFlag flags, TileIndex tile, ViewportScrollTarget target, uint32_t ref)
Scroll players main viewport.
Definition viewport.cpp:3549
SetTileSelectSize
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
Definition viewport.cpp:2542
OffsetGroundSprite
void OffsetGroundSprite(int x, int y)
Called when a foundation has been drawn for the current tile.
Definition viewport.cpp:599
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:494
LAST_CHILD_NONE
constexpr int LAST_CHILD_NONE
There is no last_child to fill.
Definition viewport.cpp:164
ResetObjectToPlace
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition viewport.cpp:3498
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition viewport.cpp:2515
SpriteCombineMode
SpriteCombineMode
Mode of "sprite combining".
Definition viewport.cpp:153
SPRITE_COMBINE_PENDING
@ SPRITE_COMBINE_PENDING
Sprite combining will start with the next unclipped sprite.
Definition viewport.cpp:155
SPRITE_COMBINE_ACTIVE
@ SPRITE_COMBINE_ACTIVE
Sprite combining is active. AddSortableSpriteToDraw outputs child sprites.
Definition viewport.cpp:156
SPRITE_COMBINE_NONE
@ SPRITE_COMBINE_NONE
Every AddSortableSpriteToDraw start its own bounding box.
Definition viewport.cpp:154
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:3435
LAST_CHILD_PARENT
constexpr int LAST_CHILD_PARENT
Fill last_child of the most recent parent sprite.
Definition viewport.cpp:165
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:111
MAX_TILE_EXTENT_LEFT
static const int MAX_TILE_EXTENT_LEFT
Maximum left extent of tile relative to north corner.
Definition viewport.cpp:109
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:804
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:2884
DrawTileSelectionRect
static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal)
Draws a selection rectangle on a tile.
Definition viewport.cpp:908
StartSpriteCombine
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:767
InitializeSpriteSorter
void InitializeSpriteSorter()
Choose the "best" sprite sorter and set _vp_sprite_sorter.
Definition viewport.cpp:3530
FoundationPart
FoundationPart
Enumeration of multi-part foundations.
Definition viewport.cpp:142
FOUNDATION_PART_NONE
@ FOUNDATION_PART_NONE
Neither foundation nor groundsprite drawn yet.
Definition viewport.cpp:143
FOUNDATION_PART_HALFTILE
@ FOUNDATION_PART_HALFTILE
Second part (halftile foundation)
Definition viewport.cpp:145
FOUNDATION_PART_NORMAL
@ FOUNDATION_PART_NORMAL
First part (normal foundation or no foundation)
Definition viewport.cpp:144
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:631
ShowMeasurementTooltips
static void ShowMeasurementTooltips(StringID str, uint paramcount)
Displays the measurement tooltips when selecting multiple tiles.
Definition viewport.cpp:2710
GetViewportY
static int GetViewportY(Point tile)
Returns the y coordinate in the viewport coordinate system where the given tile is painted.
Definition viewport.cpp:1180
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:1857
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:540
GetAutorailHT
static HighLightStyle GetAutorailHT(int x, int y)
returns the best autorail highlight type from map coordinates
Definition viewport.cpp:2559
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:1889
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:1099
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:435
GetTileHighlightType
static TileHighlightType GetTileHighlightType(TileIndex t)
Get tile highlight type of coverage area for a given tile.
Definition viewport.cpp:1014
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:792
DrawAutorailSelection
static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
Draws autorail highlights.
Definition viewport.cpp:968
DrawTileHighlightType
static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht)
Draw tile highlight for coverage area highlight.
Definition viewport.cpp:1050
ViewportDrawBoundingBoxes
static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
Draws the bounding boxes of all ParentSprites.
Definition viewport.cpp:1673
AddSortableSpriteToDraw
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:671
SetViewportCatchmentWaypoint
void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel)
Select or deselect waypoint for coverage area highlight.
Definition viewport.cpp:3638
SetRedErrorSquare
void SetRedErrorSquare(TileIndex tile)
Set a tile to display a red error square.
Definition viewport.cpp:2524
ViewportSortParentSprites
static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
Sort parent sprites pointer array replicating the way original sorter did it.
Definition viewport.cpp:1531
VpSetPresizeRange
void VpSetPresizeRange(TileIndex from, TileIndex to)
Highlights all tiles between a set of two tiles.
Definition viewport.cpp:2777
VpSelectTilesWithMethod
void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method)
Selects tiles while dragging.
Definition viewport.cpp:3216
VpHandlePlaceSizingDrag
EventState VpHandlePlaceSizingDrag()
Handle the mouse while dragging for placement/resizing.
Definition viewport.cpp:3381
ViewportAddString
void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, Colours colour)
Add a string to draw in the viewport.
Definition viewport.cpp:1311
IsPtInWindowViewport
Viewport * IsPtInWindowViewport(const Window *w, int x, int y)
Is a xy position inside the viewport of the window?
Definition viewport.cpp:411
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:3450
EndSpriteCombine
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:777
MAX_TILE_EXTENT_RIGHT
static const int MAX_TILE_EXTENT_RIGHT
Maximum right extent of tile relative to north corner.
Definition viewport.cpp:110
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:827
CheckUnderflow
static void CheckUnderflow(int &test, int &other, int mult)
Check for underflowing the map.
Definition viewport.cpp:2973
ViewportSortParentSpritesChecker
static bool ViewportSortParentSpritesChecker()
This fallback sprite checker always exists.
Definition viewport.cpp:1525
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:564
VpStartDragging
void VpStartDragging(ViewportDragDropSelectionProcess process)
Drag over the map while holding the left mouse down.
Definition viewport.cpp:2756
_vp_sprite_sorters
static ViewportSSCSS _vp_sprite_sorters[]
List of sorters ordered from best to worst.
Definition viewport.cpp:3522
UpdateTileSelection
void UpdateTileSelection()
Updates tile highlighting for all cases.
Definition viewport.cpp:2602
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:890
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:112
SetViewportCatchmentStation
void SetViewportCatchmentStation(const Station *st, bool sel)
Select or deselect station for coverage area highlight.
Definition viewport.cpp:3618
SetViewportCatchmentTown
void SetViewportCatchmentTown(const Town *t, bool sel)
Select or deselect town for coverage area highlight.
Definition viewport.cpp:3658
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:2850
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:222
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:587
CalcRaildirsDrawstyle
static void CalcRaildirsDrawstyle(int x, int y, int method)
while dragging
Definition viewport.cpp:2997
Check2x1AutoRail
static HighLightStyle Check2x1AutoRail(int mode)
returns information about the 2x1 piece to be build.
Definition viewport.cpp:2806
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:2199
ViewportDrawDirtyBlocks
static void ViewportDrawDirtyBlocks()
Draw/colour the blocks that have been redrawn.
Definition viewport.cpp:1691
VpStartPlaceSizing
void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process)
highlighting tiles while only going over them with the mouse
Definition viewport.cpp:2722
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:515
ViewportAddLandscape
static void ViewportAddLandscape()
Add the landscape to the viewport, i.e.
Definition viewport.cpp:1189
_viewport_highlight_station
const Station * _viewport_highlight_station
Currently selected station for coverage area highlight.
Definition viewport.cpp:1005
_viewport_highlight_town
const Town * _viewport_highlight_town
Currently selected town for coverage area highlight.
Definition viewport.cpp:1007
UpdateViewportPosition
void UpdateViewportPosition(Window *w, uint32_t delta_ms)
Update the viewport position being displayed.
Definition viewport.cpp:1916
_viewport_highlight_waypoint
const Waypoint * _viewport_highlight_waypoint
Currently selected waypoint for coverage area highlight.
Definition viewport.cpp:1006
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:2469
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:20
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:44
VpSpriteSorter
void(* VpSpriteSorter)(ParentSpriteToSortVector *psd)
Type for the actual viewport sprite sorter.
Definition viewport_sprite_sorter.h:46
ViewportScrollTarget
ViewportScrollTarget
Target of the viewport scrolling GS method.
Definition viewport_type.h:148
VST_EVERYONE
@ VST_EVERYONE
All players.
Definition viewport_type.h:149
VST_COMPANY
@ VST_COMPANY
All players in specific company.
Definition viewport_type.h:150
VST_CLIENT
@ VST_CLIENT
Single player.
Definition viewport_type.h:151
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:111
ZOOM_IN
@ ZOOM_IN
Zoom in (get more detailed view).
Definition viewport_type.h:77
ZOOM_OUT
@ ZOOM_OUT
Zoom out (get helicopter view).
Definition viewport_type.h:78
ViewportPlaceMethod
ViewportPlaceMethod
Viewport place method (type of highlighted area and placed objects)
Definition viewport_type.h:92
VPM_FIX_Y
@ VPM_FIX_Y
drag only in Y axis
Definition viewport_type.h:95
VPM_Y_LIMITED
@ VPM_Y_LIMITED
Drag only in Y axis with limited size.
Definition viewport_type.h:101
VPM_X_AND_Y_LIMITED
@ VPM_X_AND_Y_LIMITED
area of land of limited size
Definition viewport_type.h:97
VPM_FIX_VERTICAL
@ VPM_FIX_VERTICAL
drag only in vertical direction
Definition viewport_type.h:99
VPM_X_LIMITED
@ VPM_X_LIMITED
Drag only in X axis with limited size.
Definition viewport_type.h:100
VPM_X_AND_Y
@ VPM_X_AND_Y
area of land in X and Y directions
Definition viewport_type.h:96
VPM_FIX_HORIZONTAL
@ VPM_FIX_HORIZONTAL
drag only in horizontal direction
Definition viewport_type.h:98
VPM_FIX_X
@ VPM_FIX_X
drag only in X axis
Definition viewport_type.h:94
VPM_SIGNALDIRS
@ VPM_SIGNALDIRS
similar to VMP_RAILDIRS, but with different cursor
Definition viewport_type.h:103
VPM_X_OR_Y
@ VPM_X_OR_Y
drag in X or Y direction
Definition viewport_type.h:93
VPM_RAILDIRS
@ VPM_RAILDIRS
all rail directions
Definition viewport_type.h:102
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:223
DrawFrameRect
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:283
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:1140
GetMainWindow
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1127
FindWindowFromPt
Window * FindWindowFromPt(int x, int y)
Do a search for a window at specific coordinates.
Definition window.cpp:1768
_special_mouse_mode
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition window.cpp:93
FindWindowById
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1098
SetWindowDirty
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3101
window_func.h
Window functions not directly related to making/drawing windows.
window_gui.h
Functions, definitions and such used only by the GUI.
WSM_DRAGDROP
@ WSM_DRAGDROP
Drag&drop an object.
Definition window_gui.h:1041
WSM_DRAGGING
@ WSM_DRAGGING
Dragging mode (trees).
Definition window_gui.h:1044
WSM_PRESIZE
@ WSM_PRESIZE
Presizing mode (docks, tunnels).
Definition window_gui.h:1043
WSM_NONE
@ WSM_NONE
No special mouse mode.
Definition window_gui.h:1040
WSM_SIZING
@ WSM_SIZING
Sizing mode.
Definition window_gui.h:1042
FR_TRANSPARENT
@ FR_TRANSPARENT
Makes the background transparent if set.
Definition window_gui.h:26
WidgetID
int WidgetID
Widget ID.
Definition window_type.h:18
WindowNumber
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition window_type.h:740
EventState
EventState
State of handling an event.
Definition window_type.h:743
ES_HANDLED
@ ES_HANDLED
The passed event is handled.
Definition window_type.h:744
ES_NOT_HANDLED
@ ES_NOT_HANDLED
The passed event is not handled.
Definition window_type.h:745
WindowClass
WindowClass
Window classes.
Definition window_type.h:44
WC_INVALID
@ WC_INVALID
Invalid window.
Definition window_type.h:724
WC_WAYPOINT_VIEW
@ WC_WAYPOINT_VIEW
Waypoint view; Window numbers:
Definition window_type.h:357
WC_STATION_VIEW
@ WC_STATION_VIEW
Station view; Window numbers:
Definition window_type.h:345
WC_MAIN_WINDOW
@ WC_MAIN_WINDOW
Main window; Window numbers:
Definition window_type.h:51
WC_TOWN_VIEW
@ WC_TOWN_VIEW
Town view; Window numbers:
Definition window_type.h:333
WC_TOOLTIPS
@ WC_TOOLTIPS
Tooltip window; Window numbers:
Definition window_type.h:116
zoom_func.h
Functions related to zooming.
ScaleByZoom
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_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 > ZOOM_LVL_MIN)
Definition zoom_func.h:67
UnScaleByZoom
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_MIN) When shifting right,...
Definition zoom_func.h:34
ZoomLevel
ZoomLevel
All zoom levels we know.
Definition zoom_type.h:16
ZOOM_LVL_BEGIN
@ ZOOM_LVL_BEGIN
Begin for iteration.
Definition zoom_type.h:18
ZOOM_LVL_OUT_4X
@ ZOOM_LVL_OUT_4X
Zoomed 4 times out.
Definition zoom_type.h:23
ZOOM_LVL_END
@ ZOOM_LVL_END
End for iteration.
Definition zoom_type.h:25
ZOOM_LVL_MIN
@ ZOOM_LVL_MIN
Minimum zoom level.
Definition zoom_type.h:41