mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-05 13:44:43 +02:00
Add support for 8 bit color sprites (needs less RAM)
Added setColorDepth(d) where "d" is 8 or 16. Default is 16 bit if not specified.
This commit is contained in:
@@ -91,6 +91,7 @@ justReleased KEYWORD2
|
|||||||
TFT_eSprite KEYWORD1
|
TFT_eSprite KEYWORD1
|
||||||
|
|
||||||
createSprite KEYWORD2
|
createSprite KEYWORD2
|
||||||
|
setColorDepth KEYWORD2
|
||||||
deleteSprite KEYWORD2
|
deleteSprite KEYWORD2
|
||||||
fillSprite KEYWORD2
|
fillSprite KEYWORD2
|
||||||
setWindow KEYWORD2
|
setWindow KEYWORD2
|
||||||
|
330
TFT_eSPI.cpp
330
TFT_eSPI.cpp
@@ -552,11 +552,6 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
|||||||
|
|
||||||
if (dw < 0 || dh < 0) return;
|
if (dw < 0 || dh < 0) return;
|
||||||
|
|
||||||
//Serial.print("dx="); Serial.println(dx);
|
|
||||||
//Serial.print("dy="); Serial.println(dy);
|
|
||||||
//Serial.print("dw="); Serial.println(dw);
|
|
||||||
//Serial.print("dh="); Serial.println(dh);
|
|
||||||
|
|
||||||
spi_begin();
|
spi_begin();
|
||||||
|
|
||||||
setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
|
setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
|
||||||
@@ -574,11 +569,71 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
|||||||
*/
|
*/
|
||||||
uint32_t len = dw * 2;
|
uint32_t len = dw * 2;
|
||||||
uint8_t* ptr = (uint8_t*)data;
|
uint8_t* ptr = (uint8_t*)data;
|
||||||
|
|
||||||
// Push pixels into window rectangle, data is a 16 bit pointer thus increment is halved
|
// Push pixels into window rectangle, data is a 16 bit pointer thus increment is halved
|
||||||
while ( len>32) { SPI.writePattern(ptr, 32, 1); len -= 32; ptr += 32; }
|
while ( len>32) { SPI.writePattern(ptr, 32, 1); len -= 32; ptr += 32; }
|
||||||
if (len) SPI.writePattern((uint8_t*)ptr, len, 1);
|
if (len) SPI.writePattern((uint8_t*)ptr, len, 1);
|
||||||
data += w;
|
data += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
CS_H;
|
||||||
|
|
||||||
|
spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TFT_eSPI::pushSprite(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((x >= (int32_t)_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 + w) >= _width ) dw = _width - x;
|
||||||
|
if ((y + h) >= _height) dh = _height - y;
|
||||||
|
|
||||||
|
if (dw < 0 || dh < 0) return;
|
||||||
|
|
||||||
|
spi_begin();
|
||||||
|
|
||||||
|
setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
|
||||||
|
|
||||||
|
data += dx + dy * w;
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
uint32_t spimask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
||||||
|
SPI1U1 = (SPI1U1 & spimask) | (15 << SPILMOSI) | (15 << SPILMISO);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (dh--)
|
||||||
|
{
|
||||||
|
uint32_t len = dw;
|
||||||
|
uint8_t* ptr = data;
|
||||||
|
|
||||||
|
while(len--)
|
||||||
|
{
|
||||||
|
uint16_t color = *ptr++;
|
||||||
|
color = (color & 0xE0)<<8 | (color & 0xC0)<<5
|
||||||
|
| (color & 0x1C)<<6 | (color & 0x1C)<<3
|
||||||
|
| (color & 0x03)<<3 | (color & 0x03)<<1 | (color & 0x03)>>1;
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
SPI.write16(color);
|
||||||
|
#else
|
||||||
|
color = (color<<8) | (color>>8);
|
||||||
|
SPI1W0 = color;
|
||||||
|
SPI1CMD |= SPIBUSY;
|
||||||
|
while(SPI1CMD & SPIBUSY) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
data += w;
|
||||||
|
}
|
||||||
|
|
||||||
CS_H;
|
CS_H;
|
||||||
|
|
||||||
@@ -4108,8 +4163,8 @@ void TFT_eSPI_Button::press(boolean p) {
|
|||||||
currstate = p;
|
currstate = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean TFT_eSPI_Button::isPressed() { return currstate; }
|
boolean TFT_eSPI_Button::isPressed() { return currstate; }
|
||||||
boolean TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
|
boolean TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
|
||||||
boolean TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }
|
boolean TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }
|
||||||
|
|
||||||
|
|
||||||
@@ -4132,8 +4187,11 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
|
|||||||
|
|
||||||
_iwidth = 0; // Initialise width and height to 0 (it does not exist yet)
|
_iwidth = 0; // Initialise width and height to 0 (it does not exist yet)
|
||||||
_iheight = 0;
|
_iheight = 0;
|
||||||
|
_bpp16 = true;
|
||||||
|
|
||||||
_xs = 0; // window bounds for pushColor
|
_created = false;
|
||||||
|
|
||||||
|
_xs = 0; // window bounds for pushColor
|
||||||
_ys = 0;
|
_ys = 0;
|
||||||
_xe = 0;
|
_xe = 0;
|
||||||
_ye = 0;
|
_ye = 0;
|
||||||
@@ -4149,13 +4207,30 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
|
|||||||
** Function name: createSprite
|
** Function name: createSprite
|
||||||
** Description: Create a sprite (bitmap) of defined width and height
|
** Description: Create a sprite (bitmap) of defined width and height
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
uint16_t* TFT_eSprite::createSprite(int16_t w, int16_t h)
|
void TFT_eSprite::createSprite(int16_t w, int16_t h)
|
||||||
{
|
{
|
||||||
if ( w < 1 || h < 1) return 0;
|
if ( w < 1 || h < 1) return;
|
||||||
|
|
||||||
_iwidth = w;
|
_iwidth = w;
|
||||||
_iheight = h;
|
_iheight = h;
|
||||||
_img = (uint16_t*) malloc(w * h * sizeof(uint16_t));
|
|
||||||
return _img;
|
if(_bpp16) _img = (uint16_t*) malloc(w * h * 2);
|
||||||
|
else _img8 = ( uint8_t*) malloc(w * h);
|
||||||
|
|
||||||
|
_created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: setDepth
|
||||||
|
** Description: Set bits per pixel for colour (8 or 16)
|
||||||
|
*************************************************************************************x*/
|
||||||
|
|
||||||
|
void TFT_eSprite::setColorDepth(int8_t b)
|
||||||
|
{
|
||||||
|
if (_created) deleteSprite();
|
||||||
|
if ( b > 8 ) _bpp16 = true; // Bytes per pixel
|
||||||
|
else _bpp16 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4165,7 +4240,10 @@ uint16_t* TFT_eSprite::createSprite(int16_t w, int16_t h)
|
|||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
void TFT_eSprite::deleteSprite(void)
|
void TFT_eSprite::deleteSprite(void)
|
||||||
{
|
{
|
||||||
free(_img);
|
if (!_created ) return;
|
||||||
|
if (_bpp16) free(_img);
|
||||||
|
else free(_img8);
|
||||||
|
_created = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4175,18 +4253,30 @@ void TFT_eSprite::deleteSprite(void)
|
|||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
void TFT_eSprite::pushSprite(int32_t x, int32_t y)
|
void TFT_eSprite::pushSprite(int32_t x, int32_t y)
|
||||||
{
|
{
|
||||||
_tft->pushSprite(x, y, _iwidth, _iheight, _img);
|
if (_bpp16) _tft->pushSprite(x, y, _iwidth, _iheight, _img );
|
||||||
|
else _tft->pushSprite(x, y, _iwidth, _iheight, _img8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: readPixel
|
** Function name: readPixel
|
||||||
** Description: Read 565 colour of a pixel at deined coordinates
|
** Description: Read 565 colour of a pixel at defined coordinates
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
|
uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
|
||||||
{
|
{
|
||||||
uint16_t color = _img[x + y * _iwidth];
|
if (_bpp16)
|
||||||
return (color >> 8) | (color << 8);
|
{
|
||||||
|
uint16_t color = _img[x + y * _iwidth];
|
||||||
|
return (color >> 8) | (color << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t color = _img8[x + y * _iwidth];
|
||||||
|
if (color != 0)
|
||||||
|
color = (color & 0xE0)<<8 | (color & 0xC0)<<5
|
||||||
|
| (color & 0x1C)<<6 | (color & 0x1C)<<3
|
||||||
|
| (color & 0x03)<<3 | (color & 0x03)<<1 | (color & 0x03)>>1;
|
||||||
|
|
||||||
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4198,11 +4288,25 @@ void TFT_eSprite::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint
|
|||||||
{
|
{
|
||||||
if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0)) return;
|
if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0)) return;
|
||||||
|
|
||||||
for (uint32_t yp = y; yp < y + h; yp++)
|
if (_bpp16)
|
||||||
{
|
{
|
||||||
for (uint32_t xp = x; xp < x + w; xp++)
|
for (uint32_t yp = y; yp < y + h; yp++)
|
||||||
{
|
{
|
||||||
_img[xp + yp * _iwidth] = *data++;
|
for (uint32_t xp = x; xp < x + w; xp++)
|
||||||
|
{
|
||||||
|
_img[xp + yp * _iwidth] = *data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32_t yp = y; yp < y + h; yp++)
|
||||||
|
{
|
||||||
|
for (uint32_t xp = x; xp < x + w; xp++)
|
||||||
|
{
|
||||||
|
uint16_t color = *data++;
|
||||||
|
_img8[xp + yp * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4214,28 +4318,29 @@ void TFT_eSprite::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint
|
|||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
void TFT_eSprite::pushBitmap(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
|
void TFT_eSprite::pushBitmap(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
|
||||||
{
|
{
|
||||||
if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0)) return;
|
pushRect(x, y, w, h, data);
|
||||||
|
|
||||||
for (uint32_t yp = y; yp < y + h; yp++)
|
|
||||||
{
|
|
||||||
for (uint32_t xp = x; xp < x + w; xp++)
|
|
||||||
{
|
|
||||||
_img[xp + yp * _iwidth] = *data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: spriteWindow
|
** Function name: setWindow
|
||||||
** Description: Set the bounds of a window for pushColor
|
** Description: Set the bounds of a window for pushColor and writeColor
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
||||||
{
|
{
|
||||||
// Bounds will be checked by drawPixel
|
|
||||||
if (x0 > x1) swap_coord(x0, x1);
|
if (x0 > x1) swap_coord(x0, x1);
|
||||||
if (y0 > y1) swap_coord(y0, y1);
|
if (y0 > y1) swap_coord(y0, y1);
|
||||||
|
|
||||||
|
if (x0 < 0) x0 = 0;
|
||||||
|
if (x0 >= _iwidth) x0 = _iwidth;
|
||||||
|
if (x1 < 0) x1 = 0;
|
||||||
|
if (x1 >= _iwidth) x1 = _iwidth;
|
||||||
|
|
||||||
|
if (y0 < 0) y0 = 0;
|
||||||
|
if (y0 >= _iheight) y0 = _iheight;
|
||||||
|
if (y1 < 0) y1 = 0;
|
||||||
|
if (y1 >= _iheight) y1 = _iheight;
|
||||||
|
|
||||||
_xs = x0;
|
_xs = x0;
|
||||||
_ys = y0;
|
_ys = y0;
|
||||||
_xe = x1;
|
_xe = x1;
|
||||||
@@ -4248,20 +4353,69 @@ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
|||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: pushColor
|
** Function name: pushColor
|
||||||
** Description: Send a new pixel to the sprite window
|
** Description: Send a new pixel to the set window
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
void TFT_eSprite::pushColor(uint32_t color)
|
void TFT_eSprite::pushColor(uint32_t color)
|
||||||
{
|
{
|
||||||
drawPixel(_xptr++, _yptr, color);
|
|
||||||
if (_xptr > _xe) { _xptr = _xs; _yptr++; }
|
// Write the colour to RAM in set window
|
||||||
if (_yptr > _ye) { _yptr = _ys; }
|
if (_bpp16)
|
||||||
|
_img [_xptr + _yptr * _iwidth] = (uint16_t) (color >> 8) | (color << 8);
|
||||||
|
else
|
||||||
|
_img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
||||||
|
|
||||||
|
// Increment x
|
||||||
|
_xptr++;
|
||||||
|
|
||||||
|
// Wrap on x and y to start, increment y if needed
|
||||||
|
if (_xptr > _xe)
|
||||||
|
{
|
||||||
|
_xptr = _xs;
|
||||||
|
_yptr++;
|
||||||
|
if (_yptr > _ye) _yptr = _ys;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: pushColor
|
||||||
|
** Description: Send a "len" new pixels to the set window
|
||||||
|
*************************************************************************************x*/
|
||||||
void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
|
void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
|
||||||
{
|
{
|
||||||
drawPixel(_xptr++, _yptr, color);
|
uint16_t pixelColor;
|
||||||
if (_xptr > _xe) { _xptr = _xs; _yptr++; }
|
if (_bpp16)
|
||||||
if (_yptr > _ye) { _yptr = _ys; }
|
pixelColor = (uint16_t) (color >> 8) | (color << 8);
|
||||||
|
else
|
||||||
|
pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
|
|
||||||
|
while(len--) writeColor(pixelColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: writeColor
|
||||||
|
** Description: Write a pixel with pre-formatted colour to the set window
|
||||||
|
*************************************************************************************x*/
|
||||||
|
void TFT_eSprite::writeColor(uint16_t color)
|
||||||
|
{
|
||||||
|
// Write 16 bit RGB 565 encoded colour to RAM
|
||||||
|
if (_bpp16) _img [_xptr + _yptr * _iwidth] = color;
|
||||||
|
|
||||||
|
// Write 8 bit RGB 332 encoded colour to RAM
|
||||||
|
else _img8[_xptr + _yptr * _iwidth] = (uint8_t) color;
|
||||||
|
|
||||||
|
// Increment x
|
||||||
|
_xptr++;
|
||||||
|
|
||||||
|
// Wrap on x and y to start, increment y if needed
|
||||||
|
if (_xptr > _xe)
|
||||||
|
{
|
||||||
|
_xptr = _xs;
|
||||||
|
_yptr++;
|
||||||
|
if (_yptr > _ye) _yptr = _ys;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4272,7 +4426,10 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
|
|||||||
void TFT_eSprite::fillSprite(uint32_t color)
|
void TFT_eSprite::fillSprite(uint32_t color)
|
||||||
{
|
{
|
||||||
// Use memset if possible as it is super fast
|
// Use memset if possible as it is super fast
|
||||||
if((uint8_t)color == (color>>8)) memset(_img, (uint8_t)color, _iwidth * _iheight * 2);
|
if(( (uint8_t)color == (uint8_t)(color>>8) ) && _bpp16)
|
||||||
|
memset(_img, (uint8_t)color, _iwidth * _iheight * 2);
|
||||||
|
else if (!_bpp16) memset(_img8, (uint8_t)color, _iwidth * _iheight);
|
||||||
|
|
||||||
else fillRect(0, 0, _iwidth, _iheight, color);
|
else fillRect(0, 0, _iwidth, _iheight, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4289,7 +4446,7 @@ void TFT_eSprite::setCursor(int16_t x, int16_t y)
|
|||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: width or spriteWidth
|
** Function name: width
|
||||||
** Description: Return the width of sprite
|
** Description: Return the width of sprite
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
// Return the size of the display
|
// Return the size of the display
|
||||||
@@ -4298,16 +4455,9 @@ int16_t TFT_eSprite::width(void)
|
|||||||
return _iwidth;
|
return _iwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Return the size of the display
|
|
||||||
int16_t TFT_eSprite::spriteWidth(void)
|
|
||||||
{
|
|
||||||
return _iwidth;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: height or spriteHeight
|
** Function name: height
|
||||||
** Description: Return the height of sprite
|
** Description: Return the height of sprite
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
int16_t TFT_eSprite::height(void)
|
int16_t TFT_eSprite::height(void)
|
||||||
@@ -4315,12 +4465,6 @@ int16_t TFT_eSprite::height(void)
|
|||||||
return _iheight;
|
return _iheight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
int16_t TFT_eSprite::spriteHeight(void)
|
|
||||||
{
|
|
||||||
return _iheight;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: drawChar
|
** Function name: drawChar
|
||||||
@@ -4471,8 +4615,16 @@ void TFT_eSprite::drawPixel(uint32_t x, uint32_t y, uint32_t color)
|
|||||||
// x and y are unsigned so that -ve coordinates turn into large positive ones
|
// x and y are unsigned so that -ve coordinates turn into large positive ones
|
||||||
// this make bounds checking a bit faster
|
// this make bounds checking a bit faster
|
||||||
if ((x >= _iwidth) || (y >= _iheight)) return;
|
if ((x >= _iwidth) || (y >= _iheight)) return;
|
||||||
color = (color >> 8) | (color << 8);
|
|
||||||
_img[x+y*_iwidth] = (uint16_t) color;
|
if (_bpp16)
|
||||||
|
{
|
||||||
|
color = (color >> 8) | (color << 8);
|
||||||
|
_img[x+y*_iwidth] = (uint16_t) color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4541,8 +4693,17 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
|||||||
if ((y + h) > _iheight) h = _iheight - y;
|
if ((y + h) > _iheight) h = _iheight - y;
|
||||||
|
|
||||||
if (h < 1) return;
|
if (h < 1) return;
|
||||||
color = (color >> 8) | (color << 8);
|
|
||||||
while (h--) _img[x + _iwidth * y++] = (uint16_t) color;
|
if (_bpp16)
|
||||||
|
{
|
||||||
|
color = (color >> 8) | (color << 8);
|
||||||
|
while (h--) _img[x + _iwidth * y++] = (uint16_t) color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
|
while (h--) _img8[x + _iwidth * y++] = (uint8_t) color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4557,8 +4718,18 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
|
|||||||
if ((x + w) > _iwidth) w = _iwidth - x;
|
if ((x + w) > _iwidth) w = _iwidth - x;
|
||||||
|
|
||||||
if (w < 1) return;
|
if (w < 1) return;
|
||||||
color = (color >> 8) | (color << 8);
|
|
||||||
while (w--) _img[_iwidth * y + x++] = (uint16_t) color;
|
if (_bpp16)
|
||||||
|
{
|
||||||
|
color = (color >> 8) | (color << 8);
|
||||||
|
while (w--) _img[_iwidth * y + x++] = (uint16_t) color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
|
//while (w--) _img8[_iwidth * y + x++] = (uint8_t) color;
|
||||||
|
memset(_img8+_iwidth * y + x, (uint8_t)color, w);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4574,12 +4745,27 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
|
|||||||
if ((x + w) > _iwidth) w = _iwidth - x;
|
if ((x + w) > _iwidth) w = _iwidth - x;
|
||||||
if ((y + h) > _iheight) h = _iheight - y;
|
if ((y + h) > _iheight) h = _iheight - y;
|
||||||
if ((w < 1) || (h < 1)) return;
|
if ((w < 1) || (h < 1)) return;
|
||||||
color = (color >> 8) | (color << 8);
|
|
||||||
|
|
||||||
while (h--) {
|
if (_bpp16)
|
||||||
|
{
|
||||||
|
color = (color >> 8) | (color << 8);
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
int32_t ix = x, iw = w;
|
int32_t ix = x, iw = w;
|
||||||
while (iw--) _img[_iwidth * y + ix++] = (uint16_t) color;
|
while (iw--) _img[_iwidth * y + ix++] = (uint16_t) color;
|
||||||
y++;
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
//int32_t ix = x, iw = w;
|
||||||
|
//while (iw--) _img8[_iwidth * y + ix++] = (uint8_t) color;
|
||||||
|
memset(_img8 + _iwidth * y + x, (uint8_t)color, w);
|
||||||
|
y++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4708,7 +4894,7 @@ size_t TFT_eSprite::write(uint8_t utf8)
|
|||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y)
|
int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y)
|
||||||
{
|
{
|
||||||
return drawChar(uniCode, x, y, textfont);
|
return drawChar(uniCode, x, y, textfont);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font)
|
int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font)
|
||||||
@@ -4842,11 +5028,13 @@ int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font)
|
|||||||
w *= height; // Now w is total number of pixels in the character
|
w *= height; // Now w is total number of pixels in the character
|
||||||
|
|
||||||
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
|
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
|
||||||
|
int16_t color;
|
||||||
|
if (_bpp16) color = (textcolor >> 8) | (textcolor << 8);
|
||||||
|
else color = ((textcolor & 0xE000)>>8 | (textcolor & 0x0700)>>6 | (textcolor & 0x0018)>>3);
|
||||||
int px = 0, py = pY; // To hold character block start and end column and row values
|
int px = 0, py = pY; // To hold character block start and end column and row values
|
||||||
int pc = 0; // Pixel count
|
int pc = 0; // Pixel count
|
||||||
byte np = textsize * textsize; // Number of pixels in a drawn pixel
|
byte np = textsize * textsize; // Number of pixels in a drawn pixel
|
||||||
|
|
||||||
byte tnp = 0; // Temporary copy of np for while loop
|
|
||||||
byte ts = textsize - 1; // Temporary copy of textsize
|
byte ts = textsize - 1; // Temporary copy of textsize
|
||||||
// 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area
|
// 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area
|
||||||
// w is total number of pixels to plot to fill character block
|
// w is total number of pixels to plot to fill character block
|
||||||
@@ -4869,15 +5057,9 @@ int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font)
|
|||||||
pc++;
|
pc++;
|
||||||
setWindow(px, py, px + ts, py + ts);
|
setWindow(px, py, px + ts, py + ts);
|
||||||
|
|
||||||
if (ts) {
|
if (ts) while (np--) writeColor(color);
|
||||||
tnp = np;
|
else writeColor(color);
|
||||||
while (tnp--) {
|
|
||||||
pushColor(textcolor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pushColor(textcolor);
|
|
||||||
}
|
|
||||||
px += textsize;
|
px += textsize;
|
||||||
|
|
||||||
if (px >= (x + width * textsize))
|
if (px >= (x + width * textsize))
|
||||||
|
16
TFT_eSPI.h
16
TFT_eSPI.h
@@ -344,9 +344,6 @@ class TFT_eSPI : public Print {
|
|||||||
height(void),
|
height(void),
|
||||||
width(void);
|
width(void);
|
||||||
|
|
||||||
virtual size_t write(uint8_t);
|
|
||||||
|
|
||||||
|
|
||||||
// The TFT_eSprite class inherits the following functions
|
// The TFT_eSprite class inherits the following functions
|
||||||
void pushColors(uint16_t *data, uint8_t len),
|
void pushColors(uint16_t *data, uint8_t len),
|
||||||
pushColors(uint8_t *data, uint32_t len),
|
pushColors(uint8_t *data, uint32_t len),
|
||||||
@@ -408,7 +405,7 @@ class TFT_eSPI : public Print {
|
|||||||
// Write a block of pixels to the screen
|
// Write a block of pixels to the screen
|
||||||
void pushRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data);
|
void pushRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data);
|
||||||
void pushSprite(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint16_t *data);
|
void pushSprite(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint16_t *data);
|
||||||
|
void pushSprite(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint8_t *data);
|
||||||
// This next function has been used successfully to dump the TFT screen to a PC for documentation purposes
|
// This next function has been used successfully to dump the TFT screen to a PC for documentation purposes
|
||||||
// It reads a screen area and returns the RGB 8 bit colour values of each pixel
|
// It reads a screen area and returns the RGB 8 bit colour values of each pixel
|
||||||
// Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes
|
// Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes
|
||||||
@@ -453,6 +450,7 @@ class TFT_eSPI : public Print {
|
|||||||
void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size);
|
void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size);
|
||||||
void setTouch(uint16_t *data);
|
void setTouch(uint16_t *data);
|
||||||
|
|
||||||
|
size_t write(uint8_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -556,9 +554,12 @@ class TFT_eSprite : public TFT_eSPI {
|
|||||||
|
|
||||||
TFT_eSprite(TFT_eSPI *tft);
|
TFT_eSprite(TFT_eSPI *tft);
|
||||||
|
|
||||||
uint16_t* createSprite(int16_t w, int16_t y); // 16 bpp
|
void createSprite(int16_t w, int16_t y); // 2 bytes per pixel
|
||||||
|
|
||||||
void deleteSprite(void);
|
void deleteSprite(void);
|
||||||
|
|
||||||
|
void setColorDepth(int8_t b);
|
||||||
|
|
||||||
void drawPixel(uint32_t x, uint32_t y, uint32_t color);
|
void drawPixel(uint32_t x, uint32_t y, uint32_t color);
|
||||||
|
|
||||||
void drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size),
|
void drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size),
|
||||||
@@ -568,6 +569,7 @@ class TFT_eSprite : public TFT_eSPI {
|
|||||||
setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1),
|
setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1),
|
||||||
pushColor(uint32_t color),
|
pushColor(uint32_t color),
|
||||||
pushColor(uint32_t color, uint16_t len),
|
pushColor(uint32_t color, uint16_t len),
|
||||||
|
writeColor(uint16_t color),
|
||||||
|
|
||||||
drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color),
|
drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color),
|
||||||
drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color),
|
drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color),
|
||||||
@@ -601,10 +603,12 @@ class TFT_eSprite : public TFT_eSPI {
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
uint16_t *_img;
|
uint16_t *_img;
|
||||||
|
uint8_t *_img8;
|
||||||
|
bool _created;
|
||||||
|
|
||||||
int32_t _icursor_x, _icursor_y, _xs, _ys, _xe, _ye, _xptr, _yptr;
|
int32_t _icursor_x, _icursor_y, _xs, _ys, _xe, _ye, _xptr, _yptr;
|
||||||
|
|
||||||
int32_t _iwidth, _iheight; // Display w/h as modified by current rotation
|
uint32_t _iwidth, _iheight, _bpp16;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
205
examples/Sprite/Sprite_scroll_8bit/Sprite_scroll_8bit.ino
Normal file
205
examples/Sprite/Sprite_scroll_8bit/Sprite_scroll_8bit.ino
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
Display "flicker free" scrolling text and updating number
|
||||||
|
|
||||||
|
This sketch uses 8 bit colour sprites to save RAM.
|
||||||
|
|
||||||
|
Example for library:
|
||||||
|
https://github.com/Bodmer/TFT_eSPI
|
||||||
|
|
||||||
|
The sketch has been tested on a 320x240 ILI9341 based TFT, it
|
||||||
|
coule be adapted for other screen sizes.
|
||||||
|
|
||||||
|
A Sprite is notionally an invisible graphics screen that is
|
||||||
|
kept in the processors RAM. Graphics can be drawn into the
|
||||||
|
Sprite just as it can be drawn directly to the screen. Once
|
||||||
|
the Sprite is completed it can be plotted onto the screen in
|
||||||
|
any position. If there is sufficient RAM then the Sprite can
|
||||||
|
be the same size as the screen and used as a frame buffer.
|
||||||
|
|
||||||
|
A 16 bit colour Sprite occupies (2 * width * height) bytes.
|
||||||
|
|
||||||
|
An 8 bit colour Sprite occupies (width * height) bytes.
|
||||||
|
|
||||||
|
On a ESP8266, 16 bit Sprite sizes up to 128 x 160 can be accomodated,
|
||||||
|
this size requires 128*160*2 bytes (40kBytes) of RAM.
|
||||||
|
|
||||||
|
This sketch sets the colour depth to 8 bits so larger sprites can be
|
||||||
|
created. 8 bit colour sprites use half amount of RAM. If the colour
|
||||||
|
depth is not specified then 16 bits is assumed.
|
||||||
|
|
||||||
|
You need to make the sprite small enough to fit, with RAM spare for
|
||||||
|
any "local variables" that may be needed by your sketch and libraries.
|
||||||
|
|
||||||
|
Created by Bodmer 21/11/17
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
|
||||||
|
#########################################################################
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Size of sprite image for the scrolling text, this requires ~14 Kbytes of RAM
|
||||||
|
#define IWIDTH 240
|
||||||
|
#define IHEIGHT 30
|
||||||
|
|
||||||
|
// Pause in milliseconds to set scroll speed
|
||||||
|
#define WAIT 0
|
||||||
|
|
||||||
|
#include <TFT_eSPI.h> // Include the graphics library (this includes the sprite functions)
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI(); // Create object "tft"
|
||||||
|
|
||||||
|
TFT_eSprite img = TFT_eSprite(&tft); // Create Sprite object "img" with pointer to "tft" object
|
||||||
|
// // the pointer is used by pushSprite() to push it onto the TFT
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Setup
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
void setup(void) {
|
||||||
|
tft.init();
|
||||||
|
tft.setRotation(0);
|
||||||
|
|
||||||
|
tft.fillScreen(TFT_BLUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Main loop
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Set colour depth of Sprite to 8 (or 16) bits
|
||||||
|
img.setColorDepth(8);
|
||||||
|
|
||||||
|
// Create the sprite and clear background to black
|
||||||
|
img.createSprite(IWIDTH, IHEIGHT);
|
||||||
|
//img.fillSprite(TFT_BLACK); // Optional here as we fill the sprite later anyway
|
||||||
|
|
||||||
|
for (int pos = IWIDTH; pos > 0; pos--)
|
||||||
|
{
|
||||||
|
build_banner("Hello World", pos);
|
||||||
|
img.pushSprite(0, 0);
|
||||||
|
|
||||||
|
build_banner("TFT_eSPI sprite" , pos);
|
||||||
|
img.pushSprite(0, 50);
|
||||||
|
|
||||||
|
delay(WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete sprite to free up the memory
|
||||||
|
img.deleteSprite();
|
||||||
|
|
||||||
|
// Create a sprite of a different size
|
||||||
|
numberBox(random(100), 60, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################################################################
|
||||||
|
// Build the scrolling sprite image from scratch, draw text at x = xpos
|
||||||
|
// #########################################################################
|
||||||
|
|
||||||
|
void build_banner(String msg, int xpos)
|
||||||
|
{
|
||||||
|
int h = IHEIGHT;
|
||||||
|
|
||||||
|
// We could just use fillSprite(color) but lets be a bit more creative...
|
||||||
|
|
||||||
|
// Fill with rainbow stripes
|
||||||
|
while (h--) img.drawFastHLine(0, h, IWIDTH, rainbow(h * 4));
|
||||||
|
|
||||||
|
// Draw some graphics, the text will apear to scroll over these
|
||||||
|
img.fillRect (IWIDTH / 2 - 20, IHEIGHT / 2 - 10, 40, 20, TFT_YELLOW);
|
||||||
|
img.fillCircle(IWIDTH / 2, IHEIGHT / 2, 10, TFT_ORANGE);
|
||||||
|
|
||||||
|
// Now print text on top of the graphics
|
||||||
|
img.setTextSize(1); // Font size scaling is x1
|
||||||
|
img.setTextFont(4); // Font 4 selected
|
||||||
|
img.setTextColor(TFT_BLACK); // Black text, no background colour
|
||||||
|
img.setTextWrap(false); // Turn of wrap so we can print past end of sprite
|
||||||
|
|
||||||
|
// Need to print twice so text appears to wrap around at left and right edges
|
||||||
|
img.setCursor(xpos, 2); // Print text at xpos
|
||||||
|
img.print(msg);
|
||||||
|
|
||||||
|
img.setCursor(xpos - IWIDTH, 2); // Print text at xpos - sprite width
|
||||||
|
img.print(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################################################################
|
||||||
|
// Create sprite, plot graphics in it, plot to screen, then delete sprite
|
||||||
|
// #########################################################################
|
||||||
|
void numberBox(int num, int x, int y)
|
||||||
|
{
|
||||||
|
// Create a sprite 80 pixels wide, 50 high (8kbytes of RAM needed)
|
||||||
|
img.createSprite(80, 50);
|
||||||
|
|
||||||
|
// Fill it with black
|
||||||
|
img.fillSprite(TFT_BLACK);
|
||||||
|
|
||||||
|
// Draw a backgorund of 2 filled triangles
|
||||||
|
img.fillTriangle( 0, 0, 0, 49, 40, 25, TFT_RED);
|
||||||
|
img.fillTriangle( 79, 0, 79, 49, 40, 25, TFT_DARKGREEN);
|
||||||
|
|
||||||
|
// Set the font parameters
|
||||||
|
img.setTextSize(1); // Font size scaling is x1
|
||||||
|
img.setFreeFont(&FreeSerifBoldItalic24pt7b); // Select free font
|
||||||
|
img.setTextColor(TFT_WHITE); // White text, no background colour
|
||||||
|
|
||||||
|
// Set text coordinate datum to middle centre
|
||||||
|
img.setTextDatum(MC_DATUM);
|
||||||
|
|
||||||
|
// Draw the number in middle of 80 x 50 sprite
|
||||||
|
img.drawNumber(num, 40, 25);
|
||||||
|
|
||||||
|
// Push sprite to TFT screen CGRAM at coordinate x,y (top left corner)
|
||||||
|
img.pushSprite(x, y);
|
||||||
|
|
||||||
|
// Delete sprite to free up the RAM
|
||||||
|
img.deleteSprite();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #########################################################################
|
||||||
|
// Return a 16 bit rainbow colour
|
||||||
|
// #########################################################################
|
||||||
|
unsigned int rainbow(byte value)
|
||||||
|
{
|
||||||
|
// Value is expected to be in range 0-127
|
||||||
|
// The value is converted to a spectrum colour from 0 = red through to 127 = blue
|
||||||
|
|
||||||
|
byte red = 0; // Red is the top 5 bits of a 16 bit colour value
|
||||||
|
byte green = 0;// Green is the middle 6 bits
|
||||||
|
byte blue = 0; // Blue is the bottom 5 bits
|
||||||
|
|
||||||
|
byte sector = value >> 5;
|
||||||
|
byte amplit = value & 0x1F;
|
||||||
|
|
||||||
|
switch (sector)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
red = 0x1F;
|
||||||
|
green = amplit;
|
||||||
|
blue = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
red = 0x1F - amplit;
|
||||||
|
green = 0x1F;
|
||||||
|
blue = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
red = 0;
|
||||||
|
green = 0x1F;
|
||||||
|
blue = amplit;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
red = 0;
|
||||||
|
green = 0x1F - amplit;
|
||||||
|
blue = 0x1F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return red << 11 | green << 6 | blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user