From 9900af38f58c84a90bd1a3830b9acd08438c46c5 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Sun, 1 Dec 2019 23:17:33 +0100 Subject: Fix #7847: Use ViewportSign coordinates for sign Kdtree coordinates (#7849) Ensure the same coordinates are used for station/town/player signs regardless of how the landscape changes below it after the coordinates were first determined. By keeping track of whether each ViewportSign is valid for Kdtree use (and only ever registering the viewport sign when the object is valid) a lot of code can be simplified and become more robust at the same time. --- src/viewport.cpp | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) (limited to 'src/viewport.cpp') diff --git a/src/viewport.cpp b/src/viewport.cpp index 552fb467d..94245cf6c 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2178,13 +2178,9 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id) item.id.station = id; const Station *st = Station::Get(id); - Point pt = RemapCoords(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE, GetTileMaxZ(st->xy) * TILE_HEIGHT); - - pt.y -= 32 * ZOOM_LVL_BASE; - if ((st->facilities & FACIL_AIRPORT) && st->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_LVL_BASE; - - item.center = pt.x; - item.top = pt.y; + assert(st->sign.kdtree_valid); + item.center = st->sign.center; + item.top = st->sign.top; /* Assume the sign can be a candidate for drawing, so measure its width */ _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, st->sign.width_normal); @@ -2199,12 +2195,9 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id) item.id.station = id; const Waypoint *st = Waypoint::Get(id); - Point pt = RemapCoords(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE, GetTileMaxZ(st->xy) * TILE_HEIGHT); - - pt.y -= 32 * ZOOM_LVL_BASE; - - item.center = pt.x; - item.top = pt.y; + assert(st->sign.kdtree_valid); + item.center = st->sign.center; + item.top = st->sign.top; /* Assume the sign can be a candidate for drawing, so measure its width */ _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, st->sign.width_normal); @@ -2219,14 +2212,9 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id) item.id.town = id; const Town *town = Town::Get(id); - /* Avoid using RemapCoords2, it has dependency on the foundations status of the tile, and that can be unavailable during saveload, leading to crashes. - * Instead "fake" foundations by taking the highest Z coordinate of any corner of the tile. */ - Point pt = RemapCoords(TileX(town->xy) * TILE_SIZE, TileY(town->xy) * TILE_SIZE, GetTileMaxZ(town->xy) * TILE_HEIGHT); - - pt.y -= 24 * ZOOM_LVL_BASE; - - item.center = pt.x; - item.top = pt.y; + assert(town->cache.sign.kdtree_valid); + item.center = town->cache.sign.center; + item.top = town->cache.sign.top; /* Assume the sign can be a candidate for drawing, so measure its width */ _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, town->cache.sign.width_normal); @@ -2241,12 +2229,9 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id) item.id.sign = id; const Sign *sign = Sign::Get(id); - Point pt = RemapCoords(sign->x, sign->y, sign->z); - - pt.y -= 6 * ZOOM_LVL_BASE; - - item.center = pt.x; - item.top = pt.y; + assert(sign->sign.kdtree_valid); + item.center = sign->sign.center; + item.top = sign->sign.top; /* Assume the sign can be a candidate for drawing, so measure its width */ _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, sign->sign.width_normal); @@ -2264,22 +2249,22 @@ void RebuildViewportKdtree() const Station *st; FOR_ALL_STATIONS(st) { - items.push_back(ViewportSignKdtreeItem::MakeStation(st->index)); + if (st->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeStation(st->index)); } const Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { - items.push_back(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); + if (wp->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); } const Town *town; FOR_ALL_TOWNS(town) { - items.push_back(ViewportSignKdtreeItem::MakeTown(town->index)); + if (town->cache.sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeTown(town->index)); } const Sign *sign; FOR_ALL_SIGNS(sign) { - items.push_back(ViewportSignKdtreeItem::MakeSign(sign->index)); + if (sign->sign.kdtree_valid) items.push_back(ViewportSignKdtreeItem::MakeSign(sign->index)); } _viewport_sign_kdtree.Build(items.begin(), items.end()); -- cgit v1.2.3-54-g00ecf