/***************************************************************************** * Copyright (c) 2014-2018 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #include "../config/Config.h" #include "../interface/Colour.h" #include "../localisation/Localisation.h" #include "../localisation/LocalisationService.h" #include "../paint/Paint.h" #include "../sprites.h" #include "Drawing.h" #include "TTF.h" #include #pragma pack(push, 1) /* size: 0xA12 */ struct rct_draw_scroll_text { rct_string_id string_id; // 0x00 uint32_t string_args_0; // 0x02 uint32_t string_args_1; // 0x06 uint16_t position; // 0x0A uint16_t mode; // 0x0C uint32_t id; // 0x0E uint8_t bitmap[64 * 40]; // 0x12 }; assert_struct_size(rct_draw_scroll_text, 0xA12); #pragma pack(pop) #define MAX_SCROLLING_TEXT_ENTRIES 32 static rct_draw_scroll_text _drawScrollTextList[MAX_SCROLLING_TEXT_ENTRIES]; static uint8_t _characterBitmaps[FONT_SPRITE_GLYPH_COUNT + SPR_G2_GLYPH_COUNT][8]; static uint32_t _drawSCrollNextIndex = 0; static void scrolling_text_set_bitmap_for_sprite(utf8* text, int32_t scroll, uint8_t* bitmap, const int16_t* scrollPositionOffsets); static void scrolling_text_set_bitmap_for_ttf(utf8* text, int32_t scroll, uint8_t* bitmap, const int16_t* scrollPositionOffsets); void scrolling_text_initialise_bitmaps() { uint8_t drawingSurface[64]; rct_drawpixelinfo dpi = { /* .bits = */ (uint8_t*)&drawingSurface, /* .x = */ 0, /* .y = */ 0, /* .width = */ 8, /* .height = */ 8, /* .pitch = */ 0, /* .zoom_level = */ 0, }; for (int32_t i = 0; i < FONT_SPRITE_GLYPH_COUNT; i++) { memset(drawingSurface, 0, sizeof(drawingSurface)); gfx_draw_sprite_software(&dpi, SPR_CHAR_START + FONT_SPRITE_BASE_TINY + i, -1, 0, 0); for (int32_t x = 0; x < 8; x++) { uint8_t val = 0; for (int32_t y = 0; y < 8; y++) { val >>= 1; uint8_t pixel = dpi.bits[x + y * 8]; if (pixel == 1 || (gTinyFontAntiAliased && pixel == 2)) { val |= 0x80; } } _characterBitmaps[i][x] = val; } } for (int32_t i = 0; i < SPR_G2_GLYPH_COUNT; i++) { memset(drawingSurface, 0, sizeof(drawingSurface)); gfx_draw_sprite_software(&dpi, SPR_G2_CHAR_BEGIN + (FONT_SIZE_TINY * SPR_G2_GLYPH_COUNT) + i, -1, 0, 0); for (int32_t x = 0; x < 8; x++) { uint8_t val = 0; for (int32_t y = 0; y < 8; y++) { val >>= 1; uint8_t pixel = dpi.bits[x + y * 8]; if (pixel == 1 || (gTinyFontAntiAliased && pixel == 2)) { val |= 0x80; } } _characterBitmaps[FONT_SPRITE_GLYPH_COUNT + i][x] = val; } } for (int32_t i = 0; i < MAX_SCROLLING_TEXT_ENTRIES; i++) { int32_t imageId = SPR_SCROLLING_TEXT_START + i; const rct_g1_element* g1original = gfx_get_g1_element(imageId); if (g1original != nullptr) { rct_g1_element g1 = *g1original; g1.offset = _drawScrollTextList[i].bitmap; g1.width = 64; g1.height = 40; g1.offset[0] = 0xFF; g1.offset[1] = 0xFF; g1.offset[14] = 0; g1.offset[15] = 0; g1.offset[16] = 0; g1.offset[17] = 0; gfx_set_g1_element(imageId, &g1); } } } static uint8_t* font_sprite_get_codepoint_bitmap(int32_t codepoint) { auto offset = font_sprite_get_codepoint_offset(codepoint); if (offset >= FONT_SPRITE_GLYPH_COUNT) { return _characterBitmaps[offset - (SPR_G2_CHAR_BEGIN - SPR_CHAR_START) + FONT_SPRITE_GLYPH_COUNT]; } else { return _characterBitmaps[offset]; } } static int32_t scrolling_text_get_matching_or_oldest(rct_string_id stringId, uint16_t scroll, uint16_t scrollingMode) { uint32_t oldestId = 0xFFFFFFFF; int32_t scrollIndex = -1; for (int32_t i = 0; i < MAX_SCROLLING_TEXT_ENTRIES; i++) { rct_draw_scroll_text* scrollText = &_drawScrollTextList[i]; if (oldestId >= scrollText->id) { oldestId = scrollText->id; scrollIndex = i; } // If exact match return the matching index uint32_t stringArgs0, stringArgs1; memcpy(&stringArgs0, gCommonFormatArgs + 0, sizeof(uint32_t)); memcpy(&stringArgs1, gCommonFormatArgs + 4, sizeof(uint32_t)); if (scrollText->string_id == stringId && scrollText->string_args_0 == stringArgs0 && scrollText->string_args_1 == stringArgs1 && scrollText->position == scroll && scrollText->mode == scrollingMode) { scrollText->id = _drawSCrollNextIndex; return i + SPR_SCROLLING_TEXT_START; } } return scrollIndex; } static uint8_t scrolling_text_get_colour(uint32_t character) { int32_t colour = character & 0x7F; if (character & COLOUR_FLAG_TRANSLUCENT) { return ColourMapA[colour].light; } else { return ColourMapA[colour].mid_dark; } } static void scrolling_text_format(utf8* dst, size_t size, rct_draw_scroll_text* scrollText) { if (gConfigGeneral.upper_case_banners) { format_string_to_upper(dst, size, scrollText->string_id, &scrollText->string_args_0); } else { format_string(dst, size, scrollText->string_id, &scrollText->string_args_0); } } extern bool TempForScrollText; #define SCROLL_POS(x, y) (((y)*64) + (x)) // clang-format off static constexpr const int16_t _scrollpos0[] = { SCROLL_POS( 35, 12 ), SCROLL_POS( 36, 12 ), SCROLL_POS( 37, 11 ), SCROLL_POS( 38, 11 ), SCROLL_POS( 39, 10 ), SCROLL_POS( 40, 10 ), SCROLL_POS( 41, 9 ), SCROLL_POS( 42, 9 ), SCROLL_POS( 43, 8 ), SCROLL_POS( 44, 8 ), SCROLL_POS( 45, 7 ), SCROLL_POS( 46, 7 ), SCROLL_POS( 47, 6 ), SCROLL_POS( 48, 6 ), SCROLL_POS( 49, 5 ), SCROLL_POS( 50, 5 ), SCROLL_POS( 51, 4 ), SCROLL_POS( 52, 4 ), SCROLL_POS( 53, 3 ), SCROLL_POS( 54, 3 ), SCROLL_POS( 55, 2 ), SCROLL_POS( 56, 2 ), SCROLL_POS( 57, 1 ), SCROLL_POS( 58, 1 ), -1, }; static constexpr const int16_t _scrollpos1[] = { SCROLL_POS( 5, 1 ), SCROLL_POS( 6, 1 ), SCROLL_POS( 7, 2 ), SCROLL_POS( 8, 2 ), SCROLL_POS( 9, 3 ), SCROLL_POS( 10, 3 ), SCROLL_POS( 11, 4 ), SCROLL_POS( 12, 4 ), SCROLL_POS( 13, 5 ), SCROLL_POS( 14, 5 ), SCROLL_POS( 15, 6 ), SCROLL_POS( 16, 6 ), SCROLL_POS( 17, 7 ), SCROLL_POS( 18, 7 ), SCROLL_POS( 19, 8 ), SCROLL_POS( 20, 8 ), SCROLL_POS( 21, 9 ), SCROLL_POS( 22, 9 ), SCROLL_POS( 23, 10 ), SCROLL_POS( 24, 10 ), SCROLL_POS( 25, 11 ), SCROLL_POS( 26, 11 ), SCROLL_POS( 27, 12 ), SCROLL_POS( 28, 12 ), -1, }; static constexpr const int16_t _scrollpos2[] = { SCROLL_POS( 12, 1 ), SCROLL_POS( 13, 1 ), SCROLL_POS( 14, 2 ), SCROLL_POS( 15, 2 ), SCROLL_POS( 16, 3 ), SCROLL_POS( 17, 3 ), SCROLL_POS( 18, 4 ), SCROLL_POS( 19, 4 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 6 ), SCROLL_POS( 23, 6 ), SCROLL_POS( 24, 7 ), SCROLL_POS( 25, 7 ), SCROLL_POS( 26, 8 ), SCROLL_POS( 27, 8 ), SCROLL_POS( 28, 9 ), SCROLL_POS( 29, 9 ), SCROLL_POS( 30, 10 ), SCROLL_POS( 31, 10 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 9 ), SCROLL_POS( 34, 9 ), SCROLL_POS( 35, 8 ), SCROLL_POS( 36, 8 ), SCROLL_POS( 37, 7 ), SCROLL_POS( 38, 7 ), SCROLL_POS( 39, 6 ), SCROLL_POS( 40, 6 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 4 ), SCROLL_POS( 44, 4 ), SCROLL_POS( 45, 3 ), SCROLL_POS( 46, 3 ), SCROLL_POS( 47, 2 ), SCROLL_POS( 48, 2 ), SCROLL_POS( 49, 1 ), SCROLL_POS( 50, 1 ), -1, }; static constexpr const int16_t _scrollpos3[] = { SCROLL_POS( 16, 0 ), SCROLL_POS( 17, 1 ), SCROLL_POS( 18, 1 ), SCROLL_POS( 19, 2 ), SCROLL_POS( 20, 3 ), SCROLL_POS( 21, 3 ), SCROLL_POS( 22, 4 ), SCROLL_POS( 23, 5 ), SCROLL_POS( 24, 5 ), SCROLL_POS( 25, 6 ), SCROLL_POS( 26, 6 ), SCROLL_POS( 27, 7 ), SCROLL_POS( 28, 7 ), SCROLL_POS( 29, 8 ), SCROLL_POS( 30, 8 ), SCROLL_POS( 31, 9 ), SCROLL_POS( 32, 9 ), SCROLL_POS( 33, 10 ), SCROLL_POS( 34, 10 ), SCROLL_POS( 35, 11 ), SCROLL_POS( 36, 11 ), SCROLL_POS( 37, 12 ), SCROLL_POS( 38, 12 ), SCROLL_POS( 39, 13 ), SCROLL_POS( 40, 13 ), SCROLL_POS( 41, 14 ), SCROLL_POS( 42, 14 ), SCROLL_POS( 43, 14 ), SCROLL_POS( 44, 15 ), SCROLL_POS( 45, 15 ), SCROLL_POS( 46, 15 ), SCROLL_POS( 47, 16 ), SCROLL_POS( 48, 16 ), -1, }; static constexpr const int16_t _scrollpos4[] = { SCROLL_POS( 15, 17 ), SCROLL_POS( 16, 17 ), SCROLL_POS( 17, 16 ), SCROLL_POS( 18, 16 ), SCROLL_POS( 19, 16 ), SCROLL_POS( 20, 15 ), SCROLL_POS( 21, 15 ), SCROLL_POS( 22, 15 ), SCROLL_POS( 23, 14 ), SCROLL_POS( 24, 14 ), SCROLL_POS( 25, 13 ), SCROLL_POS( 26, 13 ), SCROLL_POS( 27, 12 ), SCROLL_POS( 28, 12 ), SCROLL_POS( 29, 11 ), SCROLL_POS( 30, 11 ), SCROLL_POS( 31, 10 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 9 ), SCROLL_POS( 34, 9 ), SCROLL_POS( 35, 8 ), SCROLL_POS( 36, 8 ), SCROLL_POS( 37, 7 ), SCROLL_POS( 38, 7 ), SCROLL_POS( 39, 6 ), SCROLL_POS( 40, 6 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 4 ), SCROLL_POS( 43, 4 ), SCROLL_POS( 44, 3 ), SCROLL_POS( 45, 2 ), SCROLL_POS( 46, 2 ), SCROLL_POS( 47, 1 ), SCROLL_POS( 48, 0 ), -1, }; static constexpr const int16_t _scrollpos5[] = { SCROLL_POS( 4, 12 ), SCROLL_POS( 5, 12 ), SCROLL_POS( 6, 11 ), SCROLL_POS( 7, 11 ), SCROLL_POS( 8, 10 ), SCROLL_POS( 9, 10 ), SCROLL_POS( 10, 9 ), SCROLL_POS( 11, 9 ), SCROLL_POS( 12, 8 ), SCROLL_POS( 13, 8 ), SCROLL_POS( 14, 7 ), SCROLL_POS( 15, 7 ), SCROLL_POS( 16, 6 ), SCROLL_POS( 17, 6 ), SCROLL_POS( 18, 5 ), SCROLL_POS( 19, 5 ), SCROLL_POS( 20, 4 ), SCROLL_POS( 21, 4 ), SCROLL_POS( 22, 3 ), SCROLL_POS( 23, 3 ), SCROLL_POS( 24, 2 ), SCROLL_POS( 25, 2 ), SCROLL_POS( 26, 1 ), SCROLL_POS( 27, 1 ), -1, }; static constexpr const int16_t _scrollpos6[] = { SCROLL_POS( 36, 1 ), SCROLL_POS( 37, 1 ), SCROLL_POS( 38, 2 ), SCROLL_POS( 39, 2 ), SCROLL_POS( 40, 3 ), SCROLL_POS( 41, 3 ), SCROLL_POS( 42, 4 ), SCROLL_POS( 43, 4 ), SCROLL_POS( 44, 5 ), SCROLL_POS( 45, 5 ), SCROLL_POS( 46, 6 ), SCROLL_POS( 47, 6 ), SCROLL_POS( 48, 7 ), SCROLL_POS( 49, 7 ), SCROLL_POS( 50, 8 ), SCROLL_POS( 51, 8 ), SCROLL_POS( 52, 9 ), SCROLL_POS( 53, 9 ), SCROLL_POS( 54, 10 ), SCROLL_POS( 55, 10 ), SCROLL_POS( 56, 11 ), SCROLL_POS( 57, 11 ), SCROLL_POS( 58, 12 ), SCROLL_POS( 59, 12 ), -1, }; static constexpr const int16_t _scrollpos7[] = { SCROLL_POS( 8, 11 ), SCROLL_POS( 9, 11 ), SCROLL_POS( 10, 10 ), SCROLL_POS( 11, 10 ), SCROLL_POS( 12, 9 ), SCROLL_POS( 13, 9 ), SCROLL_POS( 14, 8 ), SCROLL_POS( 15, 8 ), SCROLL_POS( 16, 7 ), SCROLL_POS( 17, 7 ), SCROLL_POS( 18, 6 ), SCROLL_POS( 19, 6 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 4 ), SCROLL_POS( 23, 4 ), SCROLL_POS( 24, 3 ), SCROLL_POS( 25, 3 ), SCROLL_POS( 26, 2 ), SCROLL_POS( 27, 2 ), SCROLL_POS( 28, 1 ), SCROLL_POS( 29, 1 ), -1, }; static constexpr const int16_t _scrollpos8[] = { SCROLL_POS( 36, 2 ), SCROLL_POS( 37, 2 ), SCROLL_POS( 38, 3 ), SCROLL_POS( 39, 3 ), SCROLL_POS( 40, 4 ), SCROLL_POS( 41, 4 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 6 ), SCROLL_POS( 45, 6 ), SCROLL_POS( 46, 7 ), SCROLL_POS( 47, 7 ), SCROLL_POS( 48, 8 ), SCROLL_POS( 49, 8 ), SCROLL_POS( 50, 9 ), SCROLL_POS( 51, 9 ), SCROLL_POS( 52, 10 ), SCROLL_POS( 53, 10 ), SCROLL_POS( 54, 11 ), SCROLL_POS( 55, 11 ), -1, }; static constexpr const int16_t _scrollpos9[] = { SCROLL_POS( 11, 9 ), SCROLL_POS( 12, 9 ), SCROLL_POS( 13, 9 ), SCROLL_POS( 14, 9 ), SCROLL_POS( 15, 9 ), SCROLL_POS( 16, 8 ), SCROLL_POS( 17, 8 ), SCROLL_POS( 18, 7 ), SCROLL_POS( 19, 7 ), SCROLL_POS( 20, 7 ), SCROLL_POS( 21, 6 ), SCROLL_POS( 22, 6 ), SCROLL_POS( 23, 5 ), SCROLL_POS( 24, 4 ), SCROLL_POS( 25, 4 ), SCROLL_POS( 26, 3 ), SCROLL_POS( 27, 3 ), SCROLL_POS( 28, 2 ), SCROLL_POS( 29, 1 ), -1, }; static constexpr const int16_t _scrollpos10[] = { SCROLL_POS( 34, 1 ), SCROLL_POS( 35, 2 ), SCROLL_POS( 36, 3 ), SCROLL_POS( 37, 3 ), SCROLL_POS( 38, 4 ), SCROLL_POS( 39, 4 ), SCROLL_POS( 40, 5 ), SCROLL_POS( 41, 6 ), SCROLL_POS( 42, 6 ), SCROLL_POS( 43, 7 ), SCROLL_POS( 44, 7 ), SCROLL_POS( 45, 7 ), SCROLL_POS( 46, 8 ), SCROLL_POS( 47, 8 ), SCROLL_POS( 48, 9 ), SCROLL_POS( 49, 9 ), SCROLL_POS( 50, 9 ), SCROLL_POS( 51, 9 ), SCROLL_POS( 52, 9 ), -1, }; static constexpr const int16_t _scrollpos11[] = { SCROLL_POS( 14, 10 ), SCROLL_POS( 15, 9 ), SCROLL_POS( 16, 9 ), SCROLL_POS( 17, 8 ), SCROLL_POS( 18, 8 ), SCROLL_POS( 19, 7 ), SCROLL_POS( 20, 7 ), SCROLL_POS( 21, 6 ), SCROLL_POS( 22, 6 ), SCROLL_POS( 23, 5 ), SCROLL_POS( 24, 5 ), SCROLL_POS( 25, 4 ), SCROLL_POS( 26, 4 ), SCROLL_POS( 27, 3 ), SCROLL_POS( 28, 3 ), SCROLL_POS( 29, 2 ), SCROLL_POS( 30, 2 ), SCROLL_POS( 31, 1 ), SCROLL_POS( 32, 1 ), SCROLL_POS( 33, 0 ), SCROLL_POS( 34, 0 ), -1, }; static constexpr const int16_t _scrollpos12[] = { SCROLL_POS( 33, 1 ), SCROLL_POS( 34, 2 ), SCROLL_POS( 35, 2 ), SCROLL_POS( 36, 3 ), SCROLL_POS( 37, 3 ), SCROLL_POS( 38, 4 ), SCROLL_POS( 39, 4 ), SCROLL_POS( 40, 5 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 6 ), SCROLL_POS( 43, 6 ), SCROLL_POS( 44, 7 ), SCROLL_POS( 45, 7 ), SCROLL_POS( 46, 8 ), SCROLL_POS( 47, 8 ), SCROLL_POS( 48, 9 ), SCROLL_POS( 49, 9 ), SCROLL_POS( 50, 10 ), SCROLL_POS( 51, 10 ), SCROLL_POS( 52, 11 ), SCROLL_POS( 53, 11 ), -1, }; static constexpr const int16_t _scrollpos13[] = { SCROLL_POS( 12, 11 ), SCROLL_POS( 13, 10 ), SCROLL_POS( 14, 10 ), SCROLL_POS( 15, 9 ), SCROLL_POS( 16, 9 ), SCROLL_POS( 17, 8 ), SCROLL_POS( 18, 8 ), SCROLL_POS( 19, 7 ), SCROLL_POS( 20, 7 ), SCROLL_POS( 21, 6 ), SCROLL_POS( 22, 6 ), SCROLL_POS( 23, 5 ), SCROLL_POS( 24, 5 ), SCROLL_POS( 25, 4 ), SCROLL_POS( 26, 4 ), SCROLL_POS( 27, 3 ), SCROLL_POS( 28, 3 ), SCROLL_POS( 29, 2 ), SCROLL_POS( 30, 2 ), SCROLL_POS( 31, 1 ), -1, }; static constexpr const int16_t _scrollpos14[] = { SCROLL_POS( 33, 1 ), SCROLL_POS( 34, 2 ), SCROLL_POS( 35, 2 ), SCROLL_POS( 36, 3 ), SCROLL_POS( 37, 3 ), SCROLL_POS( 38, 4 ), SCROLL_POS( 39, 4 ), SCROLL_POS( 40, 5 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 6 ), SCROLL_POS( 43, 6 ), SCROLL_POS( 44, 7 ), SCROLL_POS( 45, 7 ), SCROLL_POS( 46, 8 ), SCROLL_POS( 47, 8 ), SCROLL_POS( 48, 9 ), SCROLL_POS( 49, 9 ), SCROLL_POS( 50, 10 ), SCROLL_POS( 51, 10 ), SCROLL_POS( 52, 11 ), SCROLL_POS( 53, 11 ), -1, }; static constexpr const int16_t _scrollpos15[] = { SCROLL_POS( 10, 10 ), SCROLL_POS( 11, 10 ), SCROLL_POS( 12, 9 ), SCROLL_POS( 13, 9 ), SCROLL_POS( 14, 8 ), SCROLL_POS( 15, 8 ), SCROLL_POS( 16, 7 ), SCROLL_POS( 17, 7 ), SCROLL_POS( 18, 6 ), SCROLL_POS( 19, 6 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 4 ), SCROLL_POS( 23, 4 ), SCROLL_POS( 24, 3 ), SCROLL_POS( 25, 3 ), SCROLL_POS( 26, 2 ), SCROLL_POS( 27, 2 ), SCROLL_POS( 28, 1 ), SCROLL_POS( 29, 1 ), SCROLL_POS( 30, 0 ), SCROLL_POS( 31, 0 ), -1, }; static constexpr const int16_t _scrollpos16[] = { SCROLL_POS( 33, 0 ), SCROLL_POS( 34, 0 ), SCROLL_POS( 35, 1 ), SCROLL_POS( 36, 1 ), SCROLL_POS( 37, 2 ), SCROLL_POS( 38, 2 ), SCROLL_POS( 39, 3 ), SCROLL_POS( 40, 3 ), SCROLL_POS( 41, 4 ), SCROLL_POS( 42, 4 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 5 ), SCROLL_POS( 45, 6 ), SCROLL_POS( 46, 6 ), SCROLL_POS( 47, 7 ), SCROLL_POS( 48, 7 ), SCROLL_POS( 49, 8 ), SCROLL_POS( 50, 8 ), SCROLL_POS( 51, 9 ), SCROLL_POS( 52, 9 ), SCROLL_POS( 53, 10 ), SCROLL_POS( 54, 10 ), -1, }; static constexpr const int16_t _scrollpos17[] = { SCROLL_POS( 6, 11 ), SCROLL_POS( 7, 11 ), SCROLL_POS( 8, 10 ), SCROLL_POS( 9, 10 ), SCROLL_POS( 10, 9 ), SCROLL_POS( 11, 9 ), SCROLL_POS( 12, 8 ), SCROLL_POS( 13, 8 ), SCROLL_POS( 14, 7 ), SCROLL_POS( 15, 7 ), SCROLL_POS( 16, 6 ), SCROLL_POS( 17, 6 ), SCROLL_POS( 18, 5 ), SCROLL_POS( 19, 5 ), SCROLL_POS( 20, 4 ), SCROLL_POS( 21, 4 ), SCROLL_POS( 22, 3 ), SCROLL_POS( 23, 3 ), SCROLL_POS( 24, 2 ), SCROLL_POS( 25, 2 ), SCROLL_POS( 26, 1 ), SCROLL_POS( 27, 1 ), SCROLL_POS( 28, 0 ), SCROLL_POS( 29, 0 ), -1, }; static constexpr const int16_t _scrollpos18[] = { SCROLL_POS( 34, 0 ), SCROLL_POS( 35, 0 ), SCROLL_POS( 36, 1 ), SCROLL_POS( 37, 1 ), SCROLL_POS( 38, 2 ), SCROLL_POS( 39, 2 ), SCROLL_POS( 40, 3 ), SCROLL_POS( 41, 3 ), SCROLL_POS( 42, 4 ), SCROLL_POS( 43, 4 ), SCROLL_POS( 44, 5 ), SCROLL_POS( 45, 5 ), SCROLL_POS( 46, 6 ), SCROLL_POS( 47, 6 ), SCROLL_POS( 48, 7 ), SCROLL_POS( 49, 7 ), SCROLL_POS( 50, 8 ), SCROLL_POS( 51, 8 ), SCROLL_POS( 52, 9 ), SCROLL_POS( 53, 9 ), SCROLL_POS( 54, 10 ), SCROLL_POS( 55, 10 ), SCROLL_POS( 56, 11 ), SCROLL_POS( 57, 11 ), -1, }; static constexpr const int16_t _scrollpos19[] = { SCROLL_POS( 13, 1 ), SCROLL_POS( 14, 1 ), SCROLL_POS( 15, 2 ), SCROLL_POS( 16, 2 ), SCROLL_POS( 17, 3 ), SCROLL_POS( 18, 3 ), SCROLL_POS( 19, 4 ), SCROLL_POS( 20, 4 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 5 ), SCROLL_POS( 23, 6 ), SCROLL_POS( 24, 6 ), SCROLL_POS( 25, 7 ), SCROLL_POS( 26, 7 ), SCROLL_POS( 27, 8 ), SCROLL_POS( 28, 8 ), SCROLL_POS( 29, 9 ), SCROLL_POS( 30, 9 ), SCROLL_POS( 31, 10 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 10 ), SCROLL_POS( 34, 9 ), SCROLL_POS( 35, 9 ), SCROLL_POS( 36, 8 ), SCROLL_POS( 37, 8 ), SCROLL_POS( 38, 7 ), SCROLL_POS( 39, 7 ), SCROLL_POS( 40, 6 ), SCROLL_POS( 41, 6 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 4 ), SCROLL_POS( 45, 4 ), SCROLL_POS( 46, 3 ), SCROLL_POS( 47, 3 ), SCROLL_POS( 48, 2 ), SCROLL_POS( 49, 2 ), SCROLL_POS( 50, 1 ), SCROLL_POS( 51, 1 ), -1, }; static constexpr const int16_t _scrollpos20[] = { SCROLL_POS( 12, 1 ), SCROLL_POS( 13, 3 ), SCROLL_POS( 14, 4 ), SCROLL_POS( 15, 5 ), SCROLL_POS( 16, 6 ), SCROLL_POS( 17, 7 ), SCROLL_POS( 18, 7 ), SCROLL_POS( 19, 8 ), SCROLL_POS( 20, 8 ), SCROLL_POS( 21, 9 ), SCROLL_POS( 22, 9 ), SCROLL_POS( 23, 9 ), SCROLL_POS( 24, 10 ), SCROLL_POS( 25, 10 ), SCROLL_POS( 26, 10 ), SCROLL_POS( 27, 10 ), SCROLL_POS( 28, 10 ), SCROLL_POS( 29, 10 ), SCROLL_POS( 30, 10 ), SCROLL_POS( 31, 10 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 10 ), SCROLL_POS( 34, 10 ), SCROLL_POS( 35, 10 ), SCROLL_POS( 36, 10 ), SCROLL_POS( 37, 10 ), SCROLL_POS( 38, 10 ), SCROLL_POS( 39, 9 ), SCROLL_POS( 40, 9 ), SCROLL_POS( 41, 9 ), SCROLL_POS( 42, 8 ), SCROLL_POS( 43, 8 ), SCROLL_POS( 44, 7 ), SCROLL_POS( 45, 7 ), SCROLL_POS( 46, 6 ), SCROLL_POS( 47, 5 ), SCROLL_POS( 48, 4 ), SCROLL_POS( 49, 3 ), -1, }; static constexpr const int16_t _scrollpos21[] = { SCROLL_POS( 12, 1 ), SCROLL_POS( 13, 1 ), SCROLL_POS( 14, 2 ), SCROLL_POS( 15, 2 ), SCROLL_POS( 16, 3 ), SCROLL_POS( 17, 3 ), SCROLL_POS( 18, 4 ), SCROLL_POS( 19, 4 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 6 ), SCROLL_POS( 23, 6 ), SCROLL_POS( 24, 7 ), SCROLL_POS( 25, 7 ), SCROLL_POS( 26, 8 ), SCROLL_POS( 27, 8 ), SCROLL_POS( 28, 9 ), SCROLL_POS( 29, 9 ), SCROLL_POS( 30, 10 ), SCROLL_POS( 31, 10 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 9 ), SCROLL_POS( 34, 9 ), SCROLL_POS( 35, 8 ), SCROLL_POS( 36, 8 ), SCROLL_POS( 37, 7 ), SCROLL_POS( 38, 7 ), SCROLL_POS( 39, 6 ), SCROLL_POS( 40, 6 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 4 ), SCROLL_POS( 44, 4 ), SCROLL_POS( 45, 3 ), SCROLL_POS( 46, 3 ), SCROLL_POS( 47, 2 ), SCROLL_POS( 48, 2 ), SCROLL_POS( 49, 1 ), -1, }; static constexpr const int16_t _scrollpos22[] = { SCROLL_POS( 16, 1 ), SCROLL_POS( 17, 1 ), SCROLL_POS( 18, 2 ), SCROLL_POS( 19, 2 ), SCROLL_POS( 20, 3 ), SCROLL_POS( 21, 3 ), SCROLL_POS( 22, 4 ), SCROLL_POS( 23, 4 ), SCROLL_POS( 24, 5 ), SCROLL_POS( 25, 5 ), SCROLL_POS( 26, 6 ), SCROLL_POS( 27, 6 ), SCROLL_POS( 28, 6 ), SCROLL_POS( 29, 6 ), SCROLL_POS( 30, 6 ), SCROLL_POS( 31, 6 ), SCROLL_POS( 32, 6 ), SCROLL_POS( 33, 6 ), SCROLL_POS( 34, 6 ), SCROLL_POS( 35, 6 ), SCROLL_POS( 36, 6 ), SCROLL_POS( 37, 6 ), SCROLL_POS( 38, 6 ), SCROLL_POS( 39, 5 ), SCROLL_POS( 40, 5 ), SCROLL_POS( 41, 4 ), SCROLL_POS( 42, 4 ), SCROLL_POS( 43, 3 ), SCROLL_POS( 44, 3 ), SCROLL_POS( 45, 2 ), SCROLL_POS( 46, 2 ), SCROLL_POS( 47, 1 ), SCROLL_POS( 48, 1 ), -1, }; static constexpr const int16_t _scrollpos23[] = { SCROLL_POS( 15, 1 ), SCROLL_POS( 16, 2 ), SCROLL_POS( 17, 2 ), SCROLL_POS( 18, 3 ), SCROLL_POS( 19, 4 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 5 ), SCROLL_POS( 23, 6 ), SCROLL_POS( 24, 6 ), SCROLL_POS( 25, 6 ), SCROLL_POS( 26, 6 ), SCROLL_POS( 27, 7 ), SCROLL_POS( 28, 7 ), SCROLL_POS( 29, 7 ), SCROLL_POS( 30, 7 ), SCROLL_POS( 31, 7 ), SCROLL_POS( 32, 7 ), SCROLL_POS( 33, 7 ), SCROLL_POS( 34, 7 ), SCROLL_POS( 35, 7 ), SCROLL_POS( 36, 7 ), SCROLL_POS( 37, 6 ), SCROLL_POS( 38, 6 ), SCROLL_POS( 39, 6 ), SCROLL_POS( 40, 6 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 4 ), SCROLL_POS( 45, 3 ), SCROLL_POS( 46, 3 ), SCROLL_POS( 47, 2 ), SCROLL_POS( 48, 1 ), -1, }; static constexpr const int16_t _scrollpos24[] = { SCROLL_POS( 8, 9 ), SCROLL_POS( 9, 9 ), SCROLL_POS( 10, 8 ), SCROLL_POS( 11, 8 ), SCROLL_POS( 12, 7 ), SCROLL_POS( 13, 7 ), SCROLL_POS( 14, 6 ), SCROLL_POS( 15, 6 ), SCROLL_POS( 16, 5 ), SCROLL_POS( 17, 5 ), SCROLL_POS( 18, 4 ), SCROLL_POS( 19, 4 ), SCROLL_POS( 20, 3 ), SCROLL_POS( 21, 3 ), SCROLL_POS( 22, 2 ), SCROLL_POS( 23, 2 ), SCROLL_POS( 24, 1 ), SCROLL_POS( 25, 1 ), SCROLL_POS( 26, 0 ), SCROLL_POS( 27, 0 ), -1, }; static constexpr const int16_t _scrollpos25[] = { SCROLL_POS( 36, 0 ), SCROLL_POS( 37, 0 ), SCROLL_POS( 38, 1 ), SCROLL_POS( 39, 1 ), SCROLL_POS( 40, 2 ), SCROLL_POS( 41, 2 ), SCROLL_POS( 42, 3 ), SCROLL_POS( 43, 3 ), SCROLL_POS( 44, 4 ), SCROLL_POS( 45, 4 ), SCROLL_POS( 46, 5 ), SCROLL_POS( 47, 5 ), SCROLL_POS( 48, 6 ), SCROLL_POS( 49, 6 ), SCROLL_POS( 50, 7 ), SCROLL_POS( 51, 7 ), SCROLL_POS( 52, 8 ), SCROLL_POS( 53, 8 ), SCROLL_POS( 54, 9 ), SCROLL_POS( 55, 9 ), -1, }; static constexpr const int16_t _scrollpos26[] = { SCROLL_POS( 4, 13 ), SCROLL_POS( 5, 13 ), SCROLL_POS( 6, 12 ), SCROLL_POS( 7, 12 ), SCROLL_POS( 8, 11 ), SCROLL_POS( 9, 11 ), SCROLL_POS( 10, 10 ), SCROLL_POS( 11, 10 ), SCROLL_POS( 12, 9 ), SCROLL_POS( 13, 9 ), SCROLL_POS( 14, 8 ), SCROLL_POS( 15, 8 ), SCROLL_POS( 16, 7 ), SCROLL_POS( 17, 7 ), SCROLL_POS( 18, 6 ), SCROLL_POS( 19, 6 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 4 ), SCROLL_POS( 23, 4 ), SCROLL_POS( 24, 3 ), SCROLL_POS( 25, 3 ), SCROLL_POS( 26, 2 ), SCROLL_POS( 27, 2 ), SCROLL_POS( 28, 1 ), SCROLL_POS( 29, 1 ), SCROLL_POS( 30, 0 ), SCROLL_POS( 31, 0 ), -1, }; static constexpr const int16_t _scrollpos27[] = { SCROLL_POS( 32, 0 ), SCROLL_POS( 33, 0 ), SCROLL_POS( 34, 1 ), SCROLL_POS( 35, 1 ), SCROLL_POS( 36, 2 ), SCROLL_POS( 37, 2 ), SCROLL_POS( 38, 3 ), SCROLL_POS( 39, 3 ), SCROLL_POS( 40, 4 ), SCROLL_POS( 41, 4 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 6 ), SCROLL_POS( 45, 6 ), SCROLL_POS( 46, 7 ), SCROLL_POS( 47, 7 ), SCROLL_POS( 48, 8 ), SCROLL_POS( 49, 8 ), SCROLL_POS( 50, 9 ), SCROLL_POS( 51, 9 ), SCROLL_POS( 52, 10 ), SCROLL_POS( 53, 10 ), SCROLL_POS( 54, 11 ), SCROLL_POS( 55, 11 ), SCROLL_POS( 56, 12 ), SCROLL_POS( 57, 12 ), SCROLL_POS( 58, 13 ), SCROLL_POS( 59, 13 ), -1, }; static constexpr const int16_t _scrollpos28[] = { SCROLL_POS( 6, 13 ), SCROLL_POS( 7, 13 ), SCROLL_POS( 8, 12 ), SCROLL_POS( 9, 12 ), SCROLL_POS( 10, 11 ), SCROLL_POS( 11, 11 ), SCROLL_POS( 12, 10 ), SCROLL_POS( 13, 10 ), SCROLL_POS( 14, 9 ), SCROLL_POS( 15, 9 ), SCROLL_POS( 16, 8 ), SCROLL_POS( 17, 8 ), SCROLL_POS( 18, 7 ), SCROLL_POS( 19, 7 ), SCROLL_POS( 20, 6 ), SCROLL_POS( 21, 6 ), SCROLL_POS( 22, 5 ), SCROLL_POS( 23, 5 ), SCROLL_POS( 24, 4 ), SCROLL_POS( 25, 4 ), SCROLL_POS( 26, 3 ), SCROLL_POS( 27, 3 ), SCROLL_POS( 28, 2 ), SCROLL_POS( 29, 2 ), SCROLL_POS( 30, 1 ), SCROLL_POS( 31, 1 ), SCROLL_POS( 32, 0 ), SCROLL_POS( 33, 0 ), -1, }; static constexpr const int16_t _scrollpos29[] = { SCROLL_POS( 30, 0 ), SCROLL_POS( 31, 0 ), SCROLL_POS( 32, 1 ), SCROLL_POS( 33, 1 ), SCROLL_POS( 34, 2 ), SCROLL_POS( 35, 2 ), SCROLL_POS( 36, 3 ), SCROLL_POS( 37, 3 ), SCROLL_POS( 38, 4 ), SCROLL_POS( 39, 4 ), SCROLL_POS( 40, 5 ), SCROLL_POS( 41, 5 ), SCROLL_POS( 42, 6 ), SCROLL_POS( 43, 6 ), SCROLL_POS( 44, 7 ), SCROLL_POS( 45, 7 ), SCROLL_POS( 46, 8 ), SCROLL_POS( 47, 8 ), SCROLL_POS( 48, 9 ), SCROLL_POS( 49, 9 ), SCROLL_POS( 50, 10 ), SCROLL_POS( 51, 10 ), SCROLL_POS( 52, 11 ), SCROLL_POS( 53, 11 ), SCROLL_POS( 54, 12 ), SCROLL_POS( 55, 12 ), SCROLL_POS( 56, 13 ), SCROLL_POS( 57, 13 ), -1, }; static constexpr const int16_t _scrollpos30[] = { SCROLL_POS( 2, 30 ), SCROLL_POS( 3, 30 ), SCROLL_POS( 4, 29 ), SCROLL_POS( 5, 29 ), SCROLL_POS( 6, 28 ), SCROLL_POS( 7, 28 ), SCROLL_POS( 8, 27 ), SCROLL_POS( 9, 27 ), SCROLL_POS( 10, 26 ), SCROLL_POS( 11, 26 ), SCROLL_POS( 12, 25 ), SCROLL_POS( 13, 25 ), SCROLL_POS( 14, 24 ), SCROLL_POS( 15, 24 ), SCROLL_POS( 16, 23 ), SCROLL_POS( 17, 23 ), SCROLL_POS( 18, 22 ), SCROLL_POS( 19, 22 ), SCROLL_POS( 20, 21 ), SCROLL_POS( 21, 21 ), SCROLL_POS( 22, 20 ), SCROLL_POS( 23, 20 ), SCROLL_POS( 24, 19 ), SCROLL_POS( 25, 19 ), SCROLL_POS( 26, 18 ), SCROLL_POS( 27, 18 ), SCROLL_POS( 28, 17 ), SCROLL_POS( 29, 17 ), SCROLL_POS( 30, 16 ), SCROLL_POS( 31, 16 ), SCROLL_POS( 32, 15 ), SCROLL_POS( 33, 15 ), SCROLL_POS( 34, 14 ), SCROLL_POS( 35, 14 ), SCROLL_POS( 36, 13 ), SCROLL_POS( 37, 13 ), SCROLL_POS( 38, 12 ), SCROLL_POS( 39, 12 ), SCROLL_POS( 40, 11 ), SCROLL_POS( 41, 11 ), SCROLL_POS( 42, 10 ), SCROLL_POS( 43, 10 ), SCROLL_POS( 44, 9 ), SCROLL_POS( 45, 9 ), SCROLL_POS( 46, 8 ), SCROLL_POS( 47, 8 ), SCROLL_POS( 48, 7 ), SCROLL_POS( 49, 7 ), SCROLL_POS( 50, 6 ), SCROLL_POS( 51, 6 ), SCROLL_POS( 52, 5 ), SCROLL_POS( 53, 5 ), SCROLL_POS( 54, 4 ), SCROLL_POS( 55, 4 ), SCROLL_POS( 56, 3 ), SCROLL_POS( 57, 3 ), SCROLL_POS( 58, 2 ), SCROLL_POS( 59, 2 ), SCROLL_POS( 60, 1 ), SCROLL_POS( 61, 1 ), SCROLL_POS( 62, 0 ), -1, }; static constexpr const int16_t _scrollpos31[] = { SCROLL_POS( 1, 0 ), SCROLL_POS( 2, 1 ), SCROLL_POS( 3, 1 ), SCROLL_POS( 4, 2 ), SCROLL_POS( 5, 2 ), SCROLL_POS( 6, 3 ), SCROLL_POS( 7, 3 ), SCROLL_POS( 8, 4 ), SCROLL_POS( 9, 4 ), SCROLL_POS( 10, 5 ), SCROLL_POS( 11, 5 ), SCROLL_POS( 12, 6 ), SCROLL_POS( 13, 6 ), SCROLL_POS( 14, 7 ), SCROLL_POS( 15, 7 ), SCROLL_POS( 16, 8 ), SCROLL_POS( 17, 8 ), SCROLL_POS( 18, 9 ), SCROLL_POS( 19, 9 ), SCROLL_POS( 20, 10 ), SCROLL_POS( 21, 10 ), SCROLL_POS( 22, 11 ), SCROLL_POS( 23, 11 ), SCROLL_POS( 24, 12 ), SCROLL_POS( 25, 12 ), SCROLL_POS( 26, 13 ), SCROLL_POS( 27, 13 ), SCROLL_POS( 28, 14 ), SCROLL_POS( 29, 14 ), SCROLL_POS( 30, 15 ), SCROLL_POS( 31, 15 ), SCROLL_POS( 32, 16 ), SCROLL_POS( 33, 16 ), SCROLL_POS( 34, 17 ), SCROLL_POS( 35, 17 ), SCROLL_POS( 36, 18 ), SCROLL_POS( 37, 18 ), SCROLL_POS( 38, 19 ), SCROLL_POS( 39, 19 ), SCROLL_POS( 40, 20 ), SCROLL_POS( 41, 20 ), SCROLL_POS( 42, 21 ), SCROLL_POS( 43, 21 ), SCROLL_POS( 44, 22 ), SCROLL_POS( 45, 22 ), SCROLL_POS( 46, 23 ), SCROLL_POS( 47, 23 ), SCROLL_POS( 48, 24 ), SCROLL_POS( 49, 24 ), SCROLL_POS( 50, 25 ), SCROLL_POS( 51, 25 ), SCROLL_POS( 52, 26 ), SCROLL_POS( 53, 26 ), SCROLL_POS( 54, 27 ), SCROLL_POS( 55, 27 ), SCROLL_POS( 56, 28 ), SCROLL_POS( 57, 28 ), SCROLL_POS( 58, 29 ), SCROLL_POS( 59, 29 ), SCROLL_POS( 60, 30 ), SCROLL_POS( 61, 30 ), -1, }; static constexpr const int16_t _scrollpos32[] = { SCROLL_POS( 12, 0 ), SCROLL_POS( 13, 1 ), SCROLL_POS( 14, 1 ), SCROLL_POS( 15, 2 ), SCROLL_POS( 16, 2 ), SCROLL_POS( 17, 3 ), SCROLL_POS( 18, 3 ), SCROLL_POS( 19, 4 ), SCROLL_POS( 20, 4 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 5 ), SCROLL_POS( 23, 6 ), SCROLL_POS( 24, 6 ), SCROLL_POS( 25, 7 ), SCROLL_POS( 26, 7 ), SCROLL_POS( 27, 8 ), SCROLL_POS( 28, 8 ), SCROLL_POS( 29, 9 ), SCROLL_POS( 30, 9 ), SCROLL_POS( 31, 10 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 11 ), SCROLL_POS( 34, 11 ), SCROLL_POS( 35, 12 ), SCROLL_POS( 36, 12 ), SCROLL_POS( 37, 13 ), SCROLL_POS( 38, 13 ), SCROLL_POS( 39, 14 ), SCROLL_POS( 40, 14 ), SCROLL_POS( 41, 15 ), SCROLL_POS( 42, 15 ), SCROLL_POS( 43, 16 ), SCROLL_POS( 44, 16 ), SCROLL_POS( 45, 17 ), SCROLL_POS( 46, 17 ), SCROLL_POS( 47, 18 ), SCROLL_POS( 48, 18 ), SCROLL_POS( 49, 19 ), SCROLL_POS( 50, 19 ), -1, }; static constexpr const int16_t _scrollpos33[] = { SCROLL_POS( 12, 20 ), SCROLL_POS( 13, 20 ), SCROLL_POS( 14, 19 ), SCROLL_POS( 15, 19 ), SCROLL_POS( 16, 18 ), SCROLL_POS( 17, 18 ), SCROLL_POS( 18, 17 ), SCROLL_POS( 19, 17 ), SCROLL_POS( 20, 16 ), SCROLL_POS( 21, 16 ), SCROLL_POS( 22, 15 ), SCROLL_POS( 23, 15 ), SCROLL_POS( 24, 14 ), SCROLL_POS( 25, 14 ), SCROLL_POS( 26, 13 ), SCROLL_POS( 27, 13 ), SCROLL_POS( 28, 12 ), SCROLL_POS( 29, 12 ), SCROLL_POS( 30, 11 ), SCROLL_POS( 31, 11 ), SCROLL_POS( 32, 10 ), SCROLL_POS( 33, 10 ), SCROLL_POS( 34, 9 ), SCROLL_POS( 35, 9 ), SCROLL_POS( 36, 8 ), SCROLL_POS( 37, 8 ), SCROLL_POS( 38, 7 ), SCROLL_POS( 39, 7 ), SCROLL_POS( 40, 6 ), SCROLL_POS( 41, 6 ), SCROLL_POS( 42, 5 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 4 ), SCROLL_POS( 45, 4 ), SCROLL_POS( 46, 3 ), SCROLL_POS( 47, 3 ), SCROLL_POS( 48, 2 ), SCROLL_POS( 49, 2 ), SCROLL_POS( 50, 1 ), SCROLL_POS( 51, 1 ), -1, }; static constexpr const int16_t _scrollpos34[] = { SCROLL_POS( 2, 14 ), SCROLL_POS( 3, 14 ), SCROLL_POS( 4, 13 ), SCROLL_POS( 5, 13 ), SCROLL_POS( 6, 12 ), SCROLL_POS( 7, 12 ), SCROLL_POS( 8, 11 ), SCROLL_POS( 9, 11 ), SCROLL_POS( 10, 10 ), SCROLL_POS( 11, 10 ), SCROLL_POS( 12, 9 ), SCROLL_POS( 13, 9 ), SCROLL_POS( 14, 8 ), SCROLL_POS( 15, 8 ), SCROLL_POS( 16, 7 ), SCROLL_POS( 17, 7 ), SCROLL_POS( 18, 6 ), SCROLL_POS( 19, 6 ), SCROLL_POS( 20, 5 ), SCROLL_POS( 21, 5 ), SCROLL_POS( 22, 4 ), SCROLL_POS( 23, 4 ), SCROLL_POS( 24, 3 ), SCROLL_POS( 25, 3 ), SCROLL_POS( 26, 2 ), SCROLL_POS( 27, 2 ), SCROLL_POS( 28, 1 ), SCROLL_POS( 29, 1 ), SCROLL_POS( 30, 0 ), -1, }; static constexpr const int16_t _scrollpos35[] = { SCROLL_POS( 33, 0 ), SCROLL_POS( 34, 0 ), SCROLL_POS( 35, 1 ), SCROLL_POS( 36, 1 ), SCROLL_POS( 37, 2 ), SCROLL_POS( 38, 2 ), SCROLL_POS( 39, 3 ), SCROLL_POS( 40, 3 ), SCROLL_POS( 41, 4 ), SCROLL_POS( 42, 4 ), SCROLL_POS( 43, 5 ), SCROLL_POS( 44, 5 ), SCROLL_POS( 45, 6 ), SCROLL_POS( 46, 6 ), SCROLL_POS( 47, 7 ), SCROLL_POS( 48, 7 ), SCROLL_POS( 49, 8 ), SCROLL_POS( 50, 8 ), SCROLL_POS( 51, 9 ), SCROLL_POS( 52, 9 ), SCROLL_POS( 53, 10 ), SCROLL_POS( 54, 10 ), SCROLL_POS( 55, 11 ), SCROLL_POS( 56, 11 ), SCROLL_POS( 57, 12 ), SCROLL_POS( 58, 12 ), SCROLL_POS( 59, 13 ), SCROLL_POS( 60, 13 ), SCROLL_POS( 61, 14 ), -1, }; static constexpr const int16_t _scrollpos36[] = { SCROLL_POS( 4, 0 ), SCROLL_POS( 5, 1 ), SCROLL_POS( 6, 2 ), SCROLL_POS( 7, 3 ), SCROLL_POS( 8, 3 ), SCROLL_POS( 9, 4 ), SCROLL_POS( 10, 5 ), SCROLL_POS( 11, 5 ), SCROLL_POS( 12, 6 ), SCROLL_POS( 13, 6 ), SCROLL_POS( 14, 7 ), SCROLL_POS( 15, 7 ), SCROLL_POS( 16, 8 ), SCROLL_POS( 17, 8 ), SCROLL_POS( 18, 9 ), SCROLL_POS( 19, 9 ), SCROLL_POS( 20, 10 ), SCROLL_POS( 21, 10 ), SCROLL_POS( 22, 10 ), SCROLL_POS( 23, 11 ), SCROLL_POS( 24, 11 ), SCROLL_POS( 25, 11 ), SCROLL_POS( 26, 12 ), SCROLL_POS( 27, 12 ), SCROLL_POS( 28, 12 ), SCROLL_POS( 29, 12 ), SCROLL_POS( 30, 12 ), -1, }; static constexpr const int16_t _scrollpos37[] = { SCROLL_POS( 32, 13 ), SCROLL_POS( 33, 12 ), SCROLL_POS( 34, 12 ), SCROLL_POS( 35, 12 ), SCROLL_POS( 36, 12 ), SCROLL_POS( 37, 11 ), SCROLL_POS( 38, 11 ), SCROLL_POS( 39, 11 ), SCROLL_POS( 40, 10 ), SCROLL_POS( 41, 10 ), SCROLL_POS( 42, 10 ), SCROLL_POS( 43, 9 ), SCROLL_POS( 44, 9 ), SCROLL_POS( 45, 8 ), SCROLL_POS( 46, 8 ), SCROLL_POS( 47, 7 ), SCROLL_POS( 48, 7 ), SCROLL_POS( 49, 6 ), SCROLL_POS( 50, 6 ), SCROLL_POS( 51, 5 ), SCROLL_POS( 52, 5 ), SCROLL_POS( 53, 4 ), SCROLL_POS( 54, 3 ), SCROLL_POS( 55, 3 ), SCROLL_POS( 56, 2 ), SCROLL_POS( 57, 1 ), SCROLL_POS( 58, 0 ), -1, }; static constexpr const int16_t* _scrollPositions[MAX_SCROLLING_TEXT_MODES] = { _scrollpos0, _scrollpos1, _scrollpos2, _scrollpos3, _scrollpos4, _scrollpos5, _scrollpos6, _scrollpos7, _scrollpos8, _scrollpos9, _scrollpos10, _scrollpos11, _scrollpos12, _scrollpos13, _scrollpos14, _scrollpos15, _scrollpos16, _scrollpos17, _scrollpos18, _scrollpos19, _scrollpos20, _scrollpos21, _scrollpos22, _scrollpos23, _scrollpos24, _scrollpos25, _scrollpos26, _scrollpos27, _scrollpos28, _scrollpos29, _scrollpos30, _scrollpos31, _scrollpos32, _scrollpos33, _scrollpos34, _scrollpos35, _scrollpos36, _scrollpos37, }; // clang-format on /** * * rct2: 0x006C42D9 * @param stringId (ax) * @param scroll (cx) * @param scrollingMode (bp) * @returns ebx */ int32_t scrolling_text_setup(paint_session* session, rct_string_id stringId, uint16_t scroll, uint16_t scrollingMode) { assert(scrollingMode < MAX_SCROLLING_TEXT_MODES); rct_drawpixelinfo* dpi = session->DPI; if (dpi->zoom_level != 0) return SPR_SCROLLING_TEXT_DEFAULT; _drawSCrollNextIndex++; int32_t scrollIndex = scrolling_text_get_matching_or_oldest(stringId, scroll, scrollingMode); if (scrollIndex >= SPR_SCROLLING_TEXT_START) return scrollIndex; // Setup scrolling text uint32_t stringArgs0, stringArgs1; memcpy(&stringArgs0, gCommonFormatArgs + 0, sizeof(uint32_t)); memcpy(&stringArgs1, gCommonFormatArgs + 4, sizeof(uint32_t)); rct_draw_scroll_text* scrollText = &_drawScrollTextList[scrollIndex]; scrollText->string_id = stringId; scrollText->string_args_0 = stringArgs0; scrollText->string_args_1 = stringArgs1; scrollText->position = scroll; scrollText->mode = scrollingMode; scrollText->id = _drawSCrollNextIndex; // Create the string to draw utf8 scrollString[256]; scrolling_text_format(scrollString, 256, scrollText); const int16_t* scrollingModePositions = _scrollPositions[scrollingMode]; memset(scrollText->bitmap, 0, 320 * 8); if (LocalisationService_UseTrueTypeFont()) { scrolling_text_set_bitmap_for_ttf(scrollString, scroll, scrollText->bitmap, scrollingModePositions); } else { scrolling_text_set_bitmap_for_sprite(scrollString, scroll, scrollText->bitmap, scrollingModePositions); } uint32_t imageId = SPR_SCROLLING_TEXT_START + scrollIndex; drawing_engine_invalidate_image(imageId); return imageId; } static void scrolling_text_set_bitmap_for_sprite(utf8* text, int32_t scroll, uint8_t* bitmap, const int16_t* scrollPositionOffsets) { uint8_t characterColour = scrolling_text_get_colour(gCommonFormatArgs[7]); utf8* ch = text; while (true) { uint32_t codepoint = utf8_get_next(ch, (const utf8**)&ch); // If at the end of the string loop back to the start if (codepoint == 0) { ch = text; continue; } // Set any change in colour if (codepoint <= FORMAT_COLOUR_CODE_END && codepoint >= FORMAT_COLOUR_CODE_START) { codepoint -= FORMAT_COLOUR_CODE_START; const rct_g1_element* g1 = gfx_get_g1_element(SPR_TEXT_PALETTE); if (g1 != nullptr) { characterColour = g1->offset[codepoint * 4]; } continue; } // If another type of control character ignore if (codepoint < 32) continue; int32_t characterWidth = font_sprite_get_codepoint_width(FONT_SPRITE_BASE_TINY, codepoint); uint8_t* characterBitmap = font_sprite_get_codepoint_bitmap(codepoint); for (; characterWidth != 0; characterWidth--, characterBitmap++) { // Skip any non-displayed columns if (scroll != 0) { scroll--; continue; } int16_t scrollPosition = *scrollPositionOffsets; if (scrollPosition == -1) return; if (scrollPosition > -1) { uint8_t* dst = &bitmap[scrollPosition]; for (uint8_t char_bitmap = *characterBitmap; char_bitmap != 0; char_bitmap >>= 1) { if (char_bitmap & 1) *dst = characterColour; // Jump to next row dst += 64; } } scrollPositionOffsets++; } } } static void scrolling_text_set_bitmap_for_ttf(utf8* text, int32_t scroll, uint8_t* bitmap, const int16_t* scrollPositionOffsets) { #ifndef NO_TTF TTFFontDescriptor* fontDesc = ttf_get_font_from_sprite_base(FONT_SPRITE_BASE_TINY); if (fontDesc->font == nullptr) { scrolling_text_set_bitmap_for_sprite(text, scroll, bitmap, scrollPositionOffsets); return; } // Currently only supports one colour uint8_t colour = 0; utf8* dstCh = text; utf8* ch = text; int32_t codepoint; while ((codepoint = utf8_get_next(ch, (const utf8**)&ch)) != 0) { if (utf8_is_format_code(codepoint)) { if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) { colour = (uint8_t)codepoint; } } else { dstCh = utf8_write_codepoint(dstCh, codepoint); } } *dstCh = 0; if (colour == 0) { colour = scrolling_text_get_colour(gCommonFormatArgs[7]); } else { const rct_g1_element* g1 = gfx_get_g1_element(SPR_TEXT_PALETTE); if (g1 != nullptr) { colour = g1->offset[(colour - FORMAT_COLOUR_CODE_START) * 4]; } } TTFSurface* surface = ttf_surface_cache_get_or_add(fontDesc->font, text); if (surface == nullptr) { return; } int32_t pitch = surface->pitch; int32_t width = surface->w; auto src = (const uint8_t*)surface->pixels; // Pitch offset src += 2 * pitch; // Line height offset int32_t min_vpos = -fontDesc->offset_y; int32_t max_vpos = std::min(surface->h - 2, min_vpos + 7); bool use_hinting = gConfigFonts.enable_hinting && fontDesc->hinting_threshold > 0; for (int32_t x = 0;; x++) { if (x >= width) x = 0; // Skip any non-displayed columns if (scroll == 0) { int16_t scrollPosition = *scrollPositionOffsets; if (scrollPosition == -1) return; if (scrollPosition > -1) { uint8_t* dst = &bitmap[scrollPosition]; for (int32_t y = min_vpos; y < max_vpos; y++) { uint8_t src_pixel = src[y * pitch + x]; if ((!use_hinting && src_pixel != 0) || src_pixel > 140) { // Centre of the glyph: use full colour. *dst = colour; } else if (use_hinting && src_pixel > fontDesc->hinting_threshold) { // Simulate font hinting by shading the background colour instead. *dst = blendColours(colour, *dst); } // Jump to next row dst += 64; } } scrollPositionOffsets++; } else { scroll--; } } #endif // NO_TTF }