diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index b2c5e3e..e431cc2 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -359,9 +359,13 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) // Expects file to be open void TFT_eSPI::drawGlyph(uint16_t code) { + uint16_t fg = textcolor; + uint16_t bg = textbgcolor; + if (code < 0x21) { if (code == 0x20) { + //if (fg!=bg) fillRect(cursor_x, cursor_y, gFont.spaceWidth, gFont.yAdvance, bg); cursor_x += gFont.spaceWidth; return; } @@ -377,18 +381,15 @@ void TFT_eSPI::drawGlyph(uint16_t code) uint16_t gNum = 0; bool found = getUnicodeIndex(code, &gNum); - uint16_t fg = textcolor; - uint16_t bg = textbgcolor; - if (found) { - if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > _width)) + if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width())) { cursor_y += gFont.yAdvance; cursor_x = 0; } - if (textwrapY && ((cursor_y + gFont.yAdvance) >= _height)) cursor_y = 0; + if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0; if (cursor_x == 0) cursor_x -= gdX[gNum]; uint8_t* pbuffer = nullptr; @@ -402,15 +403,17 @@ void TFT_eSPI::drawGlyph(uint16_t code) } #endif - int16_t xs = 0; - uint32_t dl = 0; - uint8_t pixel; - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; int16_t cx = cursor_x + gdX[gNum]; + int16_t xs = cx; + uint32_t dl = 0; + uint8_t pixel; + startWrite(); // Avoid slow ESP32 transaction overhead for every pixel + //if (fg!=bg) fillRect(cursor_x, cursor_y, gxAdvance[gNum], gFont.yAdvance, bg); + for (int y = 0; y < gHeight[gNum]; y++) { #ifdef FONT_FS_AVAILABLE diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 7521fed..1395f4b 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -26,6 +26,26 @@ #include "Processors/TFT_eSPI_Generic.c" #endif +// Clipping macro for pushImage +#define PI_CLIP \ + if (_vpOoB) return; \ + x+= _xDatum; \ + y+= _yDatum; \ + \ + if ((x >= _vpW) || (y >= _vpH)) return; \ + \ + int32_t dx = 0; \ + int32_t dy = 0; \ + int32_t dw = w; \ + int32_t dh = h; \ + \ + if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } \ + if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } \ + \ + if ((x + dw) > _vpW ) dw = _vpW - x; \ + if ((y + dh) > _vpH ) dh = _vpH - y; \ + \ + if (dw < 1 || dh < 1) return; /*************************************************************************************** ** Function name: begin_tft_write (was called spi_begin) @@ -91,50 +111,63 @@ inline void TFT_eSPI::begin_tft_read(void){ ***************************************************************************************/ void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum) { - // Set to whole screen in case of error - _xDatum = 0; - _yDatum = 0; - _vpX = 0; - _vpY = 0; - _vpW = _width; - _vpH = _height; + // Viewport + _xDatum = x; // Datum x position in screen coordinates + _yDatum = y; // Datum y position in screen coordinates + _xWidth = w; // Viewport width + _yHeight = h; // Viewport height - _vpDatum = false; + // Clipped viewport + _vpX = 0; // Viewport top left corner x coordinate + _vpY = 0; // Viewport top left corner y coordinate + _vpW = _width; // Equivalent of TFT width (Nb: viewport right edge coord + 1) + _vpH = _height; // Equivalent of TFT height (Nb: viewport bottom edge coord + 1) + _vpDatum = false; // Datum is at top left corner of screen (true = top left of viewport) + _vpOoB = false; // Out of Bounds flag (true is all of viewport is off screen) - // Check if out of bounds - if ((x >= _width) || (y >= _height)) return; + // Clip viewport to screen area + if (x<0) { w += x; x = 0; } + if (y<0) { h += y; y = 0; } + if ((x + w) > _width ) { w = _width - x; } + if ((y + h) > _height) { h = _height - y; } - // Clip - if (x < 0) { x = 0; } - if (y < 0) { y = 0; } + //Serial.print(" x=");Serial.print( x);Serial.print(", y=");Serial.print( y); + //Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h); - if ((x + w) > _width ) w = _width - x; - if ((y + h) > _height) h = _height - y; - - // Check if out of bounds - if (w < 1 || h < 1) return; - - if (vpDatum) - { - _xDatum = x; - _yDatum = y; - _vpX = 0; - _vpY = 0; - _vpW = w; - _vpH = h; - } - else + // Check if viewport is entirely out of bounds + if (w < 1 || h < 1) { + // Set default values and Out of Bounds flag in case of error _xDatum = 0; _yDatum = 0; - _vpX = x; - _vpY = y; - _vpW = x + w; - _vpH = y + h; + _xWidth = _width; + _yHeight = _height; + _vpOoB = true; // Set Out of Bounds flag to inhibit all drawing + return; } + if (!vpDatum) + { + _xDatum = 0; // Reset to top left of screen if not useing a viewport datum + _yDatum = 0; + _xWidth = _width; + _yHeight = _height; + } + + // Store the on screen viewport metrics and datum position + _vpX = x; + _vpY = y; + _vpW = x + w; + _vpH = y + h; _vpDatum = vpDatum; + + //Serial.print(" _xDatum=");Serial.print( _xDatum);Serial.print(", _yDatum=");Serial.print( _yDatum); + //Serial.print(", _xWidth=");Serial.print(_xWidth);Serial.print(", _yHeight=");Serial.println(_yHeight); + + //Serial.print(" _vpX=");Serial.print( _vpX);Serial.print(", _vpY=");Serial.print( _vpY); + //Serial.print(", _vpW=");Serial.print(_vpW);Serial.print(", _vpH=");Serial.println(_vpH); + } /*************************************************************************************** @@ -143,15 +176,18 @@ void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDa ***************************************************************************************/ void TFT_eSPI::resetViewport(void) { - // Set to whole screen + // Reset viewport to the whole screen _xDatum = 0; _yDatum = 0; _vpX = 0; _vpY = 0; _vpW = _width; _vpH = _height; + _xWidth = _width; + _yHeight = _height; _vpDatum = false; + _vpOoB = false; } /*************************************************************************************** @@ -198,10 +234,10 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w) int32_t _hTemp = _vpH; _vpH = _height; bool _dTemp = _vpDatum; _vpDatum = false; - fillRect(_xDatum + _xTemp - w, _yDatum + _yTemp - w, _wTemp - _xTemp + w + w, w, color); - fillRect(_xDatum + _xTemp - w, _yDatum + _yTemp, w, _hTemp -_yTemp, color); - fillRect(_xDatum + _wTemp, _yDatum + _yTemp, w, _hTemp - _yTemp, color); - fillRect(_xDatum + _xTemp - w, _yDatum + _hTemp, _wTemp - _xTemp + w + w, w, color); + fillRect(_xTemp - _xDatum, _yTemp - w - _yDatum, _wTemp - _xTemp + w + w, w, color); + fillRect(_xTemp - w - _xDatum, _yTemp - _yDatum, w, _hTemp - _yTemp, color); + fillRect(_wTemp - _xDatum, _yTemp - _yDatum, w, _hTemp - _yTemp, color); + fillRect(_xTemp - w - _xDatum, _hTemp - _yDatum, _wTemp - _xTemp + w + w, w, color); _vpX = _xTemp; _vpY = _yTemp; @@ -308,13 +344,8 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) _init_width = _width = w; // Set by specific xxxxx_Defines.h file or by users sketch _init_height = _height = h; // Set by specific xxxxx_Defines.h file or by users sketch - // Set display clip window to whole screen - _xDatum = 0; - _yDatum = 0; - _vpX = 0; - _vpY = 0; - _vpW = _width; - _vpH = _height; + // Reset the viewport to the whole screen + resetViewport(); rotation = 0; cursor_y = cursor_x = 0; @@ -626,17 +657,8 @@ void TFT_eSPI::setRotation(uint8_t m) addr_row = 0xFFFF; addr_col = 0xFFFF; - if (!_vpDatum) - { - // Reset viewport to whole screen - _xDatum = 0; - _yDatum = 0; - _vpX = 0; - _vpY = 0; - _vpW = _width; - _vpH = _height; - } - + // Reset the viewport to the whole screen + resetViewport(); } @@ -804,6 +826,19 @@ uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index) ***************************************************************************************/ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) { + if (_vpOoB) return 0; + + x0+= _xDatum; + y0+= _yDatum; + + // Range checking + if ((x0 < _vpX) || (y0 < _vpY) ||(x0 >= _vpW) || (y0 >= _vpH)) return 0; + +#ifdef CGRAM_OFFSET + x0+=colstart; + y0+=rowstart; +#endif + #if defined(TFT_PARALLEL_8_BIT) CS_L; @@ -813,13 +848,15 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); +#if !defined (SSD1963_DRIVER) // Dummy read to throw away don't care value readByte(); +#endif // Fetch the 16 bit BRG pixel //uint16_t rgb = (readByte() << 8) | readByte(); - #if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes + #if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) | defined (SSD1963_DRIVER)// Read 3 bytes // Read window pixel 24 bit RGB values and fill in LS bits uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3); @@ -924,7 +961,21 @@ void TFT_eSPI::setCallback(getColorCallback getCol) ***************************************************************************************/ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { - if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return; + if (_vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + + // Clipping + if ((x >= _vpW) || (y >= _vpH)) return; + + if (x < _vpX) { w += x - _vpX; x = _vpX; } + if (y < _vpY) { h += y - _vpY; y = _vpY; } + + if ((x + w) > _vpW) w = _vpW - x; + if ((y + h) > _vpH) h = _vpH - y; + + if ((w < 1) || (h < 1)) return; #if defined(TFT_PARALLEL_8_BIT) @@ -935,13 +986,13 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); - // Dummy read to throw away don't care value - readByte(); - // Total pixel count uint32_t len = w * h; #if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes + // Dummy read to throw away don't care value + readByte(); + // Fetch the 24 bit RGB value while (len--) { // Assemble the RGB 16 bit colour @@ -950,7 +1001,23 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Swapped byte order for compatibility with pushRect() *data++ = (rgb<<8) | (rgb>>8); } + + #elif defined (SSD1963_DRIVER) + // Fetch the 18 bit BRG pixels + while (len--) { + uint16_t bgr = ((readByte() & 0xF8) >> 3);; // CS_L adds a small delay + bgr |= ((readByte() & 0xFC) << 3); + bgr |= (readByte() << 8); + // Swap Red and Blue (could check MADCTL setting to see if this is needed) + uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0); + // Swapped byte order for compatibility with pushRect() + *data++ = (rgb<<8) | (rgb>>8); + } + #else // ILI9481 reads as 16 bits + // Dummy read to throw away don't care value + readByte(); + // Fetch the 16 bit BRG pixels while (len--) { #ifdef ILI9486_DRIVER @@ -1049,21 +1116,7 @@ void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { - - if ((x >= _vpW) || (y >= _vpH)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; + PI_CLIP; begin_tft_write(); inTransaction = true; @@ -1093,21 +1146,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transp) { - - if ((x >= _vpW) || (y >= _vpH)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; + PI_CLIP; begin_tft_write(); inTransaction = true; @@ -1167,20 +1206,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) { // Requires 32 bit aligned access, so use PROGMEM 16 bit word functions - if ((x >= _vpW) || (y >= _vpH)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; + PI_CLIP; begin_tft_write(); inTransaction = true; @@ -1203,7 +1229,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 end_tft_write(); } - /*************************************************************************************** ** Function name: pushImage - for FLASH (PROGMEM) stored images ** Description: plot 16 bit image with 1 colour being transparent @@ -1211,20 +1236,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transp) { // Requires 32 bit aligned access, so use PROGMEM 16 bit word functions - if ((x >= _vpW) || (y >= _vpH)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; + PI_CLIP; begin_tft_write(); inTransaction = true; @@ -1280,21 +1292,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8, uint16_t *cmap) { - - if ((x >= _vpW) || (y >= _vpH)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; + PI_CLIP; begin_tft_write(); inTransaction = true; @@ -1437,20 +1435,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da ***************************************************************************************/ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transp, bool bpp8, uint16_t *cmap) { - if ((x >= _vpW) || (y >= _vpH)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; + PI_CLIP; begin_tft_write(); inTransaction = true; @@ -2476,8 +2461,7 @@ uint8_t TFT_eSPI::getTextDatum(void) // Return the size of the display (per current rotation) int16_t TFT_eSPI::width(void) { - if (_vpDatum) return _vpW - _vpX; - else return _width; + return _xWidth; } @@ -2487,8 +2471,7 @@ int16_t TFT_eSPI::width(void) ***************************************************************************************/ int16_t TFT_eSPI::height(void) { - if (_vpDatum) return _vpH - _vpY; - else return _height; + return _yHeight; } @@ -2628,28 +2611,34 @@ int16_t TFT_eSPI::fontHeight(void) ***************************************************************************************/ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) { - if ((x >= _vpW) || // Clip right - (y >= _vpH) || // Clip bottom - ((x + 6 * size - 1) < _vpX) || // Clip left - ((y + 8 * size - 1) < _vpY)) // Clip top - return; + if (_vpOoB) return; + + int32_t xd = x + _xDatum; + int32_t yd = y + _yDatum; if (c < 32) return; #ifdef LOAD_GLCD //>>>>>>>>>>>>>>>>>> -#ifdef LOAD_GFXFF + #ifdef LOAD_GFXFF if(!gfxFont) { // 'Classic' built-in font -#endif + #endif //>>>>>>>>>>>>>>>>>> - bool fillbg = (bg != color); + if ((xd >= _vpW) || // Clip right + ( yd >= _vpH) || // Clip bottom + ((xd + 6 * size - 1) < _vpX) || // Clip left + ((yd + 8 * size - 1) < _vpY)) // Clip top + return; - if ((size==1) && fillbg && x >= _vpX && (x + 6 * size - 1) < _vpW) { + bool fillbg = (bg != color); + bool clip = xd < _vpX || xd + 6 * textsize >= _vpW || yd < _vpY || yd + 8 * textsize >= _vpH; + + if ((size==1) && fillbg && !clip) { uint8_t column[6]; uint8_t mask = 0x1; begin_tft_write(); - setWindow(x, y, x+5, y+8); + setWindow(xd, yd, xd+5, yd+8); for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); column[5] = 0; @@ -2668,6 +2657,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 else { //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() inTransaction = true; + for (int8_t i = 0; i < 6; i++ ) { uint8_t line; if (i == 5) @@ -2694,9 +2684,9 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 } //>>>>>>>>>>>>>>>>>>>>>>>>>>> -#ifdef LOAD_GFXFF + #ifdef LOAD_GFXFF } else { // Custom font -#endif + #endif //>>>>>>>>>>>>>>>>>>>>>>>>>>> #endif // LOAD_GLCD @@ -2789,14 +2779,6 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { //begin_tft_write(); // Must be called before setWindow - if( _vpDatum) - { - x0+= _xDatum; - x1+= _xDatum; - y0+= _yDatum; - y1+= _yDatum; - } - #if defined (SSD1963_DRIVER) if ((rotation & 0x1) == 0) { swap_coord(x0, y0); swap_coord(x1, y1); } #endif @@ -2870,15 +2852,14 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) ***************************************************************************************/ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) { + if (_vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + // Range checking if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return; - if( _vpDatum) - { - x+= _xDatum; - y+= _yDatum; - } - #ifdef CGRAM_OFFSET x+=colstart; y+=rowstart; @@ -3077,6 +3058,11 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t ***************************************************************************************/ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { + if (_vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + // Clipping if ((x < _vpX) || (x >= _vpW) || (y >= _vpH)) return; @@ -3102,6 +3088,11 @@ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) ***************************************************************************************/ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) { + if (_vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + // Clipping if ((y < _vpY) || (x >= _vpW) || (y >= _vpH)) return; @@ -3127,6 +3118,11 @@ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) ***************************************************************************************/ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { + if (_vpOoB) return; + + x+= _xDatum; + y+= _yDatum; + // Clipping if ((x >= _vpW) || (y >= _vpH)) return; @@ -3138,6 +3134,15 @@ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col if ((w < 1) || (h < 1)) return; + //Serial.print(" _xDatum=");Serial.print( _xDatum);Serial.print(", _yDatum=");Serial.print( _yDatum); + //Serial.print(", _xWidth=");Serial.print(_xWidth);Serial.print(", _yHeight=");Serial.println(_yHeight); + + //Serial.print(" _vpX=");Serial.print( _vpX);Serial.print(", _vpY=");Serial.print( _vpY); + //Serial.print(", _vpW=");Serial.print(_vpW);Serial.print(", _vpH=");Serial.println(_vpH); + + //Serial.print(" x=");Serial.print( y);Serial.print(", y=");Serial.print( y); + //Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h); + begin_tft_write(); setWindow(x, y, x + w - 1, y + h - 1); @@ -3581,7 +3586,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y) // Any UTF-8 decoding must be done before calling drawChar() int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) { - if (!uniCode) return 0; + if (_vpOoB || !uniCode) return 0; if (font==1) { #ifdef LOAD_GLCD @@ -3645,19 +3650,23 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } #endif - if (x + width * textsize < (int16_t)_vpX || x >= _vpW) return width * textsize ; + int32_t xd = x + _xDatum; + int32_t yd = y + _yDatum; + + if ((xd + width * textsize < _vpX || xd >= _vpW) && (yd + height * textsize < _vpY || yd >= _vpH)) return width * textsize ; int32_t w = width; int32_t pX = 0; int32_t pY = y; uint8_t line = 0; + bool clip = xd < _vpX || xd + width * textsize >= _vpW || yd < _vpY || yd + height * textsize >= _vpH; #ifdef LOAD_FONT2 // chop out code if we do not need it if (font == 2) { w = w + 6; // Should be + 7 but we need to compensate for width increment w = w / 8; - if (textcolor == textbgcolor || textsize != 1 || x < _vpX || x + width * textsize >= _vpW) { + if (textcolor == textbgcolor || textsize != 1 || clip) { //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() inTransaction = true; @@ -3698,9 +3707,10 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) end_tft_write(); } else { // Faster drawing of characters and background using block write + begin_tft_write(); - setWindow(x, y, x + width - 1, y + height - 1); + setWindow(xd, yd, xd + width - 1, yd + height - 1); uint8_t mask; for (int32_t i = 0; i < height; i++) { @@ -3734,7 +3744,8 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) inTransaction = true; w *= height; // Now w is total number of pixels in the character - if (textcolor == textbgcolor && x >= _vpX && x + width * textsize <= _vpW) { + if (textcolor == textbgcolor && !clip) { + int32_t px = 0, py = pY; // To hold character block start and end column and row values int32_t pc = 0; // Pixel count uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel @@ -3750,12 +3761,12 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) line &= 0x7F; line++; if (ts) { - px = x + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow - py = y + textsize * (pc / width); + px = xd + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow + py = yd + textsize * (pc / width); } else { - px = x + pc % width; // Keep these px and py calculations outside the loop as they are slow - py = y + pc / width; + px = xd + pc % width; // Keep these px and py calculations outside the loop as they are slow + py = yd + pc / width; } while (line--) { // In this case the while(line--) is faster pc++; // This is faster than putting pc+=line before while()? @@ -3768,8 +3779,8 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) else {tft_Write_16(textcolor);} px += textsize; - if (px >= (x + width * textsize)) { - px = x; + if (px >= (xd + width * textsize)) { + px = xd; py += textsize; } } @@ -3781,11 +3792,11 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } } else { - // Text colour != background and textsize = 1 and character is within screen area + // Text colour != background and textsize = 1 and character is within viewport area // so use faster drawing of characters and background using block write - if (textsize == 1 && x >= _vpX && x + width <= _vpW) + if (textcolor != textbgcolor && textsize == 1 && !clip) { - setWindow(x, y, x + width - 1, y + height - 1); + setWindow(xd, yd, xd + width - 1, yd + height - 1); // Maximum font size is equivalent to 180x180 pixels in area while (w > 0) { @@ -3969,11 +3980,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 padding += 2; break; } -/* // Check coordinates are OK, adjust if not - if (poX < 0) poX = 0; - if (poX+cwidth > width()) poX = width() - cwidth; - if (poY < 0) poY = 0; - if (poY+cheight-baseline> height()) poY = height() - cheight; //*/ } @@ -4010,7 +4016,16 @@ 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); - +/* + // 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: + if (textwrapX && (cursor_x + width * textsize > this->width())) { + cursor_y += height; + cursor_x = 0; + } + if (textwrapY && (cursor_y >= (int32_t)this->height())) cursor_y = 0; + cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont); +*/ setCursor(poX, poY); while (n < len) { diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 358fc89..8d51999 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.3.0" +#define TFT_ESPI_VERSION "2.3.1" /*************************************************************************************** ** Section 1: Load required header files @@ -736,10 +736,13 @@ class TFT_eSPI : public Print { int32_t addr_row, addr_col; // Window position - used to minimise window commands // Viewport variables - int32_t _vpX, _vpY, _vpW, _vpH; + int32_t _vpX, _vpY, _vpW, _vpH; // Note: x start, y start, x end + 1, y end + 1 int32_t _xDatum; int32_t _yDatum; + int32_t _xWidth; + int32_t _yHeight; bool _vpDatum; + bool _vpOoB; uint32_t fontsloaded; // Bit field of fonts loaded diff --git a/examples/160 x 128/TFT_Char_times/TFT_Char_times.ino b/examples/160 x 128/TFT_Char_times/TFT_Char_times.ino index 5e4d3a8..1ab0a1c 100644 --- a/examples/160 x 128/TFT_Char_times/TFT_Char_times.ino +++ b/examples/160 x 128/TFT_Char_times/TFT_Char_times.ino @@ -45,12 +45,11 @@ void loop() { tft.setTextColor(TFT_RED, TFT_BLACK); tft.drawFloat(drawTime / 2890.0, 3, 0, 80, 4); - if (drawTime < 100) tft.drawString("Font 1 not loaded!", 0, 108, 2); - + delay(4000); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - drawTime = millis(); + drawTime = millis(); for (int i = 0; i < 1000; i++) { tft.drawNumber(i, 0, 0, 2); @@ -60,12 +59,11 @@ void loop() { tft.setTextColor(TFT_RED, TFT_BLACK); tft.drawFloat(drawTime / 2890.0, 3, 0, 80, 4); - if (drawTime < 200) tft.drawString("Font 2 not loaded!", 0, 108, 2); - + delay(4000); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - drawTime = millis(); + drawTime = millis(); for (int i = 0; i < 1000; i++) { tft.drawNumber(i, 0, 0, 4); @@ -75,12 +73,11 @@ void loop() { tft.setTextColor(TFT_RED, TFT_BLACK); tft.drawFloat(drawTime / 2890.0, 3, 0, 80, 4); - if (drawTime < 200) tft.drawString("Font 4 not loaded!", 0, 108, 2); - + delay(4000); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - drawTime = millis(); + drawTime = millis(); for (int i = 0; i < 1000; i++) { yield(); tft.drawNumber(i, 0, 0, 6); @@ -90,12 +87,11 @@ void loop() { tft.setTextColor(TFT_RED, TFT_BLACK); tft.drawFloat(drawTime / 2890.0, 3, 0, 80, 4); - if (drawTime < 200) tft.drawString("Font 6 not loaded!", 0, 108, 2); - + delay(4000); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - drawTime = millis(); + drawTime = millis(); for (int i = 0; i < 1000; i++) { yield(); tft.drawNumber(i, 0, 0, 7); @@ -105,12 +101,11 @@ void loop() { tft.setTextColor(TFT_RED, TFT_BLACK); tft.drawFloat(drawTime / 2890.0, 3, 0, 80, 4); - if (drawTime < 200) tft.drawString("Font 7 not loaded!", 0, 108, 2); - + delay(4000); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE, TFT_BLACK); - drawTime = millis(); + drawTime = millis(); for (int i = 0; i < 100; i++) { yield(); tft.drawNumber(i, 0, 0, 8); @@ -120,8 +115,7 @@ void loop() { tft.setTextColor(TFT_RED, TFT_BLACK); tft.drawFloat(drawTime / 190.0, 3, 0, 80, 4); - if (drawTime < 200) tft.drawString("Font 8 not loaded!", 0, 108, 2); - + delay(4000); } diff --git a/examples/Sprite/Animated_dial/Animated_dial.ino b/examples/Sprite/Animated_dial/Animated_dial.ino index 33b7d50..9ecd5b9 100644 --- a/examples/Sprite/Animated_dial/Animated_dial.ino +++ b/examples/Sprite/Animated_dial/Animated_dial.ino @@ -89,7 +89,7 @@ void setup() { spr.setTextColor(TFT_WHITE, bg_color); spr.setTextDatum(MC_DATUM); spr.setTextPadding(spr_width); - spr.drawNumber(0, spr_width/2, 0); + spr.drawNumber(0, spr_width/2, spr.fontHeight()/2); spr.pushSprite(DIAL_CENTRE_X - spr_width / 2, DIAL_CENTRE_Y - spr.fontHeight() / 2); // Plot the label text @@ -203,7 +203,7 @@ void plotNeedle(int16_t angle, uint16_t ms_delay) } // Update the number at the centre of the dial - spr.drawNumber(old_angle+120, spr_width/2, 0); + spr.drawNumber(old_angle+120, spr_width/2, spr.fontHeight()/2); spr.pushSprite(120 - spr_width / 2, 120 - spr.fontHeight() / 2); // Slow needle down slightly as it approaches the new position diff --git a/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino b/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino index 5bc3ffe..a6a0a6a 100644 --- a/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino +++ b/examples/Sprite/Rotated_Sprite_1/Rotated_Sprite_1.ino @@ -132,7 +132,7 @@ void loop() { for (int16_t angle = 30; angle <= 360; angle += 30) { spr.fillSprite(TFT_BLACK); // Clear the Sprite - spr.drawNumber(num, 20, 15, 4); // Plot number, in Sprite at 15,15 and with font 4 + spr.drawNumber(num, 20, 15, 4); // Plot number, in Sprite at 20,15 and with font 4 spr.pushRotated(angle, TFT_BLACK); // Plot rotated Sprite, black being transparent num++; } @@ -143,7 +143,7 @@ void loop() { for (int16_t angle = -90; angle < 270; angle += 30) { spr.fillSprite(TFT_BLACK); // Clear the Sprite - spr.drawNumber(angle+90, 15, 15, 4); // Plot number, in Sprite at 15,15 and with font 4 + spr.drawNumber(angle+90, 20, 15, 4); // Plot number, in Sprite at 20,15 and with font 4 spr.pushRotated(angle, TFT_BLACK); // Plot rotated Sprite, black being transparent num++; } diff --git a/library.json b/library.json index f69a014..52c5229 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.3.0", + "version": "2.3.1", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 749db4f..046ede3 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.3.0 +version=2.3.1 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32