diff --git a/src/lang/english.txt b/src/lang/english.txt index 9f0940e699..4244c77792 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -5830,19 +5830,8 @@ STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STR STR_SAVEGAME_NAME_SPECTATOR :Spectator, {1:STRING2} # Viewport strings -STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) -STR_VIEWPORT_TOWN :{WHITE}{TOWN} -STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} -STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} - -STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} -STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} - +STR_VIEWPORT_TOWN_POP :{TOWN} ({COMMA}) STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} -STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} - -STR_VIEWPORT_WAYPOINT :{WAYPOINT} -STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index de9801af76..1fb0b84664 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -450,7 +450,7 @@ void Station::UpdateVirtCoord() SetDParam(0, this->index); SetDParam(1, this->facilities); - this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION, STR_VIEWPORT_STATION_TINY); + this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION, STR_STATION_NAME); _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(this->index)); diff --git a/src/texteff.cpp b/src/texteff.cpp index 43201c4b91..b4e55a30e1 100644 --- a/src/texteff.cpp +++ b/src/texteff.cpp @@ -120,11 +120,19 @@ void DrawTextEffects(DrawPixelInfo *dpi) /* Don't draw the text effects when zoomed out a lot */ if (dpi->zoom > ZOOM_LVL_TEXT_EFFECT) return; if (IsTransparencySet(TO_TEXT)) return; - for (TextEffect &te : _text_effects) { + + ViewportStringFlags flags{}; + if (dpi->zoom >= ZOOM_LVL_TEXT_EFFECT) flags |= ViewportStringFlags::Small; + + for (const TextEffect &te : _text_effects) { if (te.string_id == INVALID_STRING_ID) continue; + if (te.mode == TE_RISING || _settings_client.gui.loading_indicators) { + std::string *str = ViewportAddString(dpi, &te, flags, INVALID_COLOUR); + if (str == nullptr) continue; + CopyInDParam(te.params); - ViewportAddString(dpi, ZOOM_LVL_TEXT_EFFECT, &te, te.string_id, te.string_id, STR_NULL); + *str = GetString(te.string_id); } } } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index b0db2517f0..28259aed75 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -415,8 +415,8 @@ void Town::UpdateVirtCoord() SetDParam(0, this->index); SetDParam(1, this->cache.population); this->cache.sign.UpdatePosition(pt.x, pt.y - 24 * ZOOM_BASE, - _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, - STR_VIEWPORT_TOWN_TINY_WHITE); + _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_TOWN_NAME, + STR_TOWN_NAME); _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeTown(this->index)); diff --git a/src/viewport.cpp b/src/viewport.cpp index 286273319c..341845bee7 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -113,11 +113,11 @@ static const int MAX_TILE_EXTENT_BOTTOM = ZOOM_BASE * (TILE_PIXELS + 2 * TILE_HE struct StringSpriteToDraw { std::string string; - StringID string_id; + uint16_t width; Colours colour; + ViewportStringFlags flags; int32_t x; int32_t y; - uint16_t width; }; struct TileSpriteToDraw { @@ -861,16 +861,26 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran _vd.last_child = child_id; } -static void AddStringToDraw(int x, int y, StringID string, Colours colour, uint16_t width) +/** + * Add a string to draw to a viewport. + * @param x Left position of string. + * @param y Top position of string. + * @param colour Colour of string. + * @param flags ViewportStringFlags to control the string's appearance. + * @param width Width of the string. + * @returns Reference to raw string which should be filled in by the caller. + */ +static std::string &AddStringToDraw(int x, int y, Colours colour, ViewportStringFlags flags, uint16_t width) { assert(width != 0); StringSpriteToDraw &ss = _vd.string_sprites_to_draw.emplace_back(); - ss.string = GetString(string); - ss.string_id = string; + ss.colour = colour; + ss.flags = flags; ss.x = x; ss.y = y; ss.width = width; - ss.colour = colour; + + return ss.string; } @@ -1299,24 +1309,22 @@ static void ViewportAddLandscape() } /** - * Add a string to draw in the viewport + * Add a string to draw in the current viewport. * @param dpi current viewport area * @param small_from Zoomlevel from when the small font should be used * @param sign sign position and dimension - * @param string_normal String for normal and 2x zoom level - * @param string_small String for 4x and 8x zoom level - * @param string_small_shadow Shadow string for 4x and 8x zoom level; or #STR_NULL if no shadow + * @param flags ViewportStringFlags to control the string's appearance. * @param colour colour of the sign background; or INVALID_COLOUR if transparent + * @returns Pointer to std::string to filled with sign, or nullptr if string would be outside the viewport bounds. */ -void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, Colours colour) +std::string *ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sign, ViewportStringFlags flags, Colours colour) { - bool small = dpi->zoom >= small_from; - int left = dpi->left; int top = dpi->top; int right = left + dpi->width; int bottom = top + dpi->height; + bool small = HasFlag(flags, ViewportStringFlags::Small); int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, dpi->zoom); int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom); @@ -1324,19 +1332,10 @@ void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const Vie top > sign->top + sign_height || right < sign->center - sign_half_width || left > sign->center + sign_half_width) { - return; + return nullptr; } - if (!small) { - AddStringToDraw(sign->center - sign_half_width, sign->top, string_normal, colour, sign->width_normal); - } else { - int shadow_offset = 0; - if (string_small_shadow != STR_NULL) { - shadow_offset = 4; - AddStringToDraw(sign->center - sign_half_width + shadow_offset, sign->top, string_small_shadow, INVALID_COLOUR, sign->width_small | 0x8000); - } - AddStringToDraw(sign->center - sign_half_width, sign->top - shadow_offset, string_small, colour, sign->width_small | 0x8000); - } + return &AddStringToDraw(sign->center - sign_half_width, sign->top, colour, flags, small ? sign->width_small : sign->width_normal); } static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom) @@ -1354,6 +1353,80 @@ static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom) return r; } +/** + * Add town strings to a viewport. + * @param dpi Current viewport area. + * @param towns List of towns to add. + * @param small Add small versions of strings. + */ +static void ViewportAddTownStrings(DrawPixelInfo *dpi, const std::vector &towns, bool small) +{ + ViewportStringFlags flags{}; + if (small) flags = ViewportStringFlags::Small | ViewportStringFlags::Shadow; + + StringID stringid = !small && _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_TOWN_NAME; + for (const Town *t : towns) { + std::string *str = ViewportAddString(dpi, &t->cache.sign, flags, INVALID_COLOUR); + if (str == nullptr) continue; + + SetDParam(0, t->index); + SetDParam(1, t->cache.population); + *str = GetString(stringid); + } +} + +/** + * Add sign strings to a viewport. + * @param dpi Current viewport area. + * @param towns List of signs to add. + * @param small Add small versions of strings. + */ +static void ViewportAddSignStrings(DrawPixelInfo *dpi, const std::vector &signs, bool small) +{ + ViewportStringFlags flags{}; + if (small) flags = ViewportStringFlags::Small; + + /* Signs placed by a game script don't have a frame. */ + ViewportStringFlags deity_flags{flags}; + flags |= IsTransparencySet(TO_SIGNS) ? ViewportStringFlags::TransparentRect : ViewportStringFlags::ColourRect; + + for (const Sign *si : signs) { + std::string *str = ViewportAddString(dpi, &si->sign, (si->owner == OWNER_DEITY) ? deity_flags : flags, + (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); + if (str == nullptr) continue; + + SetDParam(0, si->index); + *str = GetString(STR_SIGN_NAME); + } +} + +/** + * Add station strings to a viewport. + * @param dpi Current viewport area. + * @param towns List of stations to add. + * @param small Add small versions of strings. + */ +static void ViewportAddStationStrings(DrawPixelInfo *dpi, const std::vector &stations, bool small) +{ + /* Transparent station signs have colour text instead of a colour panel. */ + ViewportStringFlags flags{IsTransparencySet(TO_SIGNS) ? ViewportStringFlags::TextColour : ViewportStringFlags::ColourRect}; + if (small) flags = ViewportStringFlags::Small; + + for (const BaseStation *st : stations) { + std::string *str = ViewportAddString(dpi, &st->sign, flags, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); + if (str == nullptr) continue; + + if (Station::IsExpected(st)) { /* Station */ + SetDParam(0, st->index); + SetDParam(1, st->facilities); + *str = GetString(small ? STR_STATION_NAME : STR_VIEWPORT_STATION); + } else { /* Waypoint */ + SetDParam(0, st->index); + *str = GetString(STR_WAYPOINT_NAME); + } + } +} + static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi) { Rect search_rect{ dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height }; @@ -1417,42 +1490,17 @@ static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi) } }); - /* Layering order (bottom to top): Town names, signs, stations */ + /* Small versions of signs are used zoom level 4X and higher. */ + bool small = dpi->zoom >= ZOOM_LVL_OUT_4X; - for (const auto *t : towns) { - SetDParam(0, t->index); - SetDParam(1, t->cache.population); - ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &t->cache.sign, - _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, - STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK); - } + /* Layering order (bottom to top): Town names, signs, stations */ + ViewportAddTownStrings(dpi, towns, small); /* Do not draw signs nor station names if they are set invisible */ if (IsInvisibilitySet(TO_SIGNS)) return; - for (const auto *si : signs) { - SetDParam(0, si->index); - ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &si->sign, - STR_WHITE_SIGN, - (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL, - (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); - } - - for (const auto *st : stations) { - SetDParam(0, st->index); - SetDParam(1, st->facilities); - if (Station::IsExpected(st)) { - /* Station */ - ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &st->sign, - STR_VIEWPORT_STATION, STR_VIEWPORT_STATION_TINY, STR_NULL, - (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); - } else { - /* Waypoint */ - ViewportAddString(dpi, ZOOM_LVL_OUT_4X, &st->sign, - STR_VIEWPORT_WAYPOINT, STR_VIEWPORT_WAYPOINT_TINY, STR_NULL, - (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); - } - } + ViewportAddSignStrings(dpi, signs, small); + ViewportAddStationStrings(dpi, stations, small); } @@ -1710,30 +1758,36 @@ static void ViewportDrawDirtyBlocks() static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv) { for (const StringSpriteToDraw &ss : *sstdv) { - TextColour colour = TC_BLACK; - bool small = HasBit(ss.width, 15); - int w = GB(ss.width, 0, 15); + bool small = HasFlag(ss.flags, ViewportStringFlags::Small); + int w = ss.width; int x = UnScaleByZoom(ss.x, zoom); int y = UnScaleByZoom(ss.y, zoom); int h = WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom; - if (ss.colour != INVALID_COLOUR) { - if (IsTransparencySet(TO_SIGNS) && ss.string_id != STR_WHITE_SIGN) { - /* Don't draw the rectangle. - * Real colours need the TC_IS_PALETTE_COLOUR flag. - * Otherwise colours from _string_colourmap are assumed. */ - colour = (TextColour)GetColourGradient(ss.colour, SHADE_LIGHTER) | TC_IS_PALETTE_COLOUR; - } else { - /* Draw the rectangle if 'transparent station signs' is off, - * or if we are drawing a general text sign (STR_WHITE_SIGN). */ - DrawFrameRect( - x, y, x + w - 1, y + h - 1, ss.colour, - IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE - ); - } + TextColour colour = TC_WHITE; + if (HasFlag(ss.flags, ViewportStringFlags::ColourRect)) { + if (ss.colour != INVALID_COLOUR) DrawFrameRect(x, y, x + w - 1, y + h - 1, ss.colour, FR_NONE); + colour = TC_BLACK; + } else if (HasFlag(ss.flags, ViewportStringFlags::TransparentRect)) { + DrawFrameRect(x, y, x + w - 1, y + h - 1, ss.colour, FR_TRANSPARENT); } - DrawString(x + WidgetDimensions::scaled.fullbevel.left, x + w - 1 - WidgetDimensions::scaled.fullbevel.right, y + WidgetDimensions::scaled.fullbevel.top, ss.string, colour, SA_HOR_CENTER, false, small ? FS_SMALL : FS_NORMAL); + if (HasFlag(ss.flags, ViewportStringFlags::TextColour)) { + if (ss.colour != INVALID_COLOUR) colour = static_cast(GetColourGradient(ss.colour, SHADE_LIGHTER) | TC_IS_PALETTE_COLOUR); + } + + int left = x + WidgetDimensions::scaled.fullbevel.left; + int right = x + w - 1 - WidgetDimensions::scaled.fullbevel.right; + int top = y + WidgetDimensions::scaled.fullbevel.top; + + int shadow_offset = 0; + if (small && HasFlag(ss.flags, ViewportStringFlags::Shadow)) { + /* Shadow needs to be shifted 1 pixel. */ + shadow_offset = WidgetDimensions::scaled.fullbevel.top; + DrawString(left + shadow_offset, right + shadow_offset, top, ss.string, TC_BLACK, SA_HOR_CENTER, false, FS_SMALL); + } + + DrawString(left, right, top - shadow_offset, ss.string, colour, SA_HOR_CENTER, false, small ? FS_SMALL : FS_NORMAL); } } diff --git a/src/viewport_func.h b/src/viewport_func.h index 5b1537478c..1da098c4a9 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -54,7 +54,7 @@ void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = null void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32_t x, int32_t y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0); void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = nullptr); void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = nullptr, bool scale = true, bool relative = true); -void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, Colours colour = INVALID_COLOUR); +std::string *ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sign, ViewportStringFlags flags, Colours colour); void StartSpriteCombine(); diff --git a/src/viewport_type.h b/src/viewport_type.h index 0fde051f38..1a67197759 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -10,12 +10,23 @@ #ifndef VIEWPORT_TYPE_H #define VIEWPORT_TYPE_H +#include "core/enum_type.hpp" #include "zoom_type.h" #include "strings_type.h" #include "table/strings.h" class LinkGraphOverlay; +/** Flags to control how Viewport Strings are rendered. */ +enum class ViewportStringFlags : uint8_t { + Small = (1U << 0), ///< Draw using the small font. + Shadow = (1U << 1), ///< Draw an extra text shadow. Should only be used with ViewportStringFlags::Small, as normal font already has a shadow. + ColourRect = (1U << 2), ///< Draw a colour rect around the sign. + TransparentRect = (1U << 3), ///< Draw a transparent rect around the sign. + TextColour = (1U << 4), ///< Draw text in colour. +}; +DECLARE_ENUM_AS_BIT_SET(ViewportStringFlags) + /** * Data structure for viewport, display of a part of the world */ diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp index 668cffa10d..fe760dbb45 100644 --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -45,7 +45,7 @@ void Waypoint::UpdateVirtCoord() if (this->sign.kdtree_valid) _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeWaypoint(this->index)); SetDParam(0, this->index); - this->sign.UpdatePosition(pt.x, pt.y - 32 * ZOOM_BASE, STR_VIEWPORT_WAYPOINT); + this->sign.UpdatePosition(pt.x, pt.y - 32 * ZOOM_BASE, STR_WAYPOINT_NAME); _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeWaypoint(this->index));