Merge pull request #778 from Bodmer/Viewport

Add viewport feature
This commit is contained in:
Bodmer
2020-10-13 13:37:23 +01:00
committed by GitHub
18 changed files with 1014 additions and 206 deletions

View File

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

View File

@@ -843,9 +843,9 @@ bool TFT_eSprite::pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int
_tft->pushImage(tx, ty, sw, sh, _img4 + (_iwidth>>1) * _ys, false, _colorMap );
else // Render line by line
{
uint32_t ds = _xs&1; // Odd x start pixel
int32_t ds = _xs&1; // Odd x start pixel
uint32_t de = 0; // Odd x end pixel
int32_t de = 0; // Odd x end pixel
if ((sw > ds) && (_xe&1)) de = 1;
uint32_t dm = 0; // Midsection pixel count
@@ -877,7 +877,7 @@ bool TFT_eSprite::pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int
_tft->setWindow(tx, ty, tx+sw-1, ty+sh-1);
while (sh--)
{
for (uint32_t dx = _xs; dx < _xs + sw; dx++) _tft->pushColor(readPixel(dx, _ys));
for (int32_t dx = _xs; dx < _xs + sw; dx++) _tft->pushColor(readPixel(dx, _ys));
ty++;
_ys++;
}

View File

@@ -575,18 +575,18 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
// This will clip and also swap bytes if setSwapBytes(true) was called by sketch
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer)
{
if ((x >= _width) || (y >= _height) || (!DMA_Enabled)) return;
if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; }
if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if ((x + dw) > _vpW ) dw = _vpW - x;
if ((y + dh) > _vpH ) dh = _vpH - y;
if (dw < 1 || dh < 1) return;

View File

@@ -437,18 +437,18 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
// This will clip and also swap bytes if setSwapBytes(true) was called by sketch
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer)
{
if ((x >= _width) || (y >= _height)) return;
if ((x >= _vpW) || (y >= _vpH)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; }
if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if ((x + dw) > _vpW ) dw = _vpW - x;
if ((y + dh) > _vpH ) dh = _vpH - y;
if (dw < 1 || dh < 1) return;

View File

@@ -2,23 +2,24 @@
The Sprite class has been updated to remove an inconsistency for the setSwapBytes() function. Although all the examples are unchanged, user sketches may be affected. If the colors of the sprite change when loading this new version 2.2.16 then it may be necessary to change the swap bytes setting, e.g. for a sprite instance "spr" use either: spr.setSwapBytes(true) or spr.setSwapBytes(false) to correct the colour.
# News
1. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI.
1. The library now provides a "viewport" capability. See "Viewport_Demo" and "Viewport_graphicstest" examples. When a viewport is defined grpahics will only appear within that window. The coordinate datum by default moves to the top left corner of the viewport, but can optionally remain at top left corner of TFT. The GUIslice library will make use of this feature to spped up the rendering of GUI objects (see #769).
2. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488).
2. The library now supports SSD1963 based screen, this has been tested on a [480x800 screen](https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu) with an ESP32. The interface is 8 bit parallel only as that controller does not support a SPI interface.
3. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h".
3. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI.
4. A new "Animated_dial" example has been added to show how dials can be created using a rotated Sprite for the needle. To run this example the TFT must support reading from the screen RAM. The dial rim and scale is a jpeg image, created using a paint program.
4. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488).
5. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h".
6. A new "Animated_dial" example has been added to show how dials can be created using a rotated Sprite for the needle. To run this example the TFT must support reading from the screen RAM. The dial rim and scale is a jpeg image, created using a paint program.
![Animated_dial](https://i.imgur.com/S736Rg6.png)
5. Anti-aliased (smooth) fonts can now be stored as arrays in FLASH (program) memory. This means that processors such as STM32 that do not have SPIFFS support can use the fonts. The processor must have sufficient FLASH memory to store the fonts used.
7. Anti-aliased (smooth) fonts can now be stored as arrays in FLASH (program) memory. This means that processors such as STM32 that do not have SPIFFS support can use the fonts. The processor must have sufficient FLASH memory to store the fonts used.
6. The Sprite class now supports 4 bits per pixel with a 16 color palette. Three new examples have been added.
8. The Sprite class now supports 4 bits per pixel with a 16 color palette. Three new examples have been added.
7. The library has been upgraded to support STM32 processors when used with SPI or 8 bit parallel displays. DMA capability for SPI displays has been added for STM32F103 (e.g. "Blue Pill") and STM32F2xx/4xx/7xx (e.g. 32/64/144 Nucleo boards). New DMA demo examples have been added (for STM32 only).
8. The ST7796 display controller has been added. The ST7796 RPi MHS-4.0 inch Display-B type display is supported (this is fast for a SPI display as an ESP32 can clock it at 80MHz (ESP8266 at 40MHz)), see setups 27 and 28.
# TFT_eSPI

View File

@@ -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)
@@ -85,6 +105,204 @@ inline void TFT_eSPI::begin_tft_read(void){
SET_BUS_READ_MODE;
}
/***************************************************************************************
** Function name: setViewport
** Description: Set the clipping region for the TFT screen
***************************************************************************************/
void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum)
{
// 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
// 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)
// 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; }
//Serial.print(" x=");Serial.print( x);Serial.print(", y=");Serial.print( y);
//Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h);
// 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;
_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);
}
/***************************************************************************************
** Function name: checkViewport
** Description: Check if any part of specified area is visible in viewport
***************************************************************************************/
// Note: Setting w and h to 1 will check if coordinate x,y is in area
bool TFT_eSPI::checkViewport(int32_t x, int32_t y, int32_t w, int32_t h)
{
if (_vpOoB) return false;
x+= _xDatum;
y+= _yDatum;
if ((x >= _vpW) || (y >= _vpH)) return false;
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 false;
return true;
}
/***************************************************************************************
** Function name: resetViewport
** Description: Reset viewport to whle TFT screen, datum at 0,0
***************************************************************************************/
void TFT_eSPI::resetViewport(void)
{
// 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;
}
/***************************************************************************************
** Function name: getViewportX
** Description: Get x position of the viewport
***************************************************************************************/
int32_t TFT_eSPI::getViewportX(void)
{
return _xDatum;
}
/***************************************************************************************
** Function name: getViewportY
** Description: Get y position of the viewport
***************************************************************************************/
int32_t TFT_eSPI::getViewportY(void)
{
return _yDatum;
}
/***************************************************************************************
** Function name: getViewportWidth
** Description: Get width of the viewport
***************************************************************************************/
int32_t TFT_eSPI::getViewportWidth(void)
{
return _vpW - _vpX;
}
/***************************************************************************************
** Function name: getViewportHeight
** Description: Get height of the viewport
***************************************************************************************/
int32_t TFT_eSPI::getViewportHeight(void)
{
return _vpH - _vpY;
}
/***************************************************************************************
** Function name: getViewportDatum
** Description: Get datum of the viewport (true = viewport corner)
***************************************************************************************/
bool TFT_eSPI::getViewportDatum(void)
{
return _vpDatum;
}
/***************************************************************************************
** Function name: frameViewport
** Description: Draw a frame inside or outside the viewport of width w
***************************************************************************************/
void TFT_eSPI::frameViewport(uint16_t color, int32_t w)
{
// If w is positive the frame is drawn inside the viewport
// a large positive width will clear the screen inside the viewport
if (w>0)
{
fillRect(_vpX, _vpY, _vpW - _vpX, w, color);
fillRect(_vpX, _vpY + w, w, _vpH - _vpY - w - w, color);
fillRect(_vpW - w, _vpY + w, w, _vpH - _vpY - w - w, color);
fillRect(_vpX, _vpH - w, _vpW - _vpX, w, color);
}
else
// If w is negative the frame is drawn outside the viewport
// a large negative width will clear the screen outside the viewport
{
w = -w;
int32_t _xTemp = _vpX; _vpX = 0;
int32_t _yTemp = _vpY; _vpY = 0;
int32_t _wTemp = _vpW; _vpW = _width;
int32_t _hTemp = _vpH; _vpH = _height;
bool _dTemp = _vpDatum; _vpDatum = false;
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;
_vpW = _wTemp;
_vpH = _hTemp;
_vpDatum = _dTemp;
}
}
/***************************************************************************************
** Function name: end_tft_read (was called spi_end_read)
** Description: End transaction for reads and deselect TFT
@@ -181,6 +399,10 @@ 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
// Reset the viewport to the whole screen
resetViewport();
rotation = 0;
cursor_y = cursor_x = 0;
textfont = 1;
@@ -490,6 +712,9 @@ void TFT_eSPI::setRotation(uint8_t m)
addr_row = 0xFFFF;
addr_col = 0xFFFF;
// Reset the viewport to the whole screen
resetViewport();
}
@@ -657,6 +882,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;
@@ -666,13 +904,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);
@@ -777,7 +1017,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)
@@ -788,13 +1042,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
@@ -803,7 +1057,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
@@ -902,21 +1172,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 >= _width) || (y >= _height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
PI_CLIP;
begin_tft_write();
inTransaction = true;
@@ -946,21 +1202,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 >= _width) || (y >= _height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
PI_CLIP;
begin_tft_write();
inTransaction = true;
@@ -1020,20 +1262,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 >= _width) || (y >= _height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
PI_CLIP;
begin_tft_write();
inTransaction = true;
@@ -1056,7 +1285,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
@@ -1064,20 +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, const uint16_t *data, uint16_t transp)
{
// Requires 32 bit aligned access, so use PROGMEM 16 bit word functions
if ((x >= _width) || (y >= (int32_t)_height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
PI_CLIP;
begin_tft_write();
inTransaction = true;
@@ -1133,21 +1348,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 >= _width) || (y >= (int32_t)_height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
PI_CLIP;
begin_tft_write();
inTransaction = true;
@@ -1290,20 +1491,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 >= _width) || (y >= _height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
PI_CLIP;
begin_tft_write();
inTransaction = true;
@@ -2329,7 +2517,7 @@ uint8_t TFT_eSPI::getTextDatum(void)
// Return the size of the display (per current rotation)
int16_t TFT_eSPI::width(void)
{
return _width;
return _xWidth;
}
@@ -2339,7 +2527,7 @@ int16_t TFT_eSPI::width(void)
***************************************************************************************/
int16_t TFT_eSPI::height(void)
{
return _height;
return _yHeight;
}
@@ -2479,28 +2667,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 >= _width) || // Clip right
(y >= _height) || // Clip bottom
((x + 6 * size - 1) < 0) || // Clip left
((y + 8 * size - 1) < 0)) // 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) {
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;
@@ -2519,6 +2713,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)
@@ -2526,13 +2721,13 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32
else
line = pgm_read_byte(font + (c * 5) + i);
if (size == 1) { // default size
if (size == 1 && !fillbg) { // default size
for (int8_t j = 0; j < 8; j++) {
if (line & 0x1) drawPixel(x + i, y + j, color);
line >>= 1;
}
}
else { // big size
else { // big size or clipped
for (int8_t j = 0; j < 8; j++) {
if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color);
else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg);
@@ -2545,9 +2740,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
@@ -2713,8 +2908,13 @@ 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 < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return;
if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return;
#ifdef CGRAM_OFFSET
x+=colstart;
@@ -2914,12 +3114,17 @@ 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 < 0) || (x >= _width) || (y >= _height)) return;
if ((x < _vpX) || (x >= _vpW) || (y >= _vpH)) return;
if (y < 0) { h += y; y = 0; }
if (y < _vpY) { h += y - _vpY; y = _vpY; }
if ((y + h) > _height) h = _height - y;
if ((y + h) > _vpH) h = _vpH - y;
if (h < 1) return;
@@ -2939,12 +3144,17 @@ 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 < 0) || (x >= _width) || (y >= _height)) return;
if ((y < _vpY) || (x >= _vpW) || (y >= _vpH)) return;
if (x < 0) { w += x; x = 0; }
if (x < _vpX) { w += x - _vpX; x = _vpX; }
if ((x + w) > _width) w = _width - x;
if ((x + w) > _vpW) w = _vpW - x;
if (w < 1) return;
@@ -2964,17 +3174,31 @@ 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 >= _width) || (y >= _height)) return;
if ((x >= _vpW) || (y >= _vpH)) return;
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
if (x < _vpX) { w += x - _vpX; x = _vpX; }
if (y < _vpY) { h += y - _vpY; y = _vpY; }
if ((x + w) > _width) w = _width - x;
if ((y + h) > _height) h = _height - y;
if ((x + w) > _vpW) w = _vpW - x;
if ((y + h) > _vpH) h = _vpH - y;
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);
@@ -3359,11 +3583,11 @@ size_t TFT_eSPI::write(uint8_t utf8)
cursor_x = 0;
}
else {
if (textwrapX && (cursor_x + width * textsize > _width)) {
if (textwrapX && (cursor_x + width * textsize > this->width())) {
cursor_y += height;
cursor_x = 0;
}
if (textwrapY && (cursor_y >= (int32_t)_height)) cursor_y = 0;
if (textwrapY && (cursor_y >= (int32_t)this->height())) cursor_y = 0;
cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont);
}
@@ -3386,13 +3610,13 @@ size_t TFT_eSPI::write(uint8_t utf8)
h = pgm_read_byte(&glyph->height);
if((w > 0) && (h > 0)) { // Is there an associated bitmap?
int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset);
if(textwrapX && ((cursor_x + textsize * (xo + w)) > _width)) {
if(textwrapX && ((cursor_x + textsize * (xo + w)) > this->width())) {
// Drawing character would go off right edge; wrap to new line
cursor_x = 0;
cursor_y += (int16_t)textsize *
(uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
if (textwrapY && (cursor_y >= (int32_t)_height)) cursor_y = 0;
if (textwrapY && (cursor_y >= (int32_t)this->height())) cursor_y = 0;
drawChar(cursor_x, cursor_y, uniCode, textcolor, textbgcolor, textsize);
}
cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
@@ -3418,7 +3642,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
@@ -3482,18 +3706,23 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
}
#endif
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 (x + width * textsize >= (int16_t)_width) return width * textsize ;
if (textcolor == textbgcolor || textsize != 1) {
if (textcolor == textbgcolor || textsize != 1 || clip) {
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
@@ -3534,9 +3763,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++) {
@@ -3570,7 +3800,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) {
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
@@ -3586,12 +3817,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()?
@@ -3604,8 +3835,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;
}
}
@@ -3617,11 +3848,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 >= 0) && (x + width <= _width) && (y >= 0) && (y + height <= _height))
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) {
@@ -3644,12 +3875,12 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
int32_t pc = 0; // Pixel count
int32_t pl = 0; // Pixel line length
uint16_t pcol = 0; // Pixel color
bool pf = true; // Flag for plotting
while (pc < w) {
line = pgm_read_byte((uint8_t *)flash_address);
flash_address++;
if (line & 0x80) { pcol = textcolor; line &= 0x7F; }
else pcol = textbgcolor;
if (line & 0x80) { pcol = textcolor; line &= 0x7F; pf = true;}
else { pcol = textbgcolor; if (textcolor == textbgcolor) pf = false;}
line++;
px = pc % width;
tx = x + textsize * px;
@@ -3661,7 +3892,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
while (line--) {
pl++;
if ((px+pl) >= width) {
fillRect(tx, ty, pl * textsize, textsize, pcol);
if (pf) fillRect(tx, ty, pl * textsize, textsize, pcol);
pl = 0;
px = 0;
tx = x;
@@ -3669,7 +3900,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
ty += textsize;
}
}
if (pl) fillRect(tx, ty, pl * textsize, textsize, pcol);
if (pl && pf) fillRect(tx, ty, pl * textsize, textsize, pcol);
}
}
}
@@ -3805,11 +4036,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; //*/
}
@@ -3846,7 +4072,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) {

View File

@@ -16,7 +16,11 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.2.23"
#define TFT_ESPI_VERSION "2.3.2"
// Bit level feature flags
// Bit 0 set: viewport capability
#define TFT_ESPI_FEATURES 1
/***************************************************************************************
** Section 1: Load required header files
@@ -390,6 +394,17 @@ class TFT_eSPI : public Print {
void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h), // Note: start coordinates + width and height
setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates
// Viewport commands, see "Viewport_Demo" sketch
void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true);
bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h);
int32_t getViewportX(void);
int32_t getViewportY(void);
int32_t getViewportWidth(void);
int32_t getViewportHeight(void);
bool getViewportDatum(void);
void frameViewport(uint16_t color, int32_t w);
void resetViewport(void);
// Push (aka write pixel) colours to the TFT (use setAddrWindow() first)
void pushColor(uint16_t color),
pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock()
@@ -728,6 +743,15 @@ class TFT_eSPI : public Print {
int32_t _width, _height; // Display w/h as modified by current rotation
int32_t addr_row, addr_col; // Window position - used to minimise window commands
// Viewport variables
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
uint8_t glyph_ab, // Smooth font glyph delta Y (height) above baseline

View File

@@ -20,7 +20,10 @@
//#define SSD1963_480_DRIVER // 272 x 480 display
//#define SSD1963_800_DRIVER // 480 x 800 display
//#define SSD1963_800ALT_DRIVER // Alternative 480 x 800 display
#define SSD1963_800BD_DRIVER // 480 x 800 displau sourced from https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu
#define SSD1963_800BD_DRIVER // 480 x 800 display sourced from https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu
//#define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
// ##################################################################################
//

View File

@@ -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);
}

View File

@@ -311,7 +311,7 @@ void loop()
// It takes 30ms to calculate the 30,000 random numbers so this is not a true drawPixel speed test
for (int i=0; i<10000; i++)
{
myGLCD.drawPixel(2+random(316), 16+random(209),random(0xFFFF));
myGLCD.drawPixel(2+random(TFT_W - 3), 16+random(TFT_H - 31),random(0xFFFF));
}
#else
// Draw 10,000 pixels to fill a 100x100 pixel box, better drawPixel speed test

View File

@@ -20,7 +20,7 @@ uint8_t __attribute__((always_inline)) rng()
zx++;
za = (za^zc^zx);
zb = (zb+za);
zc = (zc+(zb>>1)^za);
zc = ((zc+(zb>>1))^za);
return zc;
}

View File

@@ -0,0 +1,116 @@
// Viewport Demo
// See viewport_commands tab for details of functions available
// This example uses the viewport commands to create a "virtual TFT" within the
// normal TFT display area. This allows a sketch written for a smaller screen to
// be run in a viewport window. By default, the graphics 0,0 datum is set to the
// top left corner of the viewport, but optionally the datum can be kept at the
// corner of the TFT.
// Viewports have a number of potential uses:
// - create a "virtual" TFT screen smaller than the actual TFT screen
// - render GUI items (menus etc) in a viewport, erase GUI item by redrawing whole screen,
// this will be fast because only the viewport will be refreshed (e.g. clearing menu)
// - limit screen refresh to a particular area, e.g. changing numbers, icons or graph plotting
// - showing a small portion of a larger image or sprite, this allows panning and scrolling
// A viewport can have the coordinate datum (position 0,0) either at the top left corner of
// the viewport or at the normal top left corner of the TFT.
// Putting the coordinate datum at the viewport corner means that functions that draw graphics
// in a fixed position can be relocated anywhere on the screen. (see plotBox() below). This
// makes it easier to reposition groups of graphical objects (for example GUI buttons) that have
// fixed relative positions.
// The viewport position x, and y coordinates and viewport bounds must be constrained by the
// user sketch to be within the screen boundaries.
#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
}
void loop()
{
// Normal Screen
drawX();
delay(2000);
// Viewport screen
tft.setViewport(10, 10, 140, 100);
tft.frameViewport(TFT_NAVY, -2);
tft.fillScreen(TFT_BLACK);
drawX();
tft.resetViewport();
delay(2000);
//Normal screen
tft.fillScreen(TFT_BLACK);
drawX();
delay(2000);
tft.fillScreen(TFT_BLACK);
// Viewport as a clipping window (false parameter means coordinate datum stays at TFT top left)
tft.setViewport(10, 10, tft.width()/2 - 10, tft.height() - 20, false);
//tft.frameViewport(TFT_NAVY, 2); // Add 2 pixel border inside viewport
//tft.frameViewport(TFT_NAVY, -2); // Add 2 pixel border outside viewport
drawX();
delay(2000);
while(1)
{
tft.resetViewport(); // Reset viewport so width() and height() return TFT size
uint16_t w = 40;
uint16_t h = 40;
uint16_t x = random(tft.width() - w);
uint16_t y = random(tft.height() - h);
tft.setViewport(x, y, w, h);
plotBox();
delay(0);
}
}
void drawX(void)
{
tft.fillScreen(tft.color565(25,25,25)); // Grey
// Draw circle
tft.drawCircle(tft.width()/2, tft.height()/2, tft.width()/4, TFT_RED);
// Draw diagonal lines
tft.drawLine(0 , 0, tft.width()-1, tft.height()-1, TFT_GREEN);
tft.drawLine(0 , tft.height()-1, tft.width()-1, 0, TFT_BLUE);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_WHITE, tft.color565(25,25,25));
tft.drawString("Hello World!", tft.width()/2, tft.height()/2, 4); // Font 4
}
void plotBox(void)
{
// These are always plotted at a fixed position but they can
// be plotted into a viewport anywhere on the screen because
// a viewport can move the screen datum
tft.fillScreen(TFT_BLACK); // When a viewport is set, this just fills the viewport
tft.drawRect(0,0, 40,40, TFT_BLUE);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_WHITE);
tft.drawNumber( random(100), 20, 23, 4); // Number in font 4
}

View File

@@ -0,0 +1,40 @@
/*
// Create a viewport at TFT screen coordinated X,Y of width W and height H
tft.setViewport(X, Y, W, H); // By default the 0,0 coordinate datum is moved to top left
// corner of viewport
// Note: tft.width() and tft.height() now return viewport size!
// The above command is identical to:
tft.setViewport(VP_X, VP_Y, VP_W, VP_H, true); // true parameter is optional
// To create a viewport that keeps the coordinate datum at top left of TFT, use false parameter
tft.setViewport(VP_X, VP_Y, VP_W, VP_H, false); // Note: tft.width() and tft.height() return TFT size!
// To get viewport x, y coordinates, width, height and datum position flag
int32_t x = tft.getViewportX(); // Always returns viewport x coordinate relative to screen left edge
int32_t y = tft.getViewportY(void); // Always returns viewport y coordinate relative to screen top edge
int32_t w = tft.getViewportWidth(); // Always returns width of viewport
int32_t h = tft.getViewportHeight(); // Always returns height of viewport
bool f = tft.getViewportDatum(); // Datum of the viewport (false = TFT corner, true = viewport corner)
// To check if all or part of an area is in the viewport
checkViewport(x, y, w, h); // Retruns "true" if all or part of area is in viewport
// To draw a rectangular frame outside viewport of width W (when W is negative)
tft.frameViewport(TFT_RED, -W); // Note setting the width to a large negative value will clear the screen
// outside the viewport
// To draw a rectangular frame inside viewport of width W (when W is positive)
tft.frameViewport(TFT_RED, W); // Note setting the width to a large positive value will clear the screen
// inside the viewport
// To reset the viewport to the normal TFT full screen
tft.resetViewport(); // Note: Graphics will NOT be drawn to the TFT outside a viewport until
// this command is used! ( The exception is using the frameViewport command
// detailed above with a negative width.)
// Note:
// Using setRotation rotates the whole TFT screen it does not just
// rotate the viewport (this is a possible future enhancement).
// Redraw all graphics after a rotation since some TFT's do not
// re-map the TFT graphics RAM to the screen pixels as expected.
*/

View File

@@ -0,0 +1,382 @@
/*
This sketch demonstrates the Adafruit graphicstest sketch running in a
viewport (aka window) within the TFT screen area. To do this line 37 has
been added. Line 39 draws a frame outside the viewport.
This sketch uses the GLCD font (font 1) only.
Make sure all the display driver and pin comnenctions are correct by
editting the User_Setup.h file in the TFT_eSPI library folder.
#########################################################################
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
#########################################################################
*/
#include "SPI.h"
#include "TFT_eSPI.h"
TFT_eSPI tft = TFT_eSPI();
unsigned long total = 0;
unsigned long tn = 0;
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println(""); Serial.println("");
Serial.println("TFT_eSPI library test!");
tft.init();
tn = micros();
tft.fillScreen(TFT_BLACK);
// Create a viewport 220 x 300 pixels
tft.setViewport(10,10,220,300);
tft.frameViewport(TFT_RED, -1); // 1 pixel wide frame around viewport
yield(); Serial.println(F("Benchmark Time (microseconds)"));
yield(); Serial.print(F("Screen fill "));
yield(); Serial.println(testFillScreen());
//total+=testFillScreen();
//delay(500);
yield(); Serial.print(F("Text "));
yield(); Serial.println(testText());
//total+=testText();
//delay(3000);
yield(); Serial.print(F("Lines "));
yield(); Serial.println(testLines(TFT_CYAN));
//total+=testLines(TFT_CYAN);
//delay(500);
yield(); Serial.print(F("Horiz/Vert Lines "));
yield(); Serial.println(testFastLines(TFT_RED, TFT_BLUE));
//total+=testFastLines(TFT_RED, TFT_BLUE);
//delay(500);
yield(); Serial.print(F("Rectangles (outline) "));
yield(); Serial.println(testRects(TFT_GREEN));
//total+=testRects(TFT_GREEN);
//delay(500);
yield(); Serial.print(F("Rectangles (filled) "));
yield(); Serial.println(testFilledRects(TFT_YELLOW, TFT_MAGENTA));
//total+=testFilledRects(TFT_YELLOW, TFT_MAGENTA);
//delay(500);
yield(); Serial.print(F("Circles (filled) "));
yield(); Serial.println(testFilledCircles(10, TFT_MAGENTA));
//total+= testFilledCircles(10, TFT_MAGENTA);
yield(); Serial.print(F("Circles (outline) "));
yield(); Serial.println(testCircles(10, TFT_WHITE));
//total+=testCircles(10, TFT_WHITE);
//delay(500);
yield(); Serial.print(F("Triangles (outline) "));
yield(); Serial.println(testTriangles());
//total+=testTriangles();
//delay(500);
yield(); Serial.print(F("Triangles (filled) "));
yield(); Serial.println(testFilledTriangles());
//total += testFilledTriangles();
//delay(500);
yield(); Serial.print(F("Rounded rects (outline) "));
yield(); Serial.println(testRoundRects());
//total+=testRoundRects();
//delay(500);
yield(); Serial.print(F("Rounded rects (filled) "));
yield(); Serial.println(testFilledRoundRects());
//total+=testFilledRoundRects();
//delay(500);
yield(); Serial.println(F("Done!")); yield();
//Serial.print(F("Total = ")); Serial.println(total);
//yield();Serial.println(millis()-tn);
}
void loop(void) {
for (uint8_t rotation = 0; rotation < 4; rotation++) {
tft.setRotation(rotation);
tft.resetViewport(); // reset viewport to whole screen
tft.fillScreen(TFT_BLACK); // so it can be cleared
// Create a viewport 220 x 300 pixels
tft.setViewport(10,10,220,300);
tft.frameViewport(TFT_RED, -1); // 1 pixel wide frame around viewport
testText();
delay(2000);
}
}
unsigned long testFillScreen() {
unsigned long start = micros();
tft.fillScreen(TFT_BLACK);
tft.fillScreen(TFT_RED);
tft.fillScreen(TFT_GREEN);
tft.fillScreen(TFT_BLUE);
tft.fillScreen(TFT_BLACK);
return micros() - start;
}
unsigned long testText() {
tft.fillScreen(TFT_BLACK);
unsigned long start = micros();
tft.setCursor(0, 0);
tft.setTextColor(TFT_WHITE); tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(TFT_YELLOW); tft.setTextSize(2);
tft.println(1234.56);
tft.setTextColor(TFT_RED); tft.setTextSize(3);
tft.println(0xDEADBEEF, HEX);
tft.println();
tft.setTextColor(TFT_GREEN);
tft.setTextSize(5);
tft.println("Groop");
tft.setTextSize(2);
tft.println("I implore thee,");
//tft.setTextColor(TFT_GREEN,TFT_BLACK);
tft.setTextSize(1);
tft.println("my foonting turlingdromes.");
tft.println("And hooptiously drangle me");
tft.println("with crinkly bindlewurdles,");
tft.println("Or I will rend thee");
tft.println("in the gobberwarts");
tft.println("with my blurglecruncheon,");
tft.println("see if I don't!");
return micros() - start;
}
unsigned long testLines(uint16_t color) {
unsigned long start, t;
int x1, y1, x2, y2,
w = tft.width(),
h = tft.height();
tft.fillScreen(TFT_BLACK);
x1 = y1 = 0;
y2 = h - 1;
start = micros();
for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
t = micros() - start; // fillScreen doesn't count against timing
tft.fillScreen(TFT_BLACK);
x1 = w - 1;
y1 = 0;
y2 = h - 1;
start = micros();
for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
tft.fillScreen(TFT_BLACK);
x1 = 0;
y1 = h - 1;
y2 = 0;
start = micros();
for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
tft.fillScreen(TFT_BLACK);
x1 = w - 1;
y1 = h - 1;
y2 = 0;
start = micros();
for (x2 = 0; x2 < w; x2 += 6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for (y2 = 0; y2 < h; y2 += 6) tft.drawLine(x1, y1, x2, y2, color);
return micros() - start;
}
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height();
tft.fillScreen(TFT_BLACK);
start = micros();
for (y = 0; y < h; y += 5) tft.drawFastHLine(0, y, w, color1);
for (x = 0; x < w; x += 5) tft.drawFastVLine(x, 0, h, color2);
return micros() - start;
}
unsigned long testRects(uint16_t color) {
unsigned long start;
int n, i, i2,
cx = tft.width() / 2,
cy = tft.height() / 2;
tft.fillScreen(TFT_BLACK);
n = min(tft.width(), tft.height());
start = micros();
for (i = 2; i < n; i += 6) {
i2 = i / 2;
tft.drawRect(cx - i2, cy - i2, i, i, color);
}
return micros() - start;
}
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
unsigned long start, t = 0;
int n, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK);
n = min(tft.width(), tft.height());
for (i = n - 1; i > 0; i -= 6) {
i2 = i / 2;
start = micros();
tft.fillRect(cx - i2, cy - i2, i, i, color1);
t += micros() - start;
// Outlines are not included in timing results
tft.drawRect(cx - i2, cy - i2, i, i, color2);
}
return t;
}
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
tft.fillScreen(TFT_BLACK);
start = micros();
for (x = radius; x < w; x += r2) {
for (y = radius; y < h; y += r2) {
tft.fillCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, r2 = radius * 2,
w = tft.width() + radius,
h = tft.height() + radius;
// Screen is not cleared for this one -- this is
// intentional and does not affect the reported time.
start = micros();
for (x = 0; x < w; x += r2) {
for (y = 0; y < h; y += r2) {
tft.drawCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testTriangles() {
unsigned long start;
int n, i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK);
n = min(cx, cy);
start = micros();
for (i = 0; i < n; i += 5) {
tft.drawTriangle(
cx , cy - i, // peak
cx - i, cy + i, // bottom left
cx + i, cy + i, // bottom right
tft.color565(0, 0, i));
}
return micros() - start;
}
unsigned long testFilledTriangles() {
unsigned long start, t = 0;
int i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK);
start = micros();
for (i = min(cx, cy); i > 10; i -= 5) {
start = micros();
tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(0, i, i));
t += micros() - start;
tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(i, i, 0));
}
return t;
}
unsigned long testRoundRects() {
unsigned long start;
int w, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK);
w = min(tft.width(), tft.height());
start = micros();
for (i = 0; i < w; i += 6) {
i2 = i / 2;
tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(i, 0, 0));
}
return micros() - start;
}
unsigned long testFilledRoundRects() {
unsigned long start;
int i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK);
start = micros();
for (i = min(tft.width(), tft.height()); i > 20; i -= 6) {
i2 = i / 2;
tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, i, 0));
}
return micros() - start;
}
/***************************************************
Original Adafruit text:
This is an example sketch for the Adafruit 2.2" SPI display.
This library works with the Adafruit 2.2" TFT Breakout w/SD card
----> http://www.adafruit.com/products/1480
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/

View File

@@ -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++;
}

View File

@@ -17,6 +17,16 @@ getRotation KEYWORD2
invertDisplay KEYWORD2
setAddrWindow KEYWORD2
setWindow KEYWORD2
setViewport KEYWORD2
resetViewport KEYWORD2
getViewportX KEYWORD2
getViewportY KEYWORD2
getViewportWidth KEYWORD2
getViewportHeight KEYWORD2
getViewportDatum KEYWORD2
frameViewport KEYWORD2
pushColor KEYWORD2
pushColors KEYWORD2
pushBlock KEYWORD2

View File

@@ -1,6 +1,6 @@
{
"name": "TFT_eSPI",
"version": "2.2.23",
"version": "2.3.2",
"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":

View File

@@ -1,5 +1,5 @@
name=TFT_eSPI
version=2.2.23
version=2.3.2
author=Bodmer
maintainer=Bodmer
sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32