Merge remote-tracking branch 'upstream/master'
This commit is contained in:
312
src/viewport.cpp
312
src/viewport.cpp
@@ -90,7 +90,9 @@
|
||||
#include "framerate_type.h"
|
||||
#include "build_confirmation_func.h"
|
||||
|
||||
#include <forward_list>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/string_colours.h"
|
||||
@@ -178,7 +180,7 @@ struct ViewportDrawer {
|
||||
Point foundation_offset[FOUNDATION_PART_END]; ///< Pixel offset for ground sprites on the foundations.
|
||||
};
|
||||
|
||||
static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom);
|
||||
static bool MarkViewportDirty(const Viewport *vp, int left, int top, int right, int bottom);
|
||||
|
||||
static ViewportDrawer _vd;
|
||||
|
||||
@@ -189,7 +191,7 @@ bool _draw_dirty_blocks = false;
|
||||
uint _dirty_block_colour = 0;
|
||||
static VpSpriteSorter _vp_sprite_sorter = nullptr;
|
||||
|
||||
static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z)
|
||||
static Point MapXYZToViewport(const Viewport *vp, int x, int y, int z)
|
||||
{
|
||||
Point p = RemapCoords(x, y, z);
|
||||
p.x -= vp->virtual_width / 2;
|
||||
@@ -332,7 +334,7 @@ static void DoSetViewportPosition(const Window *w, int left, int top, int width,
|
||||
|
||||
static void SetViewportPosition(Window *w, int x, int y)
|
||||
{
|
||||
ViewPort *vp = w->viewport;
|
||||
Viewport *vp = w->viewport;
|
||||
int old_left = vp->virtual_left;
|
||||
int old_top = vp->virtual_top;
|
||||
int i;
|
||||
@@ -391,9 +393,9 @@ static void SetViewportPosition(Window *w, int x, int y)
|
||||
* @return Pointer to the viewport if the xy position is in the viewport of the window,
|
||||
* otherwise \c nullptr is returned.
|
||||
*/
|
||||
ViewPort *IsPtInWindowViewport(const Window *w, int x, int y)
|
||||
Viewport *IsPtInWindowViewport(const Window *w, int x, int y)
|
||||
{
|
||||
ViewPort *vp = w->viewport;
|
||||
Viewport *vp = w->viewport;
|
||||
|
||||
if (vp != nullptr &&
|
||||
IsInsideMM(x, vp->left, vp->left + vp->width) &&
|
||||
@@ -415,7 +417,7 @@ ViewPort *IsPtInWindowViewport(const Window *w, int x, int y)
|
||||
* @param clamp_to_map Clamp the coordinate outside of the map to the closest, non-void tile within the map
|
||||
* @return Tile coordinate or (-1, -1) if given x or y is not within viewport frame
|
||||
*/
|
||||
Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y, bool clamp_to_map)
|
||||
Point TranslateXYToTileCoord(const Viewport *vp, int x, int y, bool clamp_to_map)
|
||||
{
|
||||
if (!IsInsideBS(x, vp->left, vp->width) || !IsInsideBS(y, vp->top, vp->height)) {
|
||||
Point pt = { -1, -1 };
|
||||
@@ -433,7 +435,7 @@ Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y, bool clamp_to_map
|
||||
static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y)
|
||||
{
|
||||
Window *w;
|
||||
ViewPort *vp;
|
||||
Viewport *vp;
|
||||
Point pt;
|
||||
|
||||
if ( (w = FindWindowFromPt(x, y)) != nullptr &&
|
||||
@@ -453,7 +455,7 @@ Point GetTileBelowCursor()
|
||||
Point GetTileZoomCenterWindow(bool in, Window * w)
|
||||
{
|
||||
int x, y;
|
||||
ViewPort *vp = w->viewport;
|
||||
Viewport *vp = w->viewport;
|
||||
|
||||
if (in) {
|
||||
x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2);
|
||||
@@ -474,7 +476,7 @@ Point GetTileZoomCenterWindow(bool in, Window * w)
|
||||
* @param widget_zoom_in widget index for window with zoom-in button
|
||||
* @param widget_zoom_out widget index for window with zoom-out button
|
||||
*/
|
||||
void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out)
|
||||
void HandleZoomMessage(Window *w, const Viewport *vp, byte widget_zoom_in, byte widget_zoom_out)
|
||||
{
|
||||
w->SetWidgetDisabledState(widget_zoom_in, vp->zoom <= _settings_client.gui.zoom_min);
|
||||
w->SetWidgetDirty(widget_zoom_in);
|
||||
@@ -499,8 +501,7 @@ static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y,
|
||||
{
|
||||
assert((image & SPRITE_MASK) < MAX_SPRITES);
|
||||
|
||||
/*C++17: TileSpriteToDraw &ts = */ _vd.tile_sprites_to_draw.emplace_back();
|
||||
TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.back();
|
||||
TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.emplace_back();
|
||||
ts.image = image;
|
||||
ts.pal = pal;
|
||||
ts.sub = sub;
|
||||
@@ -695,10 +696,10 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
|
||||
|
||||
if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
|
||||
/* Compute maximal extents of sprite and its bounding box */
|
||||
left = min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
|
||||
right = max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
|
||||
top = min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
|
||||
bottom = max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
|
||||
left = std::min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
|
||||
right = std::max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
|
||||
top = std::min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
|
||||
bottom = std::max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
|
||||
}
|
||||
|
||||
/* Do not add the sprite to the viewport, if it is outside */
|
||||
@@ -709,8 +710,7 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
|
||||
return;
|
||||
}
|
||||
|
||||
/*C++17: ParentSpriteToDraw &ps = */ _vd.parent_sprites_to_draw.emplace_back();
|
||||
ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.back();
|
||||
ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.emplace_back();
|
||||
ps.x = tmp_x;
|
||||
ps.y = tmp_y;
|
||||
|
||||
@@ -721,15 +721,14 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
|
||||
ps.pal = pal;
|
||||
ps.sub = sub;
|
||||
ps.xmin = x + bb_offset_x;
|
||||
ps.xmax = x + max(bb_offset_x, w) - 1;
|
||||
ps.xmax = x + std::max(bb_offset_x, w) - 1;
|
||||
|
||||
ps.ymin = y + bb_offset_y;
|
||||
ps.ymax = y + max(bb_offset_y, h) - 1;
|
||||
ps.ymax = y + std::max(bb_offset_y, h) - 1;
|
||||
|
||||
ps.zmin = z + bb_offset_z;
|
||||
ps.zmax = z + max(bb_offset_z, dz) - 1;
|
||||
ps.zmax = z + std::max(bb_offset_z, dz) - 1;
|
||||
|
||||
ps.comparison_done = false;
|
||||
ps.first_child = -1;
|
||||
|
||||
_vd.last_child = &ps.first_child;
|
||||
@@ -828,8 +827,7 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran
|
||||
|
||||
*_vd.last_child = (uint)_vd.child_screen_sprites_to_draw.size();
|
||||
|
||||
/*C++17: ChildScreenSpriteToDraw &cs = */ _vd.child_screen_sprites_to_draw.emplace_back();
|
||||
ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.back();
|
||||
ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.emplace_back();
|
||||
cs.image = image;
|
||||
cs.pal = pal;
|
||||
cs.sub = sub;
|
||||
@@ -848,8 +846,7 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran
|
||||
static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width)
|
||||
{
|
||||
assert(width != 0);
|
||||
/*C++17: StringSpriteToDraw &ss = */ _vd.string_sprites_to_draw.emplace_back();
|
||||
StringSpriteToDraw &ss = _vd.string_sprites_to_draw.back();
|
||||
StringSpriteToDraw &ss = _vd.string_sprites_to_draw.emplace_back();
|
||||
ss.string = string;
|
||||
ss.x = x;
|
||||
ss.y = y;
|
||||
@@ -1481,7 +1478,7 @@ void ViewportSign::MarkDirty(ZoomLevel maxzoom) const
|
||||
|
||||
Window *w;
|
||||
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
||||
ViewPort *vp = w->viewport;
|
||||
Viewport *vp = w->viewport;
|
||||
if (vp != nullptr && vp->zoom <= maxzoom) {
|
||||
assert(vp->width != 0);
|
||||
Rect &zl = zoomlevels[vp->zoom];
|
||||
@@ -1503,64 +1500,127 @@ static bool ViewportSortParentSpritesChecker()
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sort parent sprites pointer array */
|
||||
/** Sort parent sprites pointer array replicating the way original sorter did it. */
|
||||
static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
|
||||
{
|
||||
auto psdvend = psdv->end();
|
||||
auto psd = psdv->begin();
|
||||
while (psd != psdvend) {
|
||||
ParentSpriteToDraw *ps = *psd;
|
||||
if (psdv->size() < 2) return;
|
||||
|
||||
if (ps->comparison_done) {
|
||||
psd++;
|
||||
/* We rely on sprites being, for the most part, already ordered.
|
||||
* So we don't need to move many of them and can keep track of their
|
||||
* order efficiently by using stack. We always move sprites to the front
|
||||
* of the current position, i.e. to the top of the stack.
|
||||
* Also use special constants to indicate sorting state without
|
||||
* adding extra fields to ParentSpriteToDraw structure.
|
||||
*/
|
||||
const uint32 ORDER_COMPARED = UINT32_MAX; // Sprite was compared but we still need to compare the ones preceding it
|
||||
const uint32 ORDER_RETURNED = UINT32_MAX - 1; // Makr sorted sprite in case there are other occurrences of it in the stack
|
||||
std::stack<ParentSpriteToDraw *> sprite_order;
|
||||
uint32 next_order = 0;
|
||||
|
||||
std::forward_list<std::pair<int64, ParentSpriteToDraw *>> sprite_list; // We store sprites in a list sorted by xmin+ymin
|
||||
|
||||
/* Initialize sprite list and order. */
|
||||
for (auto p = psdv->rbegin(); p != psdv->rend(); p++) {
|
||||
sprite_list.push_front(std::make_pair((*p)->xmin + (*p)->ymin, *p));
|
||||
sprite_order.push(*p);
|
||||
(*p)->order = next_order++;
|
||||
}
|
||||
|
||||
sprite_list.sort();
|
||||
|
||||
std::vector<ParentSpriteToDraw*> preceding; // Temporarily stores sprites that precede current and their position in the list
|
||||
auto preceding_prev = sprite_list.begin(); // Store iterator in case we need to delete a single preciding sprite
|
||||
auto out = psdv->begin(); // Iterator to output sorted sprites
|
||||
|
||||
while (!sprite_order.empty()) {
|
||||
|
||||
auto s = sprite_order.top();
|
||||
sprite_order.pop();
|
||||
|
||||
/* Sprite is already sorted, ignore it. */
|
||||
if (s->order == ORDER_RETURNED) continue;
|
||||
|
||||
/* Sprite was already compared, just need to output it. */
|
||||
if (s->order == ORDER_COMPARED) {
|
||||
*(out++) = s;
|
||||
s->order = ORDER_RETURNED;
|
||||
continue;
|
||||
}
|
||||
|
||||
ps->comparison_done = true;
|
||||
preceding.clear();
|
||||
|
||||
for (auto psd2 = psd + 1; psd2 != psdvend; psd2++) {
|
||||
ParentSpriteToDraw *ps2 = *psd2;
|
||||
/* We only need sprites with xmin <= s->xmax && ymin <= s->ymax && zmin <= s->zmax
|
||||
* So by iterating sprites with xmin + ymin <= s->xmax + s->ymax
|
||||
* we get all we need and some more that we filter out later.
|
||||
* We don't include zmin into the sum as there are usually more neighbors on x and y than z
|
||||
* so including it will actually increase the amount of false positives.
|
||||
* Also min coordinates can be > max so using max(xmin, xmax) + max(ymin, ymax)
|
||||
* to ensure that we iterate the current sprite as we need to remove it from the list.
|
||||
*/
|
||||
auto ssum = std::max(s->xmax, s->xmin) + std::max(s->ymax, s->ymin);
|
||||
auto prev = sprite_list.before_begin();
|
||||
auto x = sprite_list.begin();
|
||||
while (x != sprite_list.end() && ((*x).first <= ssum)) {
|
||||
auto p = (*x).second;
|
||||
if (p == s) {
|
||||
/* We found the current sprite, remove it and move on. */
|
||||
x = sprite_list.erase_after(prev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ps2->comparison_done) continue;
|
||||
auto p_prev = prev;
|
||||
prev = x++;
|
||||
|
||||
/* Decide which comparator to use, based on whether the bounding
|
||||
* boxes overlap
|
||||
*/
|
||||
if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X?
|
||||
ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y?
|
||||
ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z?
|
||||
/* Use X+Y+Z as the sorting order, so sprites closer to the bottom of
|
||||
* the screen and with higher Z elevation, are drawn in front.
|
||||
* Here X,Y,Z are the coordinates of the "center of mass" of the sprite,
|
||||
* i.e. X=(left+right)/2, etc.
|
||||
* However, since we only care about order, don't actually divide / 2
|
||||
*/
|
||||
if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <=
|
||||
ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* We only change the order, if it is definite.
|
||||
* I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap.
|
||||
* That is: If one partial order says ps behind ps2, do not change the order.
|
||||
*/
|
||||
if (ps->xmax < ps2->xmin ||
|
||||
ps->ymax < ps2->ymin ||
|
||||
ps->zmax < ps2->zmin) {
|
||||
if (s->xmax < p->xmin || s->ymax < p->ymin || s->zmax < p->zmin) continue;
|
||||
if (s->xmin <= p->xmax && // overlap in X?
|
||||
s->ymin <= p->ymax && // overlap in Y?
|
||||
s->zmin <= p->zmax) { // overlap in Z?
|
||||
if (s->xmin + s->xmax + s->ymin + s->ymax + s->zmin + s->zmax <=
|
||||
p->xmin + p->xmax + p->ymin + p->ymax + p->zmin + p->zmax) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
preceding.push_back(p);
|
||||
preceding_prev = p_prev;
|
||||
}
|
||||
|
||||
/* Move ps2 in front of ps */
|
||||
ParentSpriteToDraw *temp = ps2;
|
||||
for (auto psd3 = psd2; psd3 > psd; psd3--) {
|
||||
*psd3 = *(psd3 - 1);
|
||||
if (preceding.empty()) {
|
||||
/* No preceding sprites, add current one to the output */
|
||||
*(out++) = s;
|
||||
s->order = ORDER_RETURNED;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Optimization for the case when we only have 1 sprite to move. */
|
||||
if (preceding.size() == 1) {
|
||||
auto p = preceding[0];
|
||||
/* We can only output the preceding sprite if there can't be any other sprites preceding it. */
|
||||
if (p->xmax <= s->xmax && p->ymax <= s->ymax && p->zmax <= s->zmax) {
|
||||
p->order = ORDER_RETURNED;
|
||||
s->order = ORDER_RETURNED;
|
||||
sprite_list.erase_after(preceding_prev);
|
||||
*(out++) = p;
|
||||
*(out++) = s;
|
||||
continue;
|
||||
}
|
||||
*psd = temp;
|
||||
}
|
||||
|
||||
/* Sort all preceding sprites by order and assign new orders in reverse (as original sorter did). */
|
||||
std::sort(preceding.begin(), preceding.end(), [](const ParentSpriteToDraw *a, const ParentSpriteToDraw *b) {
|
||||
return a->order > b->order;
|
||||
});
|
||||
|
||||
s->order = ORDER_COMPARED;
|
||||
sprite_order.push(s); // Still need to output so push it back for now
|
||||
|
||||
for (auto p: preceding) {
|
||||
p->order = next_order++;
|
||||
sprite_order.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv)
|
||||
{
|
||||
for (const ParentSpriteToDraw *ps : *psd) {
|
||||
@@ -1652,7 +1712,7 @@ static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
void ViewportDoDraw(const Viewport *vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
DrawPixelInfo *old_dpi = _cur_dpi;
|
||||
_cur_dpi = &_vd.dpi;
|
||||
@@ -1723,33 +1783,7 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom
|
||||
_vd.child_screen_sprites_to_draw.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we don't draw a too big area at a time.
|
||||
* If we do, the sprite memory will overflow.
|
||||
*/
|
||||
static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
if ((int64)ScaleByZoom(bottom - top, vp->zoom) * (int64)ScaleByZoom(right - left, vp->zoom) > (int64)(180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE)) {
|
||||
if ((bottom - top) > (right - left)) {
|
||||
int t = (top + bottom) >> 1;
|
||||
ViewportDrawChk(vp, left, top, right, t);
|
||||
ViewportDrawChk(vp, left, t, right, bottom);
|
||||
} else {
|
||||
int t = (left + right) >> 1;
|
||||
ViewportDrawChk(vp, left, top, t, bottom);
|
||||
ViewportDrawChk(vp, t, top, right, bottom);
|
||||
}
|
||||
} else {
|
||||
ViewportDoDraw(vp,
|
||||
ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
|
||||
ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top,
|
||||
ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left,
|
||||
ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
static inline void ViewportDraw(const Viewport *vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
if (right <= vp->left || bottom <= vp->top) return;
|
||||
|
||||
@@ -1763,7 +1797,12 @@ static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right
|
||||
if (top < vp->top) top = vp->top;
|
||||
if (bottom > vp->top + vp->height) bottom = vp->top + vp->height;
|
||||
|
||||
ViewportDrawChk(vp, left, top, right, bottom);
|
||||
ViewportDoDraw(vp,
|
||||
ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
|
||||
ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top,
|
||||
ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left,
|
||||
ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1794,7 +1833,7 @@ void Window::DrawViewport() const
|
||||
* @param[in,out] scroll_x Viewport X scroll.
|
||||
* @param[in,out] scroll_y Viewport Y scroll.
|
||||
*/
|
||||
static inline void ClampViewportToMap(const ViewPort *vp, int *scroll_x, int *scroll_y)
|
||||
static inline void ClampViewportToMap(const Viewport *vp, int *scroll_x, int *scroll_y)
|
||||
{
|
||||
/* Centre of the viewport is hot spot. */
|
||||
Point pt = {
|
||||
@@ -1820,7 +1859,7 @@ static inline void ClampViewportToMap(const ViewPort *vp, int *scroll_x, int *sc
|
||||
*/
|
||||
void UpdateViewportPosition(Window *w)
|
||||
{
|
||||
const ViewPort *vp = w->viewport;
|
||||
const Viewport *vp = w->viewport;
|
||||
|
||||
if (w->viewport->follow_vehicle != INVALID_VEHICLE) {
|
||||
const Vehicle *veh = Vehicle::Get(w->viewport->follow_vehicle);
|
||||
@@ -1865,34 +1904,37 @@ void UpdateViewportPosition(Window *w)
|
||||
* @param top Top edge of area to repaint
|
||||
* @param right Right edge of area to repaint
|
||||
* @param bottom Bottom edge of area to repaint
|
||||
* @return true if the viewport contains a dirty block
|
||||
* @ingroup dirty
|
||||
*/
|
||||
static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
static bool MarkViewportDirty(const Viewport *vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
/* Rounding wrt. zoom-out level */
|
||||
right += (1 << vp->zoom) - 1;
|
||||
bottom += (1 << vp->zoom) - 1;
|
||||
|
||||
right -= vp->virtual_left;
|
||||
if (right <= 0) return;
|
||||
if (right <= 0) return false;
|
||||
|
||||
bottom -= vp->virtual_top;
|
||||
if (bottom <= 0) return;
|
||||
if (bottom <= 0) return false;
|
||||
|
||||
left = max(0, left - vp->virtual_left);
|
||||
left = std::max(0, left - vp->virtual_left);
|
||||
|
||||
if (left >= vp->virtual_width) return;
|
||||
if (left >= vp->virtual_width) return false;
|
||||
|
||||
top = max(0, top - vp->virtual_top);
|
||||
top = std::max(0, top - vp->virtual_top);
|
||||
|
||||
if (top >= vp->virtual_height) return;
|
||||
if (top >= vp->virtual_height) return false;
|
||||
|
||||
SetDirtyBlocks(
|
||||
AddDirtyBlock(
|
||||
UnScaleByZoomLower(left, vp->zoom) + vp->left,
|
||||
UnScaleByZoomLower(top, vp->zoom) + vp->top,
|
||||
UnScaleByZoom(right, vp->zoom) + vp->left + 1,
|
||||
UnScaleByZoom(bottom, vp->zoom) + vp->top + 1
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1901,18 +1943,23 @@ static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right,
|
||||
* @param top Top edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL)
|
||||
* @param right Right edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL)
|
||||
* @param bottom Bottom edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL)
|
||||
* @return true if at least one viewport has a dirty block
|
||||
* @ingroup dirty
|
||||
*/
|
||||
void MarkAllViewportsDirty(int left, int top, int right, int bottom)
|
||||
bool MarkAllViewportsDirty(int left, int top, int right, int bottom)
|
||||
{
|
||||
bool dirty = false;
|
||||
|
||||
Window *w;
|
||||
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
||||
ViewPort *vp = w->viewport;
|
||||
Viewport *vp = w->viewport;
|
||||
if (vp != nullptr) {
|
||||
assert(vp->width != 0);
|
||||
MarkViewportDirty(vp, left, top, right, bottom);
|
||||
if (MarkViewportDirty(vp, left, top, right, bottom)) dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
void ConstrainAllViewportsZoom()
|
||||
@@ -2078,7 +2125,7 @@ void SetSelectionRed(bool b)
|
||||
* @param sign the sign to check
|
||||
* @return true if the sign was hit
|
||||
*/
|
||||
static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign)
|
||||
static bool CheckClickOnViewportSign(const Viewport *vp, int x, int y, const ViewportSign *sign)
|
||||
{
|
||||
bool small = (vp->zoom >= ZOOM_LVL_OUT_16X);
|
||||
int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom);
|
||||
@@ -2096,7 +2143,7 @@ static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const Vie
|
||||
* @param y Y position of click
|
||||
* @return true if the sign was hit
|
||||
*/
|
||||
static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y)
|
||||
static bool CheckClickOnViewportSign(const Viewport *vp, int x, int y)
|
||||
{
|
||||
if (_game_mode == GM_MENU) return false;
|
||||
|
||||
@@ -2184,7 +2231,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id)
|
||||
item.top = st->sign.top;
|
||||
|
||||
/* Assume the sign can be a candidate for drawing, so measure its width */
|
||||
_viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, st->sign.width_normal);
|
||||
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, st->sign.width_normal);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -2201,7 +2248,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id)
|
||||
item.top = st->sign.top;
|
||||
|
||||
/* Assume the sign can be a candidate for drawing, so measure its width */
|
||||
_viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, st->sign.width_normal);
|
||||
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, st->sign.width_normal);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -2218,7 +2265,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id)
|
||||
item.top = town->cache.sign.top;
|
||||
|
||||
/* Assume the sign can be a candidate for drawing, so measure its width */
|
||||
_viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, town->cache.sign.width_normal);
|
||||
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, town->cache.sign.width_normal);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -2235,7 +2282,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id)
|
||||
item.top = sign->sign.top;
|
||||
|
||||
/* Assume the sign can be a candidate for drawing, so measure its width */
|
||||
_viewport_sign_maxwidth = max<int>(_viewport_sign_maxwidth, sign->sign.width_normal);
|
||||
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, sign->sign.width_normal);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -2268,7 +2315,7 @@ void RebuildViewportKdtree()
|
||||
}
|
||||
|
||||
|
||||
static bool CheckClickOnLandscape(const ViewPort *vp, int x, int y)
|
||||
static bool CheckClickOnLandscape(const Viewport *vp, int x, int y)
|
||||
{
|
||||
Point pt = TranslateXYToTileCoord(vp, x, y);
|
||||
|
||||
@@ -2299,7 +2346,7 @@ static void PlaceObject()
|
||||
}
|
||||
|
||||
|
||||
bool HandleViewportClicked(const ViewPort *vp, int x, int y)
|
||||
bool HandleViewportClicked(const Viewport *vp, int x, int y)
|
||||
{
|
||||
if (_move_pressed) return false;
|
||||
|
||||
@@ -2660,6 +2707,18 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag
|
||||
_special_mouse_mode = WSM_SIZING;
|
||||
}
|
||||
|
||||
/** Drag over the map while holding the left mouse down. */
|
||||
void VpStartDragging(ViewportDragDropSelectionProcess process)
|
||||
{
|
||||
_thd.select_method = VPM_X_AND_Y;
|
||||
_thd.select_proc = process;
|
||||
_thd.selstart.x = 0;
|
||||
_thd.selstart.y = 0;
|
||||
_thd.next_drawstyle = HT_RECT;
|
||||
|
||||
_special_mouse_mode = WSM_DRAGGING;
|
||||
}
|
||||
|
||||
void VpSetPlaceSizingLimit(int limit)
|
||||
{
|
||||
_thd.sizelimit = limit;
|
||||
@@ -2831,7 +2890,7 @@ static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_t
|
||||
assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
|
||||
h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t])));
|
||||
uint ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1])));
|
||||
h0 = max(h0, ht);
|
||||
h0 = std::max(h0, ht);
|
||||
|
||||
/* Use lookup table for end-tile based on HighLightStyle direction
|
||||
* flip around side (lower/upper, left/right) based on distance */
|
||||
@@ -2839,7 +2898,7 @@ static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_t
|
||||
assert(style_t < lengthof(heightdiff_line_by_dir) - 13);
|
||||
h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t])));
|
||||
ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1])));
|
||||
h1 = max(h1, ht);
|
||||
h1 = std::max(h1, ht);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3274,7 +3333,7 @@ calc_heightdiff_single_direction:;
|
||||
*/
|
||||
EventState VpHandlePlaceSizingDrag()
|
||||
{
|
||||
if (_special_mouse_mode != WSM_SIZING) return ES_NOT_HANDLED;
|
||||
if (_special_mouse_mode != WSM_SIZING && _special_mouse_mode != WSM_DRAGGING) return ES_NOT_HANDLED;
|
||||
|
||||
/* stop drag mode if the window has been closed */
|
||||
Window *w = _thd.GetCallbackWnd();
|
||||
@@ -3286,15 +3345,24 @@ EventState VpHandlePlaceSizingDrag()
|
||||
/* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
|
||||
if (_left_button_down) {
|
||||
HideBuildConfirmationWindow();
|
||||
if (_special_mouse_mode == WSM_DRAGGING) {
|
||||
/* Only register a drag event when the mouse moved. */
|
||||
if (_thd.new_pos.x == _thd.selstart.x && _thd.new_pos.y == _thd.selstart.y) return ES_HANDLED;
|
||||
_thd.selstart.x = _thd.new_pos.x;
|
||||
_thd.selstart.y = _thd.new_pos.y;
|
||||
}
|
||||
|
||||
w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
ShowBuildConfirmationWindow(); // This will also remember tile selection, so it's okay for the code below to change selection
|
||||
|
||||
/* mouse button released..
|
||||
* keep the selected tool, but reset it to the original mode. */
|
||||
/* Mouse button released. */
|
||||
_special_mouse_mode = WSM_NONE;
|
||||
if (_special_mouse_mode == WSM_DRAGGING) return ES_HANDLED;
|
||||
|
||||
/* Keep the selected tool, but reset it to the original mode. */
|
||||
HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK);
|
||||
if (_thd.select_method == VPM_SINGLE_TILE) {
|
||||
goto place_mouseup;
|
||||
@@ -3419,7 +3487,7 @@ void ToolbarSelectLastTool()
|
||||
_last_selected_window_class = WC_INVALID;
|
||||
}
|
||||
|
||||
Point GetViewportStationMiddle(const ViewPort *vp, const Station *st)
|
||||
Point GetViewportStationMiddle(const Viewport *vp, const Station *st)
|
||||
{
|
||||
int x = TileX(st->xy) * TILE_SIZE;
|
||||
int y = TileY(st->xy) * TILE_SIZE;
|
||||
|
||||
Reference in New Issue
Block a user