Add viewport feature

2 new example sketches added for viewport demonstration
This commit is contained in:
Bodmer
2020-10-06 00:51:41 +01:00
parent 22ca8193c5
commit 13d217dc89
11 changed files with 813 additions and 72 deletions

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

@@ -85,6 +85,132 @@ 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)
{
// Set to whole screen in case of error
_xDatum = 0;
_yDatum = 0;
_vpX = 0;
_vpY = 0;
_vpW = _width;
_vpH = _height;
_vpDatum = false;
// Check if out of bounds
if ((x >= _width) || (y >= _height)) return;
// Clip
if (x < 0) { x = 0; }
if (y < 0) { y = 0; }
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
{
_xDatum = 0;
_yDatum = 0;
_vpX = x;
_vpY = y;
_vpW = x + w;
_vpH = y + h;
}
_vpDatum = vpDatum;
}
/***************************************************************************************
** Function name: resetViewport
** Description: Reset viewport to whle TFT screen, datum at 0,0
***************************************************************************************/
void TFT_eSPI::resetViewport(void)
{
// Set to whole screen
_xDatum = 0;
_yDatum = 0;
_vpX = 0;
_vpY = 0;
_vpW = _width;
_vpH = _height;
_vpDatum = false;
}
/***************************************************************************************
** 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: 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(_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);
_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 +307,15 @@ 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;
rotation = 0;
cursor_y = cursor_x = 0;
textfont = 1;
@@ -490,6 +625,18 @@ 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;
}
}
@@ -903,18 +1050,18 @@ 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;
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;
@@ -947,18 +1094,18 @@ 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;
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;
@@ -1020,18 +1167,18 @@ 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;
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;
@@ -1064,18 +1211,18 @@ 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;
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;
@@ -1134,18 +1281,18 @@ 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;
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;
@@ -1290,18 +1437,18 @@ 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;
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;
@@ -2329,7 +2476,8 @@ uint8_t TFT_eSPI::getTextDatum(void)
// Return the size of the display (per current rotation)
int16_t TFT_eSPI::width(void)
{
return _width;
if (_vpDatum) return _vpW - _vpX;
else return _width;
}
@@ -2339,7 +2487,8 @@ int16_t TFT_eSPI::width(void)
***************************************************************************************/
int16_t TFT_eSPI::height(void)
{
return _height;
if (_vpDatum) return _vpH - _vpY;
else return _height;
}
@@ -2479,10 +2628,10 @@ 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
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 (c < 32) return;
@@ -2495,7 +2644,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32
bool fillbg = (bg != color);
if ((size==1) && fillbg) {
if ((size==1) && fillbg && x >= _vpX && (x + 6 * size - 1) < _vpW) {
uint8_t column[6];
uint8_t mask = 0x1;
begin_tft_write();
@@ -2526,13 +2675,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);
@@ -2640,6 +2789,14 @@ 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
@@ -2714,7 +2871,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)
{
// Range checking
if ((x < 0) || (y < 0) ||(x >= _width) || (y >= _height)) return;
if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return;
if( _vpDatum)
{
x+= _xDatum;
y+= _yDatum;
}
#ifdef CGRAM_OFFSET
x+=colstart;
@@ -2915,11 +3078,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)
{
// 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;
@@ -2940,11 +3103,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)
{
// 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;
@@ -2965,13 +3128,13 @@ 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)
{
// 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;
@@ -3359,11 +3522,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 +3549,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;
@@ -3482,6 +3645,8 @@ 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 w = width;
int32_t pX = 0;
int32_t pY = y;
@@ -3491,9 +3656,8 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
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 || x < _vpX || x + width * textsize >= _vpW) {
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
@@ -3570,7 +3734,7 @@ 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 && x >= _vpX && x + width * textsize <= _vpW) {
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
@@ -3619,7 +3783,7 @@ 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
// 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 (textsize == 1 && x >= _vpX && x + width <= _vpW)
{
setWindow(x, y, x + width - 1, y + height - 1);
@@ -3644,12 +3808,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 +3825,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 +3833,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);
}
}
}

View File

@@ -16,7 +16,7 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.2.23"
#define TFT_ESPI_VERSION "2.3.0"
/***************************************************************************************
** Section 1: Load required header files
@@ -390,6 +390,13 @@ 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);
int32_t getViewportWidth(void);
int32_t getViewportHeight(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 +735,12 @@ 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;
int32_t _xDatum;
int32_t _yDatum;
bool _vpDatum;
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

@@ -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,142 @@
// Viewport Demo
// See viewport_commands tab
// 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 plotShapes() below). This
// makes it easier to reposition groupd of graphical ojects (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);
/*
tft.setViewport(VP_X, VP_Y, VP_W, VP_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
// Other command options:
//tft.setViewport(VP_X, VP_Y, VP_W, VP_H, true); // Explicitly set datum to viewport corner
//tft.setViewport(VP_X, VP_Y, VP_W, VP_H, false); // Create viewport but datum stays at TFT corner
// Note: tft.width() and tft.height() now return TFT size
w = tft.getViewportWidth(); // Always returns width of viewport
h = tft.getViewportHeight(); // Always returns height of viewport
tft.frameViewport(TFT_GREEN, -2); // Draw a rectangle of width 2 outside (negative width) viewport
tft.frameViewport(TFT_RED, 10); // Draw a rectangle of width 10 inside (positive width) viewport
// tft.resetViewport(); // Command to reset viewport to "normal" full TFT screen
// Graphics will not be drawn to the TFT outside a viewport until
// this command is used!
// tft.setRotation(2); // 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.
delay(1000);
*/
}
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();
}
}
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);
}

View File

@@ -0,0 +1,33 @@
/*
// 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 width of viewport
uint16_t w = tft.getViewportWidth(); // Always returns width of viewport
// To get height of viewport
uint16_t h = tft.getViewportHeight(); // Always returns height of 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.)
*/

View File

@@ -0,0 +1,381 @@
/*
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 38 outlines 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

@@ -17,6 +17,11 @@ getRotation KEYWORD2
invertDisplay KEYWORD2
setAddrWindow KEYWORD2
setWindow KEYWORD2
setViewport KEYWORD2
resetViewport KEYWORD2
getViewportWidth KEYWORD2
getViewportHeight 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.0",
"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.0
author=Bodmer
maintainer=Bodmer
sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32