96 #include "table/strings.h"
101 Point _tile_fract_coords;
178 bool _draw_bounding_boxes =
false;
179 bool _draw_dirty_blocks =
false;
180 uint _dirty_block_colour = 0;
183 static Point MapXYZToViewport(
const ViewPort *vp,
int x,
int y,
int z)
191 void DeleteWindowViewport(
Window *w)
213 int width,
int height, uint32 follow_flags,
ZoomLevel zoom)
231 if (follow_flags & 0x80000000) {
242 pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y));
257 static Point _vp_move_offs;
259 static void DoSetViewportPosition(
const Window *w,
int left,
int top,
int width,
int height)
262 if (left + width > w->
left &&
264 top + height > w->
top &&
267 if (left < w->left) {
268 DoSetViewportPosition(w, left, top, w->
left - left, height);
269 DoSetViewportPosition(w, left + (w->
left - left), top, width - (w->
left - left), height);
274 DoSetViewportPosition(w, left, top, (w->
left + w->
width - left), height);
275 DoSetViewportPosition(w, left + (w->
left + w->
width - left), top, width - (w->
left + w->
width - left), height);
280 DoSetViewportPosition(w, left, top, width, (w->
top - top));
281 DoSetViewportPosition(w, left, top + (w->
top - top), width, height - (w->
top - top));
286 DoSetViewportPosition(w, left, top, width, (w->
top + w->
height - top));
287 DoSetViewportPosition(w, left, top + (w->
top + w->
height - top), width, height - (w->
top + w->
height - top));
296 int xo = _vp_move_offs.x;
297 int yo = _vp_move_offs.y;
299 if (
abs(xo) >= width ||
abs(yo) >= height) {
301 RedrawScreenRect(left, top, left + width, top + height);
305 GfxScroll(left, top, width, height, xo, yo);
308 RedrawScreenRect(left, top, xo + left, top + height);
312 RedrawScreenRect(left + width + xo, top, left + width, top + height);
317 RedrawScreenRect(left, top, width + left, top + yo);
319 RedrawScreenRect(left, top + height + yo, width + left, top + height);
324 static void SetViewportPosition(
Window *w,
int x,
int y)
330 int left, top, width, height;
346 if (old_top == 0 && old_left == 0)
return;
348 _vp_move_offs.x = old_left;
349 _vp_move_offs.y = old_top;
361 i = left + width - _screen.width;
362 if (i >= 0) width -= i;
370 i = top + height - _screen.height;
371 if (i >= 0) height -= i;
373 if (height > 0) DoSetViewportPosition(w->
z_front, left, top, width, height);
410 if ( (uint)(x -= vp->
left) >= (uint)vp->
width ||
411 (uint)(y -= vp->
top) >= (uint)vp->
height) {
428 b =
Clamp(b, -extra_tiles * TILE_SIZE,
MapMaxY() * TILE_SIZE - 1);
441 for (
int i = 0; i < 5; i++) z = GetSlopePixelZ(
Clamp(a +
max(z, 4) - 4, min_coord,
MapMaxX() * TILE_SIZE - 1),
Clamp(b +
max(z, 4) - 4, min_coord,
MapMaxY() * TILE_SIZE - 1)) / 2;
442 for (
int malus = 3; malus > 0; malus--) z = GetSlopePixelZ(
Clamp(a +
max(z, malus) - malus, min_coord,
MapMaxX() * TILE_SIZE - 1),
Clamp(b +
max(z, malus) - malus, min_coord,
MapMaxY() * TILE_SIZE - 1)) / 2;
443 for (
int i = 0; i < 5; i++) z = GetSlopePixelZ(
Clamp(a + z, min_coord,
MapMaxX() * TILE_SIZE - 1),
Clamp(b + z, min_coord,
MapMaxY() * TILE_SIZE - 1)) / 2;
445 pt.x =
Clamp(a + z, min_coord,
MapMaxX() * TILE_SIZE - 1);
446 pt.y =
Clamp(b + z, min_coord,
MapMaxY() * TILE_SIZE - 1);
454 static Point GetTileFromScreenXY(
int x,
int y,
int zoom_x,
int zoom_y)
468 Point GetTileBelowCursor()
470 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
480 x = ((_cursor.pos.x - vp->
left) >> 1) + (vp->
width >> 2);
481 y = ((_cursor.pos.y - vp->
top) >> 1) + (vp->
height >> 2);
483 x = vp->
width - (_cursor.pos.x - vp->
left);
484 y = vp->
height - (_cursor.pos.y - vp->
top);
487 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->
left, y + vp->
top);
528 ts->
x = pt.x + extra_offs_x;
529 ts->
y = pt.y + extra_offs_y;
546 assert(
IsInsideMM(foundation_part, 0, FOUNDATION_PART_END));
547 assert(_vd.
foundation[foundation_part] != -1);
551 int *old_child = _vd.last_child;
554 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y,
false, sub,
false);
557 _vd.last_child = old_child;
582 AddTileSpriteToDraw(image, pal, _cur_ti->
x + x, _cur_ti->
y + y, _cur_ti->
z + z, sub, extra_offs_x * ZOOM_LVL_BASE, extra_offs_y * ZOOM_LVL_BASE);
618 default: NOT_REACHED();
645 if (pt.x + spr->
x_offs >= _vd.dpi.left + _vd.dpi.width ||
647 pt.y + spr->
y_offs >= _vd.dpi.top + _vd.dpi.height ||
680 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)
682 int32 left, right, top, bottom;
697 _vd.last_child = NULL;
700 int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
703 if (image == SPR_EMPTY_BOUNDING_BOX) {
704 left = tmp_left =
RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
705 right =
RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1;
706 top = tmp_top =
RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
707 bottom =
RemapCoords(x + w , y + h , z + bb_offset_z).y + 1;
710 left = tmp_left = (pt.x += spr->
x_offs);
711 right = (pt.x + spr->
width );
712 top = tmp_top = (pt.y += spr->
y_offs);
713 bottom = (pt.y + spr->
height);
716 if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
718 left =
min(left ,
RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
719 right =
max(right ,
RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
720 top =
min(top ,
RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
721 bottom =
max(bottom,
RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
725 if (left >= _vd.dpi.left + _vd.dpi.width ||
726 right <= _vd.dpi.left ||
727 top >= _vd.dpi.top + _vd.dpi.height ||
728 bottom <= _vd.dpi.top) {
742 ps->
xmin = x + bb_offset_x;
743 ps->
xmax = x +
max(bb_offset_x, w) - 1;
745 ps->
ymin = y + bb_offset_y;
746 ps->
ymax = y +
max(bb_offset_y, h) - 1;
748 ps->
zmin = z + bb_offset_z;
749 ps->
zmax = z +
max(bb_offset_z, dz) - 1;
804 if (begin > end)
Swap(begin, end);
805 return begin <= check && check <= end;
816 int dist_a = (_thd.
size.x + _thd.
size.y);
817 int dist_b = (_thd.
size.x - _thd.
size.y);
818 int a = ((x - _thd.
pos.x) + (y - _thd.
pos.y));
819 int b = ((x - _thd.
pos.x) - (y - _thd.
pos.y));
840 if (_vd.last_child == NULL)
return;
848 *_vd.last_child = _vd.child_screen_sprites_to_draw.
Length();
854 cs->x = scale ? x * ZOOM_LVL_BASE : x;
855 cs->y = scale ? y * ZOOM_LVL_BASE : y;
863 _vd.last_child = &cs->
next;
866 static void AddStringToDraw(
int x,
int y,
StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width)
873 ss->params[0] = params_1;
874 ss->params[1] = params_2;
916 SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner;
921 sel = SPR_HALFTILE_SELECTION_DOWN;
925 sel += opposite_corner;
932 static bool IsPartOfAutoLine(
int px,
int py)
942 case HT_DIR_HU:
return px == -py || px == -py - 16;
943 case HT_DIR_HL:
return px == -py || px == -py + 16;
944 case HT_DIR_VL:
return px == py || px == py + 16;
945 case HT_DIR_VR:
return px == py || px == py - 16;
978 static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
980 if (autorail_type != _lower_rail[halftile_corner]) {
987 offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
989 image = SPR_AUTORAIL_BASE + offset;
992 image = SPR_AUTORAIL_BASE - offset;
1033 if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z +=
TILE_HEIGHT;
1034 if (halftile_corner != CORNER_S) {
1045 }
else if (IsPartOfAutoLine(ti->
x, ti->
y)) {
1063 if (!is_redsq && _thd.
outersize.x > 0 &&
1170 return tile_coord.y - tile_coord.x;
1184 if (tile.x < tile.y) {
1186 northern_end.y = tile.y - tile.x;
1188 northern_end.x = tile.x - tile.y;
1192 return northern_end;
1206 Point distance_to_end;
1207 distance_to_end.x = (int)
MapMaxX() - tile.x;
1208 distance_to_end.y = (int)
MapMaxY() - tile.y;
1211 if (distance_to_end.x < distance_to_end.y) {
1212 int number_of_steps =
min(limit, distance_to_end.x);
1213 southern_end.x = tile.x + number_of_steps;
1214 southern_end.y = tile.y + number_of_steps;
1216 int number_of_steps =
min(limit, distance_to_end.y);
1217 southern_end.x = tile.x + number_of_steps;
1218 southern_end.y = tile.y + number_of_steps;
1221 return southern_end;
1246 middle_tile.x = (lower_tile.x + upper_tile.x) / 2;
1247 middle_tile.y = (lower_tile.y + upper_tile.y) / 2;
1286 int northern_tile_viewport_y =
GetViewportY(northern_tile);
1287 int southern_tile_viewport_y =
GetViewportY(southern_tile);
1289 if (northern_tile_viewport_y >= viewport_y) {
1291 while (northern_tile_viewport_y >= viewport_y) {
1294 northern_tile_viewport_y =
GetViewportY(northern_tile);
1296 return northern_tile.x + northern_tile.y;
1299 if (southern_tile_viewport_y <= viewport_y) {
1301 while (southern_tile_viewport_y <= viewport_y) {
1304 southern_tile_viewport_y =
GetViewportY(southern_tile);
1306 return southern_tile.x + southern_tile.y;
1319 Point upper_tile = tile;
1327 if (middle_bound >= viewport_y) {
1330 lower_tile = middle_tile;
1334 upper_tile = middle_tile;
1337 while (lower_tile.y - upper_tile.y > 1);
1346 int correction_step = 0;
1347 if (bridge_correct) {
1356 for (
int n = 0; n < worst_case_steps_southwards; n++) {
1357 TileIndex potential_bridge_tile =
TileXY(upper_tile.x + n, upper_tile.y + n);
1362 int upper_tile_height =
GetTileZ(
TileXY(upper_tile.x, upper_tile.y));
1367 if (bridge_height - 2 * n - 1 > upper_tile_height) {
1368 correction_step = n;
1375 upper_tile.x += correction_step;
1376 upper_tile.y += correction_step;
1379 return upper_tile.x + upper_tile.y;
1399 int upper_row = upper_tile.x + upper_tile.y;
1400 int lower_row = lower_right_tile.x + lower_right_tile.y;
1402 assert(upper_row <= lower_row);
1404 int number_of_rows = lower_row - upper_row;
1406 if (number_of_rows % 2 != 0) {
1413 bottom_tile.x = upper_tile.x + number_of_rows / 2;
1414 bottom_tile.y = upper_tile.y + number_of_rows / 2;
1416 int bottom_row = bottom_tile.x + bottom_tile.y;
1418 assert(bottom_row >= lower_row);
1428 assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height);
1429 assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width);
1436 int viewport_top = _vd.dpi.top - 16;
1437 int viewport_bottom = _vd.dpi.top + _vd.dpi.height + 116;
1454 int *top_row =
AllocaM(
int, right_column - left_column + 1);
1455 int *bottom_row =
AllocaM(
int, right_column - left_column + 1);
1457 int max_bottom_row = 0;
1458 Point top_tile_of_column = upper_left_tile;
1461 bool south_east_direction =
false;
1462 for (
int x = left_column; x <= right_column; x++) {
1470 top_row[x - left_column] =
GetRowAtTile(viewport_top, top_tile_of_column,
false);
1472 top_row[x - left_column] -= 3;
1473 bottom_row[x - left_column] =
GetRowAtTile(viewport_bottom, bottom_tile_of_column,
true);
1474 bottom_row[x - left_column]++;
1477 min_top_row =
min(min_top_row, top_row[x - left_column]);
1478 max_bottom_row =
max(max_bottom_row, bottom_row[x - left_column]);
1481 if (south_east_direction) {
1482 top_tile_of_column.y++;
1484 top_tile_of_column.x--;
1488 south_east_direction = !south_east_direction;
1491 for (
int row = min_top_row; row <= max_bottom_row; row++) {
1492 for (
int column = left_column; column <= right_column; column++) {
1496 if (((row + column) % 2 == 0) &&
1497 (top_row[column - left_column] <= row) &&
1498 (row <= bottom_row[column - left_column])) {
1501 _cur_ti = &tile_info;
1505 int x = (row - column) / 2;
1506 int y = (row + column) / 2;
1512 if (0 < x && x < (
int)
MapMaxX() && 0 < y && y < (int)
MapMaxY()) {
1553 bool small = dpi->zoom >= small_from;
1555 int left = dpi->left;
1557 int right = left + dpi->width;
1558 int bottom = top + dpi->height;
1563 if (bottom < sign->top ||
1564 top > sign->
top + sign_height ||
1565 right < sign->center - sign_half_width ||
1566 left > sign->
center + sign_half_width) {
1571 AddStringToDraw(sign->
center - sign_half_width, sign->
top, string_normal, params_1, params_2, colour, sign->
width_normal);
1573 int shadow_offset = 0;
1574 if (string_small_shadow != STR_NULL) {
1576 AddStringToDraw(sign->
center - sign_half_width + shadow_offset, sign->
top, string_small_shadow, params_1, params_2, INVALID_COLOUR, sign->
width_small);
1578 AddStringToDraw(sign->
center - sign_half_width, sign->
top - shadow_offset, string_small, params_1, params_2,
1591 STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK,
1602 FOR_ALL_BASE_STATIONS(st) {
1613 is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT,
1614 (is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT) + 1, STR_NULL,
1653 GetString(buffer, str,
lastof(buffer));
1676 zoomlevels[zoom].top = this->top -
ScaleByZoom(1, zoom);
1682 FOR_ALL_WINDOWS_FROM_BACK(w) {
1684 if (vp != NULL && vp->
zoom <= maxzoom) {
1685 assert(vp->
width != 0);
1711 while (psd != psdvend) {
1757 *psd3 = *(psd3 - 1);
1772 while (child_idx >= 0) {
1774 child_idx = cs->
next;
1795 pt2.x - pt1.x, pt2.y - pt1.y,
1796 pt3.x - pt1.x, pt3.y - pt1.y,
1797 pt4.x - pt1.x, pt4.y - pt1.y);
1816 byte bo =
UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
1818 for (
int i = (bo ^= 1); i < right; i += 2) blitter->
SetPixel(dst, i, 0, (uint8)colour);
1819 dst = blitter->
MoveTo(dst, 0, 1);
1820 }
while (--bottom > 0);
1828 bool small =
HasBit(ss->width, 15);
1829 int w =
GB(ss->width, 0, 15);
1837 if (ss->colour != INVALID_COLOUR) {
1850 x, y, x + w, y + h, ss->colour,
1860 void ViewportDoDraw(
const ViewPort *vp,
int left,
int top,
int right,
int bottom)
1863 _cur_dpi = &_vd.dpi;
1865 _vd.dpi.zoom = vp->
zoom;
1870 _vd.dpi.width = (right - left) & mask;
1871 _vd.dpi.height = (bottom - top) & mask;
1872 _vd.dpi.left = left & mask;
1873 _vd.dpi.top = top & mask;
1874 _vd.dpi.pitch = old_dpi->pitch;
1875 _vd.last_child = NULL;
1885 ViewportAddTownNames(&_vd.dpi);
1886 ViewportAddStationNames(&_vd.dpi);
1887 ViewportAddSigns(&_vd.dpi);
1889 DrawTextEffects(&_vd.dpi);
1891 if (_vd.tile_sprites_to_draw.
Length() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw);
1915 vp->overlay->
Draw(&dp);
1918 if (_vd.string_sprites_to_draw.
Length() != 0) {
1922 ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw);
1927 _vd.string_sprites_to_draw.
Clear();
1928 _vd.tile_sprites_to_draw.
Clear();
1929 _vd.parent_sprites_to_draw.
Clear();
1931 _vd.child_screen_sprites_to_draw.
Clear();
1941 if ((bottom - top) > (right - left)) {
1942 int t = (top + bottom) >> 1;
1946 int t = (left + right) >> 1;
1960 static inline void ViewportDraw(
const ViewPort *vp,
int left,
int top,
int right,
int bottom)
1962 if (right <= vp->left || bottom <= vp->top)
return;
1964 if (left >= vp->
left + vp->
width)
return;
1966 if (left < vp->left) left = vp->
left;
1969 if (top >= vp->
top + vp->
height)
return;
1971 if (top < vp->top) top = vp->
top;
1984 dpi->left += this->
left;
1985 dpi->top += this->
top;
1987 ViewportDraw(this->
viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
1989 dpi->left -= this->
left;
1990 dpi->top -= this->
top;
2025 iter =
Clamp(iter + offset, 0, iter_limit);
2027 }
while (continue_criteria(iter, iter_limit, sy, sy_limit));
2046 static inline int ClampXYToMap(
Point &curr_tile,
int &iter,
int iter_limit,
int start,
int &other_ref,
int other_value,
int vp_value,
int other_limit,
int vp_top,
int vp_bottom)
2058 other_ref = upper_edge ? 0 : other_limit;
2065 min_iter =
min(min_iter, max_iter);
2068 int max_heightlevel_at_edge = 0;
2069 for (iter = min_iter; iter <= max_iter; iter += 10) {
2070 max_heightlevel_at_edge =
max(max_heightlevel_at_edge, (
int)
TileHeight(
TileXY(curr_tile.x, curr_tile.y)));
2076 max(vp_value, -max_heightlevel_at_edge * (
int)(
TILE_HEIGHT * 2 * ZOOM_LVL_BASE)) :
2080 static inline void ClampViewportToMap(
const ViewPort *vp,
int &x,
int &y)
2090 int vx = -x + y * 2;
2095 int tx = vx / (int)(
TILE_SIZE * 4 * ZOOM_LVL_BASE);
2096 int ty = vy / (int)(
TILE_SIZE * 4 * ZOOM_LVL_BASE);
2125 SetViewportPosition(w, pt.x, pt.y);
2133 bool update_overlay =
false;
2134 if (delta_x != 0 || delta_y != 0) {
2151 if (update_overlay) RebuildViewportOverlay(w);
2167 if (right <= 0)
return;
2170 if (bottom <= 0)
return;
2199 FOR_ALL_WINDOWS_FROM_BACK(w) {
2202 assert(vp->
width != 0);
2208 void ConstrainAllViewportsZoom()
2211 FOR_ALL_WINDOWS_FROM_FRONT(w) {
2231 pt.x - 31 * ZOOM_LVL_BASE,
2232 pt.y - 122 * ZOOM_LVL_BASE,
2233 pt.x - 31 * ZOOM_LVL_BASE + 67 * ZOOM_LVL_BASE,
2234 pt.y - 122 * ZOOM_LVL_BASE + 154 * ZOOM_LVL_BASE
2238 void MarkTileDirtyByTileOutsideMap(
int x,
int y)
2245 pt.x - TILE_SIZE + 1,
2247 pt.x + TILE_SIZE - 1,
2261 int x_size = _thd.
size.x;
2262 int y_size = _thd.
size.y;
2265 int x_start = _thd.
pos.x;
2266 int y_start = _thd.
pos.y;
2270 x_start += _thd.
offs.x;
2272 y_start += _thd.
offs.y;
2278 assert(x_size >= 0);
2279 assert(y_size >= 0);
2288 assert((x_end | y_end | x_start | y_start) %
TILE_SIZE == 0);
2309 int top_y = y_start;
2325 int l = top.x - (
TILE_PIXELS - 2) * ZOOM_LVL_BASE;
2327 int r = top.x + (
TILE_PIXELS - 2) * ZOOM_LVL_BASE;
2330 static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE;
2336 if (top_x != x_start) {
2343 if (bot_y != y_end) {
2348 }
while (bot_x >= top_x);
2351 int a_size = x_size + y_size, b_size = x_size - y_size;
2356 for (
int a = -interval_a; a != a_size + interval_a; a += interval_a) {
2357 for (
int b = -interval_b; b != b_size + interval_b; b += interval_b) {
2370 void SetSelectionRed(
bool b)
2393 return y >= sign->
top && y < sign->
top + sign_height &&
2394 x >= sign->
center - sign_half_width && x < sign->
center + sign_half_width;
2397 static bool CheckClickOnTown(
const ViewPort *vp,
int x,
int y)
2404 ShowTownViewWindow(t->
index);
2412 static bool CheckClickOnStation(
const ViewPort *vp,
int x,
int y)
2417 FOR_ALL_BASE_STATIONS(st) {
2441 static bool CheckClickOnSign(
const ViewPort *vp,
int x,
int y)
2450 if (si->owner ==
OWNER_DEITY && _game_mode != GM_EDITOR)
continue;
2462 static bool CheckClickOnLandscape(
const ViewPort *vp,
int x,
int y)
2466 if (pt.x != -1)
return ClickTile(
TileVirtXY(pt.x, pt.y));
2470 static void PlaceObject()
2475 pt = GetTileBelowCursor();
2476 if (pt.x == -1)
return;
2491 bool HandleViewportClicked(
const ViewPort *vp,
int x,
int y)
2505 if (CheckClickOnTown(vp, x, y))
return true;
2506 if (CheckClickOnStation(vp, x, y))
return true;
2507 if (CheckClickOnSign(vp, x, y))
return true;
2508 bool result = CheckClickOnLandscape(vp, x, y);
2525 void RebuildViewportOverlay(
Window *w)
2527 if (w->
viewport->overlay != NULL &&
2550 z = GetSlopePixelZ(x, y);
2564 RebuildViewportOverlay(w);
2625 void SetTileSelectBigSize(
int ox,
int oy,
int sx,
int sy)
2683 bool new_diagonal =
false;
2695 new_diagonal =
true;
2697 if (x1 >= x2)
Swap(x1, x2);
2698 if (y1 >= y2)
Swap(y1, y2);
2704 if (!new_diagonal) {
2711 Point pt = GetTileBelowCursor();
2743 default: NOT_REACHED();
2826 void VpSetPlaceSizingLimit(
int limit)
2850 static void VpStartPreSizing()
2862 int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
2864 int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
2868 default: NOT_REACHED();
2870 if (fxpy >= 20 && sxpy <= 12)
return HT_DIR_HL;
2871 if (fxmy < -3 && sxmy > 3)
return HT_DIR_VR;
2875 if (fxmy > 3 && sxmy < -3)
return HT_DIR_VL;
2876 if (fxpy <= 12 && sxpy >= 20)
return HT_DIR_HU;
2880 if (fxmy > 3 && sxmy < -3)
return HT_DIR_VL;
2881 if (fxpy >= 20 && sxpy <= 12)
return HT_DIR_HL;
2885 if (fxmy < -3 && sxmy > 3)
return HT_DIR_VR;
2886 if (fxpy <= 12 && sxpy >= 20)
return HT_DIR_HU;
2906 uint start_x =
TileX(start_tile);
2907 uint start_y =
TileY(start_tile);
2908 uint end_x =
TileX(end_tile);
2909 uint end_y =
TileY(end_tile);
2913 case HT_LINE:
return (end_x > start_x || (end_x == start_x && end_y > start_y));
2916 case HT_POINT:
return (end_x != start_x && end_y < start_y);
2917 default: NOT_REACHED();
2943 if (start_tile == end_tile)
return 0;
2944 if (swap)
Swap(start_tile, end_tile);
2955 byte style_t = (byte)(
TileX(end_tile) >
TileX(start_tile));
2970 {1, 0}, {1, 1}, {0, 1}, {1, 1},
2971 {1, 0}, {0, 0}, {1, 0}, {1, 1},
2972 {1, 0}, {1, 1}, {0, 1}, {1, 1},
2974 {0, 1}, {0, 0}, {1, 0}, {0, 0},
2975 {0, 1}, {0, 0}, {1, 1}, {0, 1},
2976 {1, 0}, {0, 0}, {0, 0}, {0, 1},
2986 if (swap && distance == 0) style = flip_style_direction[style];
2989 byte style_t = style * 2;
2990 assert(style_t <
lengthof(heightdiff_line_by_dir) - 13);
2997 if (distance == 0) style_t = flip_style_direction[style] * 2;
2998 assert(style_t <
lengthof(heightdiff_line_by_dir) - 13);
3006 if (swap)
Swap(h0, h1);
3010 static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
3020 if (test >= 0)
return;
3022 other += mult * test;
3035 if (test <= max)
return;
3037 other += mult * (test -
max);
3080 int offset = (raw_dx - raw_dy) / 2;
3115 int offset = (raw_dx + raw_dy + (int)
TILE_SIZE) / 2;
3164 }
else if (w > h * 2) {
3167 }
else if (h > w * 2) {
3181 }
else if (d >= 0) {
3192 }
else if (d >= 0) {
3205 }
else if (d >= 0) {
3216 }
else if (d >= 0) {
3234 if (distance != 1) {
3240 distance =
CeilDiv(distance, 2);
3243 params[index++] = distance;
3244 if (heightdiff != 0) params[index++] = heightdiff;
3293 if (
abs(sy - y) <
abs(sx - x)) {
3300 goto calc_heightdiff_single_direction;
3309 goto calc_heightdiff_single_direction;
3319 calc_heightdiff_single_direction:;
3321 x = sx +
Clamp(x - sx, -limit, limit);
3322 y = sy +
Clamp(y - sy, -limit, limit);
3331 if (distance != 1) {
3339 params[index++] = distance;
3340 if (heightdiff != 0) params[index++] = heightdiff;
3349 x = sx +
Clamp(x - sx, -limit, limit);
3350 y = sy +
Clamp(y - sy, -limit, limit);
3355 static const StringID measure_strings_area[] = {
3356 STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
3382 int a_max = dist_x + dist_y;
3383 int b_max = dist_y - dist_x;
3387 a_max =
abs(a_max + (a_max > 0 ? 2 : -2)) / 2;
3388 b_max =
abs(b_max + (b_max > 0 ? 2 : -2)) / 2;
3394 if (a_max != 1 || b_max != 1) {
3401 }
else if (dy == 1) {
3406 if (dx != 1 || dy != 1) {
3409 params[index++] = dx - (style &
HT_POINT ? 1 : 0);
3410 params[index++] = dy - (style &
HT_POINT ? 1 : 0);
3411 if (heightdiff != 0) params[index++] = heightdiff;
3418 default: NOT_REACHED();
3436 ResetObjectToPlace();
3517 void ResetObjectToPlace()
3543 { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
3551 for (uint i = 0; i <
lengthof(_vp_sprite_sorters); i++) {
3552 if (_vp_sprite_sorters[i].fct_checker()) {
3553 _vp_sprite_sorter = _vp_sprite_sorters[i].
fct_sorter;
3557 assert(_vp_sprite_sorter != NULL);