Address #1001 - flicker reduction for smooth fonts

Replace block erase of string area with glyph by glyph scan-line clearing to minimise flicker
This commit is contained in:
Bodmer 2021-02-15 19:20:12 +00:00
parent 04747bcaaa
commit 34c00b12e7
3 changed files with 62 additions and 16 deletions

View File

@ -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

View File

@ -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

View File

@ -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