96 #include "table/strings.h"
101 Point _tile_fract_coords;
184 bool _draw_bounding_boxes =
false;
185 bool _draw_dirty_blocks =
false;
186 uint _dirty_block_colour = 0;
189 static Point MapXYZToViewport(
const ViewPort *vp,
int x,
int y,
int z)
197 void DeleteWindowViewport(
Window *w)
219 int width,
int height, uint32 follow_flags,
ZoomLevel zoom)
237 if (follow_flags & 0x80000000) {
248 pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y));
263 static Point _vp_move_offs;
265 static void DoSetViewportPosition(
const Window *w,
int left,
int top,
int width,
int height)
268 if (left + width > w->
left &&
270 top + height > w->
top &&
273 if (left < w->left) {
274 DoSetViewportPosition(w, left, top, w->
left - left, height);
275 DoSetViewportPosition(w, left + (w->
left - left), top, width - (w->
left - left), height);
280 DoSetViewportPosition(w, left, top, (w->
left + w->
width - left), height);
281 DoSetViewportPosition(w, left + (w->
left + w->
width - left), top, width - (w->
left + w->
width - left), height);
286 DoSetViewportPosition(w, left, top, width, (w->
top - top));
287 DoSetViewportPosition(w, left, top + (w->
top - top), width, height - (w->
top - top));
292 DoSetViewportPosition(w, left, top, width, (w->
top + w->
height - top));
293 DoSetViewportPosition(w, left, top + (w->
top + w->
height - top), width, height - (w->
top + w->
height - top));
302 int xo = _vp_move_offs.x;
303 int yo = _vp_move_offs.y;
305 if (
abs(xo) >= width ||
abs(yo) >= height) {
307 RedrawScreenRect(left, top, left + width, top + height);
311 GfxScroll(left, top, width, height, xo, yo);
314 RedrawScreenRect(left, top, xo + left, top + height);
318 RedrawScreenRect(left + width + xo, top, left + width, top + height);
323 RedrawScreenRect(left, top, width + left, top + yo);
325 RedrawScreenRect(left, top + height + yo, width + left, top + height);
330 static void SetViewportPosition(
Window *w,
int x,
int y)
336 int left, top, width, height;
352 if (old_top == 0 && old_left == 0)
return;
354 _vp_move_offs.x = old_left;
355 _vp_move_offs.y = old_top;
367 i = left + width - _screen.width;
368 if (i >= 0) width -= i;
376 i = top + height - _screen.height;
377 if (i >= 0) height -= i;
379 if (height > 0) DoSetViewportPosition(w->
z_front, left, top, width, height);
416 if ( (uint)(x -= vp->
left) >= (uint)vp->
width ||
417 (uint)(y -= vp->
top) >= (uint)vp->
height) {
434 b =
Clamp(b, -extra_tiles * TILE_SIZE,
MapMaxY() * TILE_SIZE - 1);
447 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;
448 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;
449 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;
451 pt.x =
Clamp(a + z, min_coord,
MapMaxX() * TILE_SIZE - 1);
452 pt.y =
Clamp(b + z, min_coord,
MapMaxY() * TILE_SIZE - 1);
460 static Point GetTileFromScreenXY(
int x,
int y,
int zoom_x,
int zoom_y)
474 Point GetTileBelowCursor()
476 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y);
486 x = ((_cursor.pos.x - vp->
left) >> 1) + (vp->
width >> 2);
487 y = ((_cursor.pos.y - vp->
top) >> 1) + (vp->
height >> 2);
489 x = vp->
width - (_cursor.pos.x - vp->
left);
490 y = vp->
height - (_cursor.pos.y - vp->
top);
493 return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->
left, y + vp->
top);
534 ts->
x = pt.x + extra_offs_x;
535 ts->
y = pt.y + extra_offs_y;
552 assert(
IsInsideMM(foundation_part, 0, FOUNDATION_PART_END));
553 assert(_vd.
foundation[foundation_part] != -1);
557 int *old_child = _vd.last_child;
560 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y,
false, sub,
false);
563 _vd.last_child = old_child;
588 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);
624 default: NOT_REACHED();
651 if (pt.x + spr->
x_offs >= _vd.dpi.left + _vd.dpi.width ||
653 pt.y + spr->
y_offs >= _vd.dpi.top + _vd.dpi.height ||
686 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)
688 int32 left, right, top, bottom;
703 _vd.last_child = NULL;
706 int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
709 if (image == SPR_EMPTY_BOUNDING_BOX) {
710 left = tmp_left =
RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
711 right =
RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1;
712 top = tmp_top =
RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
713 bottom =
RemapCoords(x + w , y + h , z + bb_offset_z).y + 1;
716 left = tmp_left = (pt.x += spr->
x_offs);
717 right = (pt.x + spr->
width );
718 top = tmp_top = (pt.y += spr->
y_offs);
719 bottom = (pt.y + spr->
height);
722 if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
724 left =
min(left ,
RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
725 right =
max(right ,
RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
726 top =
min(top ,
RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
727 bottom =
max(bottom,
RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
731 if (left >= _vd.dpi.left + _vd.dpi.width ||
732 right <= _vd.dpi.left ||
733 top >= _vd.dpi.top + _vd.dpi.height ||
734 bottom <= _vd.dpi.top) {
748 ps->
xmin = x + bb_offset_x;
749 ps->
xmax = x +
max(bb_offset_x, w) - 1;
751 ps->
ymin = y + bb_offset_y;
752 ps->
ymax = y +
max(bb_offset_y, h) - 1;
754 ps->
zmin = z + bb_offset_z;
755 ps->
zmax = z +
max(bb_offset_z, dz) - 1;
810 if (begin > end)
Swap(begin, end);
811 return begin <= check && check <= end;
822 int dist_a = (_thd.
size.x + _thd.
size.y);
823 int dist_b = (_thd.
size.x - _thd.
size.y);
824 int a = ((x - _thd.
pos.x) + (y - _thd.
pos.y));
825 int b = ((x - _thd.
pos.x) - (y - _thd.
pos.y));
846 if (_vd.last_child == NULL)
return;
854 *_vd.last_child = _vd.child_screen_sprites_to_draw.
Length();
860 cs->x = scale ? x * ZOOM_LVL_BASE : x;
861 cs->y = scale ? y * ZOOM_LVL_BASE : y;
869 _vd.last_child = &cs->
next;
872 static void AddStringToDraw(
int x,
int y,
StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width)
879 ss->params[0] = params_1;
880 ss->params[1] = params_2;
922 SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner;
927 sel = SPR_HALFTILE_SELECTION_DOWN;
931 sel += opposite_corner;
938 static bool IsPartOfAutoLine(
int px,
int py)
948 case HT_DIR_HU:
return px == -py || px == -py - 16;
949 case HT_DIR_HL:
return px == -py || px == -py + 16;
950 case HT_DIR_VL:
return px == py || px == py + 16;
951 case HT_DIR_VR:
return px == py || px == py - 16;
984 static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
986 if (autorail_type != _lower_rail[halftile_corner]) {
993 offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
995 image = SPR_AUTORAIL_BASE + offset;
998 image = SPR_AUTORAIL_BASE - offset;
1039 if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z +=
TILE_HEIGHT;
1040 if (halftile_corner != CORNER_S) {
1051 }
else if (IsPartOfAutoLine(ti->
x, ti->
y)) {
1069 if (!is_redsq && _thd.
outersize.x > 0 &&
1176 return tile_coord.y - tile_coord.x;
1190 if (tile.x < tile.y) {
1192 northern_end.y = tile.y - tile.x;
1194 northern_end.x = tile.x - tile.y;
1198 return northern_end;
1212 Point distance_to_end;
1213 distance_to_end.x = (int)
MapMaxX() - tile.x;
1214 distance_to_end.y = (int)
MapMaxY() - tile.y;
1217 if (distance_to_end.x < distance_to_end.y) {
1218 int number_of_steps =
min(limit, distance_to_end.x);
1219 southern_end.x = tile.x + number_of_steps;
1220 southern_end.y = tile.y + number_of_steps;
1222 int number_of_steps =
min(limit, distance_to_end.y);
1223 southern_end.x = tile.x + number_of_steps;
1224 southern_end.y = tile.y + number_of_steps;
1227 return southern_end;
1252 middle_tile.x = (lower_tile.x + upper_tile.x) / 2;
1253 middle_tile.y = (lower_tile.y + upper_tile.y) / 2;
1292 int northern_tile_viewport_y =
GetViewportY(northern_tile);
1293 int southern_tile_viewport_y =
GetViewportY(southern_tile);
1295 if (northern_tile_viewport_y >= viewport_y) {
1297 while (northern_tile_viewport_y >= viewport_y) {
1300 northern_tile_viewport_y =
GetViewportY(northern_tile);
1302 return northern_tile.x + northern_tile.y;
1305 if (southern_tile_viewport_y <= viewport_y) {
1307 while (southern_tile_viewport_y <= viewport_y) {
1310 southern_tile_viewport_y =
GetViewportY(southern_tile);
1312 return southern_tile.x + southern_tile.y;
1325 Point upper_tile = tile;
1333 if (middle_bound >= viewport_y) {
1336 lower_tile = middle_tile;
1340 upper_tile = middle_tile;
1343 while (lower_tile.y - upper_tile.y > 1);
1352 int correction_step = 0;
1353 if (bridge_correct) {
1362 for (
int n = 0; n < worst_case_steps_southwards; n++) {
1363 TileIndex potential_bridge_tile =
TileXY(upper_tile.x + n, upper_tile.y + n);
1368 int upper_tile_height =
GetTileZ(
TileXY(upper_tile.x, upper_tile.y));
1373 if (bridge_height - 2 * n - 1 > upper_tile_height) {
1374 correction_step = n;
1381 upper_tile.x += correction_step;
1382 upper_tile.y += correction_step;
1385 return upper_tile.x + upper_tile.y;
1405 int upper_row = upper_tile.x + upper_tile.y;
1406 int lower_row = lower_right_tile.x + lower_right_tile.y;
1408 assert(upper_row <= lower_row);
1410 int number_of_rows = lower_row - upper_row;
1412 if (number_of_rows % 2 != 0) {
1419 bottom_tile.x = upper_tile.x + number_of_rows / 2;
1420 bottom_tile.y = upper_tile.y + number_of_rows / 2;
1422 int bottom_row = bottom_tile.x + bottom_tile.y;
1424 assert(bottom_row >= lower_row);
1434 assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height);
1435 assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width);
1442 int viewport_top = _vd.dpi.top - 16;
1443 int viewport_bottom = _vd.dpi.top + _vd.dpi.height + 116;
1460 int *top_row =
AllocaM(
int, right_column - left_column + 1);
1461 int *bottom_row =
AllocaM(
int, right_column - left_column + 1);
1463 int max_bottom_row = 0;
1464 Point top_tile_of_column = upper_left_tile;
1467 bool south_east_direction =
false;
1468 for (
int x = left_column; x <= right_column; x++) {
1476 top_row[x - left_column] =
GetRowAtTile(viewport_top, top_tile_of_column,
false);
1478 top_row[x - left_column] -= 3;
1479 bottom_row[x - left_column] =
GetRowAtTile(viewport_bottom, bottom_tile_of_column,
true);
1480 bottom_row[x - left_column]++;
1483 min_top_row =
min(min_top_row, top_row[x - left_column]);
1484 max_bottom_row =
max(max_bottom_row, bottom_row[x - left_column]);
1487 if (south_east_direction) {
1488 top_tile_of_column.y++;
1490 top_tile_of_column.x--;
1494 south_east_direction = !south_east_direction;
1497 for (
int row = min_top_row; row <= max_bottom_row; row++) {
1498 for (
int column = left_column; column <= right_column; column++) {
1502 if (((row + column) % 2 == 0) &&
1503 (top_row[column - left_column] <= row) &&
1504 (row <= bottom_row[column - left_column])) {
1507 _cur_ti = &tile_info;
1511 int x = (row - column) / 2;
1512 int y = (row + column) / 2;
1518 if (0 < x && x < (
int)
MapMaxX() && 0 < y && y < (int)
MapMaxY()) {
1559 bool small = dpi->zoom >= small_from;
1561 int left = dpi->left;
1563 int right = left + dpi->width;
1564 int bottom = top + dpi->height;
1569 if (bottom < sign->top ||
1570 top > sign->
top + sign_height ||
1571 right < sign->center - sign_half_width ||
1572 left > sign->
center + sign_half_width) {
1577 AddStringToDraw(sign->
center - sign_half_width, sign->
top, string_normal, params_1, params_2, colour, sign->
width_normal);
1579 int shadow_offset = 0;
1580 if (string_small_shadow != STR_NULL) {
1582 AddStringToDraw(sign->
center - sign_half_width + shadow_offset, sign->
top, string_small_shadow, params_1, params_2, INVALID_COLOUR, sign->
width_small);
1584 AddStringToDraw(sign->
center - sign_half_width, sign->
top - shadow_offset, string_small, params_1, params_2,
1597 STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK,
1608 FOR_ALL_BASE_STATIONS(st) {
1619 is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT,
1620 (is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT) + 1, STR_NULL,
1659 GetString(buffer, str,
lastof(buffer));
1682 zoomlevels[zoom].top = this->top -
ScaleByZoom(1, zoom);
1688 FOR_ALL_WINDOWS_FROM_BACK(w) {
1690 if (vp != NULL && vp->
zoom <= maxzoom) {
1691 assert(vp->
width != 0);
1717 while (psd != psdvend) {
1763 *psd3 = *(psd3 - 1);
1778 while (child_idx >= 0) {
1780 child_idx = cs->
next;
1801 pt2.x - pt1.x, pt2.y - pt1.y,
1802 pt3.x - pt1.x, pt3.y - pt1.y,
1803 pt4.x - pt1.x, pt4.y - pt1.y);
1822 byte bo =
UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
1824 for (
int i = (bo ^= 1); i < right; i += 2) blitter->
SetPixel(dst, i, 0, (uint8)colour);
1825 dst = blitter->
MoveTo(dst, 0, 1);
1826 }
while (--bottom > 0);
1834 bool small =
HasBit(ss->width, 15);
1835 int w =
GB(ss->width, 0, 15);
1843 if (ss->colour != INVALID_COLOUR) {
1856 x, y, x + w, y + h, ss->colour,
1866 void ViewportDoDraw(
const ViewPort *vp,
int left,
int top,
int right,
int bottom)
1869 _cur_dpi = &_vd.dpi;
1871 _vd.dpi.zoom = vp->
zoom;
1876 _vd.dpi.width = (right - left) & mask;
1877 _vd.dpi.height = (bottom - top) & mask;
1878 _vd.dpi.left = left & mask;
1879 _vd.dpi.top = top & mask;
1880 _vd.dpi.pitch = old_dpi->pitch;
1881 _vd.last_child = NULL;
1891 ViewportAddTownNames(&_vd.dpi);
1892 ViewportAddStationNames(&_vd.dpi);
1893 ViewportAddSigns(&_vd.dpi);
1895 DrawTextEffects(&_vd.dpi);
1897 if (_vd.tile_sprites_to_draw.
Length() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw);
1921 vp->overlay->
Draw(&dp);
1924 if (_vd.string_sprites_to_draw.
Length() != 0) {
1928 ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw);
1933 _vd.string_sprites_to_draw.
Clear();
1934 _vd.tile_sprites_to_draw.
Clear();
1935 _vd.parent_sprites_to_draw.
Clear();
1937 _vd.child_screen_sprites_to_draw.
Clear();
1947 if ((bottom - top) > (right - left)) {
1948 int t = (top + bottom) >> 1;
1952 int t = (left + right) >> 1;
1966 static inline void ViewportDraw(
const ViewPort *vp,
int left,
int top,
int right,
int bottom)
1968 if (right <= vp->left || bottom <= vp->top)
return;
1970 if (left >= vp->
left + vp->
width)
return;
1972 if (left < vp->left) left = vp->
left;
1975 if (top >= vp->
top + vp->
height)
return;
1977 if (top < vp->top) top = vp->
top;
1990 dpi->left += this->
left;
1991 dpi->top += this->
top;
1993 ViewportDraw(this->
viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
1995 dpi->left -= this->
left;
1996 dpi->top -= this->
top;
2031 iter =
Clamp(iter + offset, 0, iter_limit);
2033 }
while (continue_criteria(iter, iter_limit, sy, sy_limit));
2052 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)
2064 other_ref = upper_edge ? 0 : other_limit;
2071 min_iter =
min(min_iter, max_iter);
2074 int max_heightlevel_at_edge = 0;
2075 for (iter = min_iter; iter <= max_iter; iter += 10) {
2076 max_heightlevel_at_edge =
max(max_heightlevel_at_edge, (
int)
TileHeight(
TileXY(curr_tile.x, curr_tile.y)));
2082 max(vp_value, -max_heightlevel_at_edge * (
int)(
TILE_HEIGHT * 2 * ZOOM_LVL_BASE)) :
2086 static inline void ClampViewportToMap(
const ViewPort *vp,
int &x,
int &y)
2096 int vx = -x + y * 2;
2101 int tx = vx / (int)(
TILE_SIZE * 4 * ZOOM_LVL_BASE);
2102 int ty = vy / (int)(
TILE_SIZE * 4 * ZOOM_LVL_BASE);
2131 SetViewportPosition(w, pt.x, pt.y);
2139 bool update_overlay =
false;
2140 if (delta_x != 0 || delta_y != 0) {
2157 if (update_overlay) RebuildViewportOverlay(w);
2173 right += (1 << vp->
zoom) - 1;
2174 bottom += (1 << vp->
zoom) - 1;
2177 if (right <= 0)
return;
2180 if (bottom <= 0)
return;
2209 FOR_ALL_WINDOWS_FROM_BACK(w) {
2212 assert(vp->
width != 0);
2218 void ConstrainAllViewportsZoom()
2221 FOR_ALL_WINDOWS_FROM_FRONT(w) {
2272 int x_size = _thd.
size.x;
2273 int y_size = _thd.
size.y;
2276 int x_start = _thd.
pos.x;
2277 int y_start = _thd.
pos.y;
2281 x_start += _thd.
offs.x;
2283 y_start += _thd.
offs.y;
2289 assert(x_size >= 0);
2290 assert(y_size >= 0);
2299 assert((x_end | y_end | x_start | y_start) %
TILE_SIZE == 0);
2320 int top_y = y_start;
2341 static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE;
2347 if (top_x != x_start) {
2354 if (bot_y != y_end) {
2359 }
while (bot_x >= top_x);
2362 int a_size = x_size + y_size, b_size = x_size - y_size;
2367 for (
int a = -interval_a; a != a_size + interval_a; a += interval_a) {
2368 for (
int b = -interval_b; b != b_size + interval_b; b += interval_b) {
2381 void SetSelectionRed(
bool b)
2404 return y >= sign->
top && y < sign->
top + sign_height &&
2405 x >= sign->
center - sign_half_width && x < sign->
center + sign_half_width;
2408 static bool CheckClickOnTown(
const ViewPort *vp,
int x,
int y)
2415 ShowTownViewWindow(t->
index);
2423 static bool CheckClickOnStation(
const ViewPort *vp,
int x,
int y)
2428 FOR_ALL_BASE_STATIONS(st) {
2452 static bool CheckClickOnSign(
const ViewPort *vp,
int x,
int y)
2461 if (si->owner ==
OWNER_DEITY && _game_mode != GM_EDITOR)
continue;
2473 static bool CheckClickOnLandscape(
const ViewPort *vp,
int x,
int y)
2477 if (pt.x != -1)
return ClickTile(
TileVirtXY(pt.x, pt.y));
2481 static void PlaceObject()
2486 pt = GetTileBelowCursor();
2487 if (pt.x == -1)
return;
2502 bool HandleViewportClicked(
const ViewPort *vp,
int x,
int y)
2516 if (CheckClickOnTown(vp, x, y))
return true;
2517 if (CheckClickOnStation(vp, x, y))
return true;
2518 if (CheckClickOnSign(vp, x, y))
return true;
2519 bool result = CheckClickOnLandscape(vp, x, y);
2536 void RebuildViewportOverlay(
Window *w)
2538 if (w->
viewport->overlay != NULL &&
2561 z = GetSlopePixelZ(x, y);
2575 RebuildViewportOverlay(w);
2636 void SetTileSelectBigSize(
int ox,
int oy,
int sx,
int sy)
2694 bool new_diagonal =
false;
2706 new_diagonal =
true;
2708 if (x1 >= x2)
Swap(x1, x2);
2709 if (y1 >= y2)
Swap(y1, y2);
2715 if (!new_diagonal) {
2722 Point pt = GetTileBelowCursor();
2754 default: NOT_REACHED();
2837 void VpSetPlaceSizingLimit(
int limit)
2861 static void VpStartPreSizing()
2873 int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
2875 int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
2879 default: NOT_REACHED();
2881 if (fxpy >= 20 && sxpy <= 12)
return HT_DIR_HL;
2882 if (fxmy < -3 && sxmy > 3)
return HT_DIR_VR;
2886 if (fxmy > 3 && sxmy < -3)
return HT_DIR_VL;
2887 if (fxpy <= 12 && sxpy >= 20)
return HT_DIR_HU;
2891 if (fxmy > 3 && sxmy < -3)
return HT_DIR_VL;
2892 if (fxpy >= 20 && sxpy <= 12)
return HT_DIR_HL;
2896 if (fxmy < -3 && sxmy > 3)
return HT_DIR_VR;
2897 if (fxpy <= 12 && sxpy >= 20)
return HT_DIR_HU;
2917 uint start_x =
TileX(start_tile);
2918 uint start_y =
TileY(start_tile);
2919 uint end_x =
TileX(end_tile);
2920 uint end_y =
TileY(end_tile);
2924 case HT_LINE:
return (end_x > start_x || (end_x == start_x && end_y > start_y));
2927 case HT_POINT:
return (end_x != start_x && end_y < start_y);
2928 default: NOT_REACHED();
2954 if (start_tile == end_tile)
return 0;
2955 if (swap)
Swap(start_tile, end_tile);
2966 byte style_t = (byte)(
TileX(end_tile) >
TileX(start_tile));
2981 {1, 0}, {1, 1}, {0, 1}, {1, 1},
2982 {1, 0}, {0, 0}, {1, 0}, {1, 1},
2983 {1, 0}, {1, 1}, {0, 1}, {1, 1},
2985 {0, 1}, {0, 0}, {1, 0}, {0, 0},
2986 {0, 1}, {0, 0}, {1, 1}, {0, 1},
2987 {1, 0}, {0, 0}, {0, 0}, {0, 1},
2997 if (swap && distance == 0) style = flip_style_direction[style];
3000 byte style_t = style * 2;
3001 assert(style_t <
lengthof(heightdiff_line_by_dir) - 13);
3008 if (distance == 0) style_t = flip_style_direction[style] * 2;
3009 assert(style_t <
lengthof(heightdiff_line_by_dir) - 13);
3017 if (swap)
Swap(h0, h1);
3021 static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF};
3031 if (test >= 0)
return;
3033 other += mult * test;
3046 if (test <= max)
return;
3048 other += mult * (test -
max);
3091 int offset = (raw_dx - raw_dy) / 2;
3126 int offset = (raw_dx + raw_dy + (int)
TILE_SIZE) / 2;
3175 }
else if (w > h * 2) {
3178 }
else if (h > w * 2) {
3192 }
else if (d >= 0) {
3203 }
else if (d >= 0) {
3216 }
else if (d >= 0) {
3227 }
else if (d >= 0) {
3245 if (distance != 1) {
3251 distance =
CeilDiv(distance, 2);
3254 params[index++] = distance;
3255 if (heightdiff != 0) params[index++] = heightdiff;
3304 if (
abs(sy - y) <
abs(sx - x)) {
3311 goto calc_heightdiff_single_direction;
3320 goto calc_heightdiff_single_direction;
3330 calc_heightdiff_single_direction:;
3332 x = sx +
Clamp(x - sx, -limit, limit);
3333 y = sy +
Clamp(y - sy, -limit, limit);
3342 if (distance != 1) {
3350 params[index++] = distance;
3351 if (heightdiff != 0) params[index++] = heightdiff;
3360 x = sx +
Clamp(x - sx, -limit, limit);
3361 y = sy +
Clamp(y - sy, -limit, limit);
3366 static const StringID measure_strings_area[] = {
3367 STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF
3393 int a_max = dist_x + dist_y;
3394 int b_max = dist_y - dist_x;
3398 a_max =
abs(a_max + (a_max > 0 ? 2 : -2)) / 2;
3399 b_max =
abs(b_max + (b_max > 0 ? 2 : -2)) / 2;
3405 if (a_max != 1 || b_max != 1) {
3412 }
else if (dy == 1) {
3417 if (dx != 1 || dy != 1) {
3420 params[index++] = dx - (style &
HT_POINT ? 1 : 0);
3421 params[index++] = dy - (style &
HT_POINT ? 1 : 0);
3422 if (heightdiff != 0) params[index++] = heightdiff;
3429 default: NOT_REACHED();
3447 ResetObjectToPlace();
3528 void ResetObjectToPlace()
3554 { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
3562 for (uint i = 0; i <
lengthof(_vp_sprite_sorters); i++) {
3563 if (_vp_sprite_sorters[i].fct_checker()) {
3564 _vp_sprite_sorter = _vp_sprite_sorters[i].
fct_sorter;
3568 assert(_vp_sprite_sorter != NULL);