From 34c00b12e7d8c1d03cc3e0c3a5e21c2c642f1d52 Mon Sep 17 00:00:00 2001 From: Bodmer Date: Mon, 15 Feb 2021 19:20:12 +0000 Subject: [PATCH] Address #1001 - flicker reduction for smooth fonts Replace block erase of string area with glyph by glyph scan-line clearing to minimise flicker --- Extensions/Smooth_font.cpp | 35 +++++++++++++++++++++++++++++------ TFT_eSPI.cpp | 38 ++++++++++++++++++++++++++++---------- TFT_eSPI.h | 5 +++++ 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index fa94c59..22d3bc9 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -316,7 +316,7 @@ uint32_t TFT_eSPI::readInt32(void) #ifdef FONT_FS_AVAILABLE if (fs_font) { - val |= fontFile.read() << 24; + val = fontFile.read() << 24; val |= fontFile.read() << 16; val |= fontFile.read() << 8; val |= fontFile.read(); @@ -324,7 +324,7 @@ uint32_t TFT_eSPI::readInt32(void) else #endif { - val |= pgm_read_byte(fontPtr++) << 24; + val = pgm_read_byte(fontPtr++) << 24; val |= pgm_read_byte(fontPtr++) << 16; val |= pgm_read_byte(fontPtr++) << 8; val |= pgm_read_byte(fontPtr++); @@ -364,8 +364,12 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (code < 0x21) { - if (code == 0x20) { - //if (fg!=bg) fillRect(cursor_x, cursor_y, gFont.spaceWidth, gFont.yAdvance, bg); + if (code == 0x20) { // May need to expand to other thin space glyphs, see https://en.wikipedia.org/wiki/Thin_space + if (fg!=bg && _sfbg_enable) { + fillRect(glyph_xbg, cursor_y, gFont.spaceWidth, gFont.yAdvance, bg); + glyph_xbg += gFont.spaceWidth; + // glyph_1st = false; + } cursor_x += gFont.spaceWidth; return; } @@ -374,6 +378,8 @@ void TFT_eSPI::drawGlyph(uint16_t code) cursor_x = 0; cursor_y += gFont.yAdvance; if (textwrapY && (cursor_y >= height())) cursor_y = 0; + glyph_xbg = 0; + // glyph_1st = true; return; } } @@ -390,7 +396,12 @@ void TFT_eSPI::drawGlyph(uint16_t code) cursor_x = 0; } if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0; - if (cursor_x == 0) cursor_x -= gdX[gNum]; + if (cursor_x == 0) + { + cursor_x -= gdX[gNum]; + glyph_xbg = 0; + // glyph_1st = true; + } uint8_t* pbuffer = nullptr; const uint8_t* gPtr = (const uint8_t*) gFont.gArray; @@ -405,6 +416,7 @@ void TFT_eSPI::drawGlyph(uint16_t code) int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; int16_t cx = cursor_x + gdX[gNum]; + int32_t bw = 0; int16_t xs = cx; uint32_t dl = 0; @@ -412,7 +424,15 @@ void TFT_eSPI::drawGlyph(uint16_t code) startWrite(); // Avoid slow ESP32 transaction overhead for every pixel - //if (fg!=bg) fillRect(cursor_x, cursor_y, gxAdvance[gNum], gFont.yAdvance, bg); + if (fg!=bg && _sfbg_enable) + { + bw = (cursor_x + gxAdvance[gNum]) - glyph_xbg; + if (bw > 0) + { + fillRect(glyph_xbg, cursor_y, bw, gFont.maxAscent - gdY[gNum], bg); + fillRect(glyph_xbg, cursor_y + (gFont.maxAscent - gdY[gNum]) + gHeight[gNum], bw, gFont.descent - (gHeight[gNum] - gdY[gNum]), bg); + } + } for (int y = 0; y < gHeight[gNum]; y++) { @@ -432,6 +452,7 @@ void TFT_eSPI::drawGlyph(uint16_t code) } } #endif + drawFastHLine(glyph_xbg, y + cy, bw, bg); for (int x = 0; x < gWidth[gNum]; x++) { #ifdef FONT_FS_AVAILABLE @@ -468,6 +489,8 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (pbuffer) free(pbuffer); cursor_x += gxAdvance[gNum]; + glyph_xbg += bw; + // glyph_1st = false; endWrite(); } else diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 142760a..a0c210e 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -506,6 +506,8 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) textwrapY = false; // Wrap text at bottom of screen when using print stream textdatum = TL_DATUM; // Top Left text alignment is default fontsloaded = 0; + glyph_xbg = 0; // Smooth font scan blanking line start coordinate + // glyph_1st = true; // Not used at the moment, flags blanking adjustment needed _swapBytes = false; // Do not swap colour bytes by default @@ -515,7 +517,8 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) _booted = true; // Default attributes _cp437 = true; _utf8 = true; - + _sfbg_enable = false; + #ifdef FONT_FS_AVAILABLE fs_font = true; // Smooth font filing system or array (fs_font = false) flag #endif @@ -1414,9 +1417,12 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_ // The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse // so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left - *data++ = (tft_Read_8()&0x7E)<<1; - *data++ = (tft_Read_8()&0x7E)<<1; - *data++ = (tft_Read_8()&0x7E)<<1; + //*data++ = (tft_Read_8()&0x7E)<<1; + //*data++ = (tft_Read_8()&0x7E)<<1; + //*data++ = (tft_Read_8()&0x7E)<<1; + *data++ = tft_Read_8(); + *data++ = tft_Read_8(); + *data++ = tft_Read_8(); #endif @@ -1565,9 +1571,12 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // The 6 colour bits are in MS 6 bits of each byte but we do not include the extra clock pulse // so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left - uint8_t r = (tft_Read_8()&0x7E)<<1; - uint8_t g = (tft_Read_8()&0x7E)<<1; - uint8_t b = (tft_Read_8()&0x7E)<<1; + //uint8_t r = (tft_Read_8()&0x7E)<<1; + //uint8_t g = (tft_Read_8()&0x7E)<<1; + //uint8_t b = (tft_Read_8()&0x7E)<<1; + uint8_t r = tft_Read_8(); + uint8_t g = tft_Read_8(); + uint8_t b = tft_Read_8(); color = color565(r, g, b); #endif @@ -3824,7 +3833,10 @@ void TFT_eSPI::setAttribute(uint8_t attr_id, uint8_t param) { #endif _psram_enable = false; break; - //case 4: // TBD future feature control + case SFBG_ENABLE: // Enable glyph by glyph background clearing + _sfbg_enable = param; + break; + //case 5: // TBD future feature control // _tbd = param; // break; } @@ -3843,7 +3855,9 @@ uint8_t TFT_eSPI::getAttribute(uint8_t attr_id) { return _utf8; case PSRAM_ENABLE: return _psram_enable; - //case 3: // TBD future feature control + case SFBG_ENABLE: + return _sfbg_enable; + //case 5: // TBD future feature control // return _tbd; // break; } @@ -4495,7 +4509,8 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 #ifdef SMOOTH_FONT if(fontLoaded) { - if (textcolor!=textbgcolor) fillRect(poX, poY, cwidth, cheight, textbgcolor); + // This line causes flicker - to be replaced by new experimental scanline blanking + if (textcolor!=textbgcolor && !_sfbg_enable) fillRect(poX, poY, cwidth, cheight, textbgcolor); /* // The above only works for a single text line, not if the text is going to wrap... // So need to use code like this in a while loop to fix it: @@ -4507,12 +4522,15 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont); */ setCursor(poX, poY); + glyph_xbg = poX; // Keeps track of next area to clear + // glyph_1st = true; // Flag for first glyph, true means glyph_xbg adjustment required while (n < len) { uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); drawGlyph(uniCode); } sumX += cwidth; + // glyph_1st = false; //fontFile.close(); } else diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 40a2b81..d2ce1f6 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -676,9 +676,11 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // id = 1: Turn on (a=true) or off (a=false) GLCD cp437 font character error correction // id = 2: Turn on (a=true) or off (a=false) UTF8 decoding // id = 3: Enable or disable use of ESP32 PSRAM (if available) + // id = 4: Enable or disable glyph by glyph background clearing to reduce flicker (experimental) #define CP437_SWITCH 1 #define UTF8_SWITCH 2 #define PSRAM_ENABLE 3 + #define SFBG_ENABLE 4 void setAttribute(uint8_t id = 0, uint8_t a = 0); // Set attribute value uint8_t getAttribute(uint8_t id = 0); // Get attribute value @@ -788,6 +790,8 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac uint8_t glyph_ab, // Smooth font glyph delta Y (height) above baseline glyph_bb; // Smooth font glyph delta Y (height) below baseline + int32_t glyph_xbg; // x coordinate for glyph by glyph background clearing (experimental) + //bool glyph_1st; // flags first glyph in a string, since glyph_xbg might need adjusting for italic scripts bool isDigits; // adjust bounding box for numbers to reduce visual jiggling bool textwrapX, textwrapY; // If set, 'wrap' text at right and optionally bottom edge of display @@ -800,6 +804,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac bool _cp437; // If set, use correct CP437 charset (default is ON) bool _utf8; // If set, use UTF-8 decoder in print stream 'write()' function (default ON) bool _psram_enable; // Enable PSRAM use for library functions (TBD) and Sprites + bool _sfbg_enable; // Enable glyph by glyph background clearing (experimental) uint32_t _lastColor; // Buffered value of last colour used