Add zoom in support to the small map

Heavily referenced from citimania
6f8e0c144b
This commit is contained in:
Jonathan G Rennison
2023-01-17 23:07:54 +00:00
parent aaf9fcebee
commit 4bc19fad60
2 changed files with 128 additions and 216 deletions

View File

@@ -631,32 +631,12 @@ static const byte _vehicle_type_colours[6] = {
InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES); InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES);
} }
inline Point SmallMapWindow::SmallmapRemapCoords(int x, int y) const inline Point SmallMapWindow::TileToPixel(int tx, int ty) const
{ {
Point pt; return {
pt.x = (y - x) * 2; (ty - tx) * 2 / this->zoom + this->scroll_x,
pt.y = y + x; (ty + tx) / this->zoom + this->scroll_y,
return pt; };
}
/**
* Remap tile to location on this smallmap.
* @param tile_x X coordinate of the tile.
* @param tile_y Y coordinate of the tile.
* @return Position to draw on.
*/
inline Point SmallMapWindow::RemapTile(int tile_x, int tile_y) const
{
int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset);
/* For negative offsets, round towards -inf. */
if (x_offset < 0) x_offset -= this->zoom - 1;
if (y_offset < 0) y_offset -= this->zoom - 1;
return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom);
} }
/** /**
@@ -664,63 +644,16 @@ inline Point SmallMapWindow::RemapTile(int tile_x, int tile_y) const
* that tile for a point in the smallmap. * that tile for a point in the smallmap.
* @param px Horizontal coordinate of the pixel. * @param px Horizontal coordinate of the pixel.
* @param py Vertical coordinate of the pixel. * @param py Vertical coordinate of the pixel.
* @param[out] sub Pixel position at the tile (0..3).
* @param add_sub Add current #subscroll to the position.
* @return Tile being displayed at the given position relative to #scroll_x and #scroll_y.
* @note The #subscroll offset is already accounted for.
*/ */
inline Point SmallMapWindow::PixelToTile(int px, int py, int *sub, bool add_sub) const inline Point SmallMapWindow::PixelToTile(int px, int py) const
{ {
if (add_sub) px += this->subscroll; // Total horizontal offset. px -= this->scroll_x;
py -= this->scroll_y;
/* For each two rows down, add a x and a y tile, and return {
* For each four pixels to the right, move a tile to the right. */ (py * 2 - px) * this->zoom / 4,
Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom}; (py * 2 + px) * this->zoom / 4,
px &= 3; };
if (py & 1) { // Odd number of rows, handle the 2 pixel shift.
if (px < 2) {
pt.x += this->zoom;
px += 2;
} else {
pt.y += this->zoom;
px -= 2;
}
}
*sub = px;
return pt;
}
/**
* Compute base parameters of the smallmap such that tile (\a tx, \a ty) starts at pixel (\a x, \a y).
* @param tx Tile x coordinate.
* @param ty Tile y coordinate.
* @param x Non-negative horizontal position in the display where the tile starts.
* @param y Non-negative vertical position in the display where the tile starts.
* @param[out] sub Value of #subscroll needed.
* @return #scroll_x, #scroll_y values.
*/
Point SmallMapWindow::ComputeScroll(int tx, int ty, int x, int y, int *sub)
{
assert(x >= 0 && y >= 0);
int new_sub;
Point tile_xy = PixelToTile(x, y, &new_sub, false);
tx -= tile_xy.x;
ty -= tile_xy.y;
Point scroll;
if (new_sub == 0) {
*sub = 0;
scroll.x = (tx + this->zoom) * TILE_SIZE;
scroll.y = (ty - this->zoom) * TILE_SIZE;
} else {
*sub = 4 - new_sub;
scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
}
return scroll;
} }
/** /**
@@ -731,27 +664,28 @@ Point SmallMapWindow::ComputeScroll(int tx, int ty, int x, int y, int *sub)
*/ */
void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt) void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
{ {
static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away). static const int tile_zoomlevels[] = {1, 1, 1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away).
static const int ui_zoomlevels[] = {4, 2, 1, 1, 1, 1, 1};
static const int MIN_ZOOM_INDEX = 0; static const int MIN_ZOOM_INDEX = 0;
static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1; static const int MAX_ZOOM_INDEX = lengthof(tile_zoomlevels) - 1;
int new_index, cur_index, sub; int new_index, cur_index;
Point tile; Point tile;
switch (change) { switch (change) {
case ZLC_INITIALIZE: case ZLC_INITIALIZE:
cur_index = - 1; // Definitely different from new_index. cur_index = - 1; // Definitely different from new_index.
new_index = MIN_ZOOM_INDEX; new_index = Clamp((int)ZOOM_LVL_GUI, MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
tile.x = tile.y = 0; tile.x = tile.y = 0;
break; break;
case ZLC_ZOOM_IN: case ZLC_ZOOM_IN:
case ZLC_ZOOM_OUT: case ZLC_ZOOM_OUT:
for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) { for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
if (this->zoom == zoomlevels[cur_index]) break; if (this->tile_zoom == tile_zoomlevels[cur_index] && this->ui_zoom == ui_zoomlevels[cur_index]) break;
} }
assert(cur_index <= MAX_ZOOM_INDEX); assert(cur_index <= MAX_ZOOM_INDEX);
tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); tile = this->PixelToTile(zoom_pt->x, zoom_pt->y);
new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX); new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
break; break;
@@ -759,14 +693,16 @@ void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
} }
if (new_index != cur_index) { if (new_index != cur_index) {
this->zoom = zoomlevels[new_index]; this->tile_zoom = tile_zoomlevels[new_index];
this->ui_zoom = ui_zoomlevels[new_index];
this->zoom = this->tile_zoom * TILE_SIZE / this->ui_zoom;
if (cur_index >= 0) { if (cur_index >= 0) {
Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); Point new_tile = this->TileToPixel(tile.x, tile.y);
this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE, this->scroll_x += zoom_pt->x - new_tile.x;
this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub); this->scroll_y += zoom_pt->y - new_tile.y;
} }
this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]); this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->ui_zoom == ui_zoomlevels[MIN_ZOOM_INDEX]);
this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]); this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->tile_zoom == tile_zoomlevels[MAX_ZOOM_INDEX]);
this->SetDirty(); this->SetDirty();
} }
} }
@@ -865,11 +801,15 @@ inline uint32 SmallMapWindow::GetTileColours(const TileArea &ta) const
* @param blitter current blitter * @param blitter current blitter
* @note If pixel position is below \c 0, skip drawing. * @note If pixel position is below \c 0, skip drawing.
*/ */
void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, int y, int end_y, Blitter *blitter) const
{ {
void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height); void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
int hidden_x = std::max(0, -start_pos);
int hidden_idx = hidden_x / this->ui_zoom;
int hidden_mod = hidden_x % this->ui_zoom;
do { do {
/* Check if the tile (xc,yc) is within the map range */ /* Check if the tile (xc,yc) is within the map range */
if (xc >= MapMaxX() || yc >= MapMaxY()) continue; if (xc >= MapMaxX() || yc >= MapMaxY()) continue;
@@ -881,23 +821,47 @@ void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch,
/* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */ /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */
TileArea ta; TileArea ta;
if (min_xy == 1 && (xc == 0 || yc == 0)) { if (min_xy == 1 && (xc == 0 || yc == 0)) {
if (this->zoom == 1) continue; // The tile area is empty, don't draw anything. if (this->tile_zoom == 1) continue; // The tile area is empty, don't draw anything.
ta = TileArea(TileXY(std::max(min_xy, xc), std::max(min_xy, yc)), this->tile_zoom - (xc == 0), this->tile_zoom - (yc == 0));
ta = TileArea(TileXY(std::max(min_xy, xc), std::max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
} else { } else {
ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom); ta = TileArea(TileXY(xc, yc), this->tile_zoom, this->tile_zoom);
} }
ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!). ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!).
uint32 val = this->GetTileColours(ta); uint32 val = this->GetTileColours(ta);
uint8 *val8 = (uint8 *)&val; uint8 *val8 = (uint8 *)&val;
if (this->ui_zoom == 1) {
int idx = std::max(0, -start_pos); int idx = std::max(0, -start_pos);
if (y >= 0 && y < end_y) {
for (int pos = std::max(0, start_pos); pos < end_pos; pos++) { for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
blitter->SetPixel(dst, idx, 0, val8[idx]); blitter->SetPixel(dst, idx, 0, val8[idx]);
idx++; idx++;
} }
}
} else {
auto ndst = dst;
auto ny = y;
for (auto i = 0; i < this->ui_zoom; i++) {
if (ny >= 0 && ny < end_y) {
int idx = hidden_idx;
int j = hidden_mod;
int x = hidden_x;
for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
blitter->SetPixel(ndst, x, 0, val8[idx]);
j++;
x++;
if (j == this->ui_zoom) {
idx++;
j = 0;
}
}
}
ndst = blitter->MoveTo(ndst, pitch, 0);
ny++;
}
}
/* Switch to next tile in the column */ /* Switch to next tile in the column */
} while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); } while (xc += this->tile_zoom, yc += this->tile_zoom, dst = blitter->MoveTo(dst, pitch * this->ui_zoom * 2, 0), y += 2 * this->ui_zoom, --reps != 0);
} }
/** /**
@@ -912,30 +876,23 @@ void SmallMapWindow::DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) co
if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue; if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
/* Remap into flat coordinates. */ /* Remap into flat coordinates. */
Point pt = this->RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE); Point pt = this->TileToPixel(v->x_pos & ~TILE_UNIT_MASK, v->y_pos & ~TILE_UNIT_MASK);
int y = pt.y - dpi->top; int y = pt.y - dpi->top;
if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds. int x = pt.x - 1 * this->ui_zoom - dpi->left; // Offset X coordinate.
if (!IsInsideMM(y, -this->ui_zoom + 1, dpi->height)) continue; // y is out of bounds.
bool skip = false; // Default is to draw both pixels.
int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
if (x < 0) {
/* if x+1 is 0, that means we're on the very left edge,
* and should thus only draw a single pixel */
if (++x != 0) continue;
skip = true;
} else if (x >= dpi->width - 1) {
/* Check if we're at the very right edge, and if so draw only a single pixel */
if (x != dpi->width - 1) continue;
skip = true;
}
/* Calculate pointer to pixel and the colour */ /* Calculate pointer to pixel and the colour */
byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
/* And draw either one or two pixels depending on clipping */ /* And draw either one or two pixels depending on clipping */
blitter->SetPixel(dpi->dst_ptr, x, y, colour); auto min_i = std::max(0, -y);
if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour); auto max_i = std::min(this->ui_zoom, dpi->height - y);
auto min_j = std::max(0, -x);
auto max_j = std::min(2 * this->ui_zoom, dpi->width - x);
if (min_i < max_i && min_j < max_j) {
blitter->DrawRectAt(dpi->dst_ptr, x + min_j, y + min_i, max_j - min_j, max_i - min_i, colour);
}
} }
} }
@@ -947,8 +904,8 @@ void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const
{ {
for (const Town *t : Town::Iterate()) { for (const Town *t : Town::Iterate()) {
/* Remap the town coordinate */ /* Remap the town coordinate */
Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy)); Point pt = this->TileToPixel(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE);
int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1); int x = pt.x - (t->cache.sign.width_small >> 1);
int y = pt.y; int y = pt.y;
/* Check if the town sign is within bounds */ /* Check if the town sign is within bounds */
@@ -974,11 +931,8 @@ void SmallMapWindow::DrawMapIndicators() const
Point upper_left_smallmap_coord = InverseRemapCoords2(vp->virtual_left, vp->virtual_top); Point upper_left_smallmap_coord = InverseRemapCoords2(vp->virtual_left, vp->virtual_top);
Point lower_right_smallmap_coord = InverseRemapCoords2(vp->virtual_left + vp->virtual_width - 1, vp->virtual_top + vp->virtual_height - 1); Point lower_right_smallmap_coord = InverseRemapCoords2(vp->virtual_left + vp->virtual_width - 1, vp->virtual_top + vp->virtual_height - 1);
Point upper_left = this->RemapTile(upper_left_smallmap_coord.x / (int)TILE_SIZE, upper_left_smallmap_coord.y / (int)TILE_SIZE); Point upper_left = this->TileToPixel(upper_left_smallmap_coord.x, upper_left_smallmap_coord.y);
upper_left.x -= this->subscroll; Point lower_right = this->TileToPixel(lower_right_smallmap_coord.x, lower_right_smallmap_coord.y);
Point lower_right = this->RemapTile(lower_right_smallmap_coord.x / (int)TILE_SIZE, lower_right_smallmap_coord.y / (int)TILE_SIZE);
lower_right.x -= this->subscroll;
SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y); SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y);
SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y); SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y);
@@ -1010,38 +964,43 @@ void SmallMapWindow::DrawSmallMap(DrawPixelInfo *dpi, bool draw_indicators) cons
GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK); GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK);
/* Which tile is displayed at (dpi->left, dpi->top)? */ /* Which tile is displayed at (dpi->left, dpi->top)? */
int dx; Point tile = this->PixelToTile(dpi->left, dpi->top);
Point tile = this->PixelToTile(dpi->left, dpi->top, &dx); int tile_x = tile.x / (int)TILE_SIZE + this->tile_zoom;
int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x; int tile_y = tile.y / (int)TILE_SIZE - 2 * this->tile_zoom;
int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y; tile_x -= tile_x % this->tile_zoom;
tile_y -= tile_y % this->tile_zoom;
Point tile_pos = this->TileToPixel(tile_x * TILE_SIZE, tile_y * TILE_SIZE);
int dx = tile_pos.x - dpi->left;
int dy = tile_pos.y - dpi->top;
void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); int x = dx - 2 * this->ui_zoom;
int x = - dx - 4; int y = dy;
int y = 0; void *ptr = blitter->MoveTo(dpi->dst_ptr, x, y);
bool even = true;
for (;;) { for (;;) {
/* Distance from left edge */ /* Distance from left edge */
if (x >= -3) { if (x > -4 * this->ui_zoom) {
if (x >= dpi->width) break; // Exit the loop. if (x >= dpi->width) break; // Exit the loop.
int end_pos = std::min(dpi->width, x + 4); int end_pos = std::min(dpi->width, x + 4 * this->ui_zoom);
int reps = (dpi->height - y + 1) / 2; // Number of lines. int reps = (dpi->height - y + 3 * this->ui_zoom - 1) / 2 / this->ui_zoom; // Number of lines.
if (reps > 0) { if (reps > 0) {
this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter); this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch, reps, x, end_pos, y, dpi->height, blitter);
} }
} }
if (even) {
if (y == 0) { tile_y += this->tile_zoom;
tile_y += this->zoom; y += this->ui_zoom;
y++; ptr = blitter->MoveTo(ptr, 0, this->ui_zoom);
ptr = blitter->MoveTo(ptr, 0, 1);
} else { } else {
tile_x -= this->zoom; tile_x -= this->tile_zoom;
y--; y -= this->ui_zoom;
ptr = blitter->MoveTo(ptr, 0, -1); ptr = blitter->MoveTo(ptr, 0, -this->ui_zoom);
} }
ptr = blitter->MoveTo(ptr, 2, 0); even = !even;
x += 2; ptr = blitter->MoveTo(ptr, 2 * this->ui_zoom, 0);
x += 2 * this->ui_zoom;
} }
/* Draw vehicles */ /* Draw vehicles */
@@ -1462,10 +1421,8 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP); const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
Window *w = GetMainWindow(); Window *w = GetMainWindow();
int sub; pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y);
pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub); ScrollWindowTo(pt.x, pt.y, -1, w);
ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w);
this->SetDirty(); this->SetDirty();
break; break;
} }
@@ -1652,13 +1609,13 @@ uint SmallMapWindow::GetRefreshPeriod() const
switch (map_type) { switch (map_type) {
case SMT_CONTOUR: case SMT_CONTOUR:
case SMT_VEHICLES: case SMT_VEHICLES:
return FORCE_REFRESH_PERIOD_VEH * (1 + (this->zoom / 2)); return FORCE_REFRESH_PERIOD_VEH * (1 + (this->tile_zoom / 2));
case SMT_LINKSTATS: case SMT_LINKSTATS:
return FORCE_REFRESH_PERIOD_LINK_GRAPH * (1 + (this->zoom / 6)); return FORCE_REFRESH_PERIOD_LINK_GRAPH * (1 + (this->tile_zoom / 6));
default: default:
return FORCE_REFRESH_PERIOD * (1 + (this->zoom / 6)); return FORCE_REFRESH_PERIOD * (1 + (this->tile_zoom / 6));
} }
} }
@@ -1679,51 +1636,12 @@ uint SmallMapWindow::PausedAdjustRefreshTimeDelta(uint delta_ms) const
} }
} }
/**
* Set new #scroll_x, #scroll_y, and #subscroll values after limiting them such that the center
* of the smallmap always contains a part of the map.
* @param sx Proposed new #scroll_x
* @param sy Proposed new #scroll_y
* @param sub Proposed new #subscroll
*/
void SmallMapWindow::SetNewScroll(int sx, int sy, int sub)
{
const NWidgetBase *wi = this->GetWidget<NWidgetBase>(WID_SM_MAP);
Point hv = InverseRemapCoords(wi->current_x * ZOOM_LVL_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_LVL_BASE * TILE_SIZE / 2);
hv.x *= this->zoom;
hv.y *= this->zoom;
if (sx < -hv.x) {
sx = -hv.x;
sub = 0;
}
if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) {
sx = MapMaxX() * TILE_SIZE - hv.x;
sub = 0;
}
if (sy < -hv.y) {
sy = -hv.y;
sub = 0;
}
if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) {
sy = MapMaxY() * TILE_SIZE - hv.y;
sub = 0;
}
this->scroll_x = sx;
this->scroll_y = sy;
this->subscroll = sub;
}
/* virtual */ void SmallMapWindow::OnScroll(Point delta) /* virtual */ void SmallMapWindow::OnScroll(Point delta)
{ {
if (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED) _cursor.fix_at = true; if (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED) _cursor.fix_at = true;
/* While tile is at (delta.x, delta.y)? */ this->scroll_x -= delta.x;
int sub; this->scroll_y -= delta.y;
Point pt = this->PixelToTile(delta.x, delta.y, &sub);
this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
this->SetDirty(); this->SetDirty();
} }
@@ -1735,11 +1653,10 @@ void SmallMapWindow::SmallMapCenterOnCurrentPos()
const Viewport *vp = GetMainWindow()->viewport; const Viewport *vp = GetMainWindow()->viewport;
Point viewport_center = InverseRemapCoords2(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2); Point viewport_center = InverseRemapCoords2(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2);
int sub;
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP); const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
Point sxy = this->ComputeScroll(viewport_center.x / (int)TILE_SIZE, viewport_center.y / (int)TILE_SIZE, auto pt = this->TileToPixel(viewport_center.x, viewport_center.y);
std::max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub); this->scroll_x += std::max(0, (int)wid->current_x / 2 - 2) - pt.x;
this->SetNewScroll(sxy.x, sxy.y, sub); this->scroll_y += wid->current_y / 2 - pt.y;
this->SetDirty(); this->SetDirty();
} }
@@ -1750,14 +1667,14 @@ void SmallMapWindow::SmallMapCenterOnCurrentPos()
*/ */
Point SmallMapWindow::GetStationMiddle(const Station *st) const Point SmallMapWindow::GetStationMiddle(const Station *st) const
{ {
int x = CenterBounds(st->rect.left, st->rect.right, 0); int x = (st->rect.right + st->rect.left + 1) * TILE_SIZE / 2;
int y = CenterBounds(st->rect.top, st->rect.bottom, 0); int y = (st->rect.bottom + st->rect.top + 1) * TILE_SIZE / 2;
Point ret = this->RemapTile(x, y); Point ret = this->TileToPixel(x, y);
/* Same magic 3 as in DrawVehicles; that's where I got it from. /* Same magic 3 as in DrawVehicles; that's where I got it from.
* No idea what it is, but without it the result looks bad. * No idea what it is, but without it the result looks bad.
*/ */
ret.x -= 3 + this->subscroll; ret.x -= 3;
return ret; return ret;
} }
@@ -1767,17 +1684,14 @@ Point SmallMapWindow::GetStationMiddle(const Station *st) const
*/ */
void SmallMapWindow::TakeScreenshot() void SmallMapWindow::TakeScreenshot()
{ {
int32 width = ((MapMaxX() + MapMaxY()) * 2) / this->zoom; int32 width = (((MapMaxX() + MapMaxY()) * 2) * this->ui_zoom) / this->tile_zoom;
int32 height = (MapMaxX() + MapMaxY() + 1) / this->zoom; int32 height = ((MapMaxX() + MapMaxY() + 1) * this->ui_zoom) / this->tile_zoom;
int32 saved_scroll_x = this->scroll_x; int32 saved_scroll_x = this->scroll_x;
int32 saved_scroll_y = this->scroll_y; int32 saved_scroll_y = this->scroll_y;
int32 saved_subscroll = this->subscroll;
this->subscroll = 0;
MakeSmallMapScreenshot(width, height, this); MakeSmallMapScreenshot(width, height, this);
this->scroll_x = saved_scroll_x; this->scroll_x = saved_scroll_x;
this->scroll_y = saved_scroll_y; this->scroll_y = saved_scroll_y;
this->subscroll = saved_subscroll;
} }
/** /**
@@ -1806,7 +1720,7 @@ void SmallMapWindow::ScreenshotCallbackHandler(void *buf, uint y, uint pitch, ui
dpi.dst_ptr = buf; dpi.dst_ptr = buf;
dpi.height = n; dpi.height = n;
dpi.width = ((MapMaxX() + MapMaxY()) * 2) / this->zoom; dpi.width = (((MapMaxX() + MapMaxY()) * 2) * this->ui_zoom) / this->tile_zoom;
dpi.pitch = pitch; dpi.pitch = pitch;
dpi.zoom = ZOOM_LVL_NORMAL; dpi.zoom = ZOOM_LVL_NORMAL;
dpi.left = 0; dpi.left = 0;

View File

@@ -102,14 +102,14 @@ protected:
int32 scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display. int32 scroll_x; ///< Horizontal world coordinate of the base tile left of the top-left corner of the smallmap display.
int32 scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display. int32 scroll_y; ///< Vertical world coordinate of the base tile left of the top-left corner of the smallmap display.
int32 subscroll; ///< Number of pixels (0..3) between the right end of the base tile and the pixel at the top-left corner of the smallmap display. int tile_zoom; ///< Tile zoom level. Bigger number means more zoom-out (further away).
int zoom; ///< Zoom level. Bigger number means more zoom-out (further away). int ui_zoom; ///< UI (pixel doubling) Zoom level. Bigger number means more zoom-in (closer).
int zoom = 1; ///< Zoom level. Bigger number means more zoom-out (further away).
GUITimer refresh; ///< Refresh timer. GUITimer refresh; ///< Refresh timer.
LinkGraphOverlay *overlay; LinkGraphOverlay *overlay;
static void BreakIndustryChainLink(); static void BreakIndustryChainLink();
Point SmallmapRemapCoords(int x, int y) const;
/** /**
* Draws vertical part of map indicator * Draws vertical part of map indicator
@@ -177,19 +177,17 @@ protected:
uint GetNumberRowsLegend(uint columns) const; uint GetNumberRowsLegend(uint columns) const;
void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0); void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0);
void SwitchMapType(SmallMapType map_type); void SwitchMapType(SmallMapType map_type);
void SetNewScroll(int sx, int sy, int sub);
uint GetRefreshPeriod() const; uint GetRefreshPeriod() const;
uint PausedAdjustRefreshTimeDelta(uint delta_ms) const; uint PausedAdjustRefreshTimeDelta(uint delta_ms) const;
void DrawMapIndicators() const; void DrawMapIndicators() const;
void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const; void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, int y, int end_y, Blitter *blitter) const;
void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const; void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const;
void DrawTowns(const DrawPixelInfo *dpi) const; void DrawTowns(const DrawPixelInfo *dpi) const;
void DrawSmallMap(DrawPixelInfo *dpi, bool draw_indicators = true) const; void DrawSmallMap(DrawPixelInfo *dpi, bool draw_indicators = true) const;
Point RemapTile(int tile_x, int tile_y) const; Point TileToPixel(int tx, int ty) const;
Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const; Point PixelToTile(int px, int py) const;
Point ComputeScroll(int tx, int ty, int x, int y, int *sub);
void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt); void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt);
void SetOverlayCargoMask(); void SetOverlayCargoMask();
void SetupWidgetData(); void SetupWidgetData();