mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-09 23:54:43 +02:00
Merge pull request #528 from kamorris/add_color_maps
Add Sprite 4 bit color depth option with a defined palette of 16 colors. Add new Sprite examples.
This commit is contained in:
@@ -36,6 +36,8 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
|
|||||||
_xpivot = 0;
|
_xpivot = 0;
|
||||||
_ypivot = 0;
|
_ypivot = 0;
|
||||||
|
|
||||||
|
_colorMap = nullptr;
|
||||||
|
|
||||||
this->cursor_y = this->cursor_x = 0; // Text cursor position
|
this->cursor_y = this->cursor_x = 0; // Text cursor position
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +57,8 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
|
|||||||
_iwidth = _dwidth = _bitwidth = w;
|
_iwidth = _dwidth = _bitwidth = w;
|
||||||
_iheight = _dheight = h;
|
_iheight = _dheight = h;
|
||||||
|
|
||||||
|
_colorMap = nullptr;
|
||||||
|
|
||||||
this->cursor_x = 0;
|
this->cursor_x = 0;
|
||||||
this->cursor_y = 0;
|
this->cursor_y = 0;
|
||||||
|
|
||||||
@@ -72,6 +76,7 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
|
|||||||
_img8_1 = _img8;
|
_img8_1 = _img8;
|
||||||
_img8_2 = _img8;
|
_img8_2 = _img8;
|
||||||
_img = (uint16_t*) _img8;
|
_img = (uint16_t*) _img8;
|
||||||
|
_img4 = _img8;
|
||||||
|
|
||||||
// This is to make it clear what pointer size is expected to be used
|
// This is to make it clear what pointer size is expected to be used
|
||||||
// but casting in the user sketch is needed due to the use of void*
|
// but casting in the user sketch is needed due to the use of void*
|
||||||
@@ -132,6 +137,17 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
|
|||||||
ptr8 = ( uint8_t*) calloc(w * h + 1, sizeof(uint8_t));
|
ptr8 = ( uint8_t*) calloc(w * h + 1, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
w = (w+1) & 0xFFFE; // width needs to be multiple of 2, with an extra "off screen" pixel
|
||||||
|
_iwidth = w;
|
||||||
|
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
|
||||||
|
if ( psramFound() ) ptr8 = ( uint8_t*) ps_calloc(((w * h) >> 1) + 1, sizeof(uint8_t));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
ptr8 = ( uint8_t*) calloc(((w * h) >> 1) + 1, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
else // Must be 1 bpp
|
else // Must be 1 bpp
|
||||||
{
|
{
|
||||||
//_dwidth Display width+height in pixels always in rotation 0 orientation
|
//_dwidth Display width+height in pixels always in rotation 0 orientation
|
||||||
@@ -154,6 +170,33 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
|
|||||||
return ptr8;
|
return ptr8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: createPalette
|
||||||
|
** Description: Set a palette for a 4-bit per pixel sprite
|
||||||
|
*************************************************************************************x*/
|
||||||
|
|
||||||
|
void TFT_eSprite::createPalette(uint16_t colorMap[], int colors)
|
||||||
|
{
|
||||||
|
if (_colorMap != nullptr)
|
||||||
|
{
|
||||||
|
free(_colorMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorMap == nullptr)
|
||||||
|
{
|
||||||
|
return; // do nothing other than clear the existing map
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate color map
|
||||||
|
_colorMap = (uint16_t *)calloc(16, sizeof(uint16_t));
|
||||||
|
if (colors > 16)
|
||||||
|
colors = 16;
|
||||||
|
for (auto i = 0; i < colors; i++)
|
||||||
|
{
|
||||||
|
_colorMap[i] = colorMap[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: frameBuffer
|
** Function name: frameBuffer
|
||||||
** Description: For 1 bpp Sprites, select the frame used for graphics
|
** Description: For 1 bpp Sprites, select the frame used for graphics
|
||||||
@@ -167,6 +210,8 @@ void* TFT_eSprite::frameBuffer(int8_t f)
|
|||||||
|
|
||||||
if (_bpp == 8) return _img8;
|
if (_bpp == 8) return _img8;
|
||||||
|
|
||||||
|
if (_bpp == 4) return _img4;
|
||||||
|
|
||||||
if ( f == 2 ) _img8 = _img8_2;
|
if ( f == 2 ) _img8 = _img8_2;
|
||||||
else _img8 = _img8_1;
|
else _img8 = _img8_1;
|
||||||
|
|
||||||
@@ -185,7 +230,8 @@ void* TFT_eSprite::setColorDepth(int8_t b)
|
|||||||
|
|
||||||
// Now define the new colour depth
|
// Now define the new colour depth
|
||||||
if ( b > 8 ) _bpp = 16; // Bytes per pixel
|
if ( b > 8 ) _bpp = 16; // Bytes per pixel
|
||||||
else if ( b > 1 ) _bpp = 8;
|
else if ( b > 4 ) _bpp = 8;
|
||||||
|
else if ( b > 1 ) _bpp = 4;
|
||||||
else _bpp = 1;
|
else _bpp = 1;
|
||||||
|
|
||||||
// If it existed, re-create the sprite with the new colour depth
|
// If it existed, re-create the sprite with the new colour depth
|
||||||
@@ -222,6 +268,28 @@ void TFT_eSprite::setBitmapColor(uint16_t c, uint16_t b)
|
|||||||
_tft->bitmap_bg = b;
|
_tft->bitmap_bg = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: setPaletteColor
|
||||||
|
** Description: Set the palette color at the given index
|
||||||
|
***************************************************************************************/
|
||||||
|
void TFT_eSprite::setPaletteColor(uint8_t index, uint16_t color)
|
||||||
|
{
|
||||||
|
if (_colorMap == nullptr || index > 15)
|
||||||
|
return; // out of bounds
|
||||||
|
_colorMap[index] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: getPaletteColor
|
||||||
|
** Description: Return the palette color at index, or 0 (black) on error.
|
||||||
|
***************************************************************************************/
|
||||||
|
uint16_t TFT_eSprite::getPaletteColor(uint8_t index)
|
||||||
|
{
|
||||||
|
if (_colorMap == nullptr || index > 15)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _colorMap[index];
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: deleteSprite
|
** Function name: deleteSprite
|
||||||
@@ -231,6 +299,11 @@ void TFT_eSprite::deleteSprite(void)
|
|||||||
{
|
{
|
||||||
if (!_created ) return;
|
if (!_created ) return;
|
||||||
|
|
||||||
|
if (_colorMap != nullptr)
|
||||||
|
{
|
||||||
|
free(_colorMap);
|
||||||
|
}
|
||||||
|
|
||||||
free(_img8_1);
|
free(_img8_1);
|
||||||
|
|
||||||
_created = false;
|
_created = false;
|
||||||
@@ -667,6 +740,13 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y)
|
|||||||
_tft->pushImage(x, y, _iwidth, _iheight, _img );
|
_tft->pushImage(x, y, _iwidth, _iheight, _img );
|
||||||
_tft->setSwapBytes(oldSwapBytes);
|
_tft->setSwapBytes(oldSwapBytes);
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
if (_colorMap == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_tft->pushImage(x, y, _dwidth, _dheight, _img4, false, _colorMap);
|
||||||
|
}
|
||||||
|
|
||||||
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8));
|
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8));
|
||||||
}
|
}
|
||||||
@@ -692,10 +772,33 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
|
|||||||
transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3);
|
transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3);
|
||||||
_tft->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true);
|
_tft->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true);
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
_tft->pushImage(x, y, _dwidth, _dheight, _img4, (uint8_t)(transp & 0x0F), false, _colorMap);
|
||||||
|
}
|
||||||
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false);
|
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
** Function name: readPixelValue
|
||||||
|
** Description: Read the color map index of a pixel at defined coordinates
|
||||||
|
*************************************************************************************x*/
|
||||||
|
uint8_t TFT_eSprite::readPixelValue(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFFFF;
|
||||||
|
|
||||||
|
if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint16_t color;
|
||||||
|
if ((x & 0x01) == 0)
|
||||||
|
return ((_img4[((x+y*_iwidth)>>1)] & 0xF0) >> 4) & 0x0F; // even index = bits 7 .. 4
|
||||||
|
else
|
||||||
|
return _img4[((x-1+y*_iwidth)>>1)] & 0x0F; // odd index = bits 3 .. 0.
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: readPixel
|
** Function name: readPixel
|
||||||
** Description: Read 565 colour of a pixel at defined coordinates
|
** Description: Read 565 colour of a pixel at defined coordinates
|
||||||
@@ -723,6 +826,16 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint16_t color;
|
||||||
|
if ((x & 0x01) == 0)
|
||||||
|
color = _colorMap[((_img4[((x+y*_iwidth)>>1)] & 0xF0) >> 4) & 0x0F ]; // even index = bits 7 .. 4
|
||||||
|
else
|
||||||
|
color = _colorMap[_img4[((x-1+y*_iwidth)>>1)] & 0x0F]; // odd index = bits 3 .. 0.
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
if (_rotation == 1)
|
if (_rotation == 1)
|
||||||
{
|
{
|
||||||
uint16_t tx = x;
|
uint16_t tx = x;
|
||||||
@@ -802,6 +915,15 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
|
|||||||
ys++;
|
ys++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
// not supported. The image is unlikely to have the correct colors for the color map.
|
||||||
|
// we could implement a way to push a 4-bit image using the color map?
|
||||||
|
#ifdef TFT_eSPI_DEBUG
|
||||||
|
Serial.println("pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) not implemented");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else // 1bpp
|
else // 1bpp
|
||||||
{
|
{
|
||||||
@@ -900,6 +1022,14 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
#ifdef TFT_eSPI_DEBUG
|
||||||
|
Serial.println("TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) not implemented");
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else // 1bpp
|
else // 1bpp
|
||||||
{
|
{
|
||||||
// Move coordinate rotation to support fn
|
// Move coordinate rotation to support fn
|
||||||
@@ -1007,6 +1137,17 @@ void TFT_eSprite::pushColor(uint32_t color)
|
|||||||
|
|
||||||
else if (_bpp == 8)
|
else if (_bpp == 8)
|
||||||
_img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
_img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
||||||
|
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint8_t c = (uint8_t)color & 0x0F;
|
||||||
|
if ((_xptr & 0x01) == 0) {
|
||||||
|
_img4[(_xptr + _yptr * _iwidth)>>1] = ((c << 4) & 0xF0) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_img4[(_xptr - 1 + _yptr * _iwidth)>>1] = (_img4[(_xptr - 1 + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else drawPixel(_xptr, _yptr, color);
|
else drawPixel(_xptr, _yptr, color);
|
||||||
|
|
||||||
@@ -1040,7 +1181,7 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
|
|||||||
else if (_bpp == 8)
|
else if (_bpp == 8)
|
||||||
pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
|
|
||||||
else pixelColor = (uint16_t) color; // for 1bpp
|
else pixelColor = (uint16_t) color; // for 1bpp or 4bpp
|
||||||
|
|
||||||
while(len--) writeColor(pixelColor);
|
while(len--) writeColor(pixelColor);
|
||||||
}
|
}
|
||||||
@@ -1060,6 +1201,15 @@ void TFT_eSprite::writeColor(uint16_t color)
|
|||||||
// Write 8 bit RGB 332 encoded colour to RAM
|
// Write 8 bit RGB 332 encoded colour to RAM
|
||||||
else if (_bpp == 8) _img8[_xptr + _yptr * _iwidth] = (uint8_t) color;
|
else if (_bpp == 8) _img8[_xptr + _yptr * _iwidth] = (uint8_t) color;
|
||||||
|
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint8_t c = (uint8_t)color & 0x0F;
|
||||||
|
if ((_xptr & 0x01) == 0)
|
||||||
|
_img4[(_xptr + _yptr * _iwidth)>>1] = ((c << 4) & 0xF0) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4
|
||||||
|
else
|
||||||
|
_img4[(_xptr - 1 + _yptr * _iwidth)>>1] = (_img4[(_xptr - 1 + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits (x is odd)
|
||||||
|
}
|
||||||
|
|
||||||
else drawPixel(_xptr, _yptr, color);
|
else drawPixel(_xptr, _yptr, color);
|
||||||
|
|
||||||
// Increment x
|
// Increment x
|
||||||
@@ -1159,7 +1309,22 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
|
|||||||
fyp += iw;
|
fyp += iw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_bpp == 1)
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
// could optimize for scrolling by even # pixels using memove (later)
|
||||||
|
if (dx > 0) { tx += w; fx += w; } // Start from right edge
|
||||||
|
while (h--)
|
||||||
|
{ // move pixels one by one
|
||||||
|
for (uint16_t xp = 0; xp < w; xp++)
|
||||||
|
{
|
||||||
|
if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy));
|
||||||
|
if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy));
|
||||||
|
}
|
||||||
|
if (dy <= 0) { ty++; fy++; }
|
||||||
|
else { ty--; fy--; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_bpp == 1 )
|
||||||
{
|
{
|
||||||
if (dx > 0) { tx += w; fx += w; } // Start from right edge
|
if (dx > 0) { tx += w; fx += w; } // Start from right edge
|
||||||
while (h--)
|
while (h--)
|
||||||
@@ -1173,7 +1338,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
|
|||||||
else { ty--; fy--; }
|
else { ty--; fy--; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return; // Not 1, 8 or 16 bpp
|
else return; // Not 1, 4, 8 or 16 bpp
|
||||||
|
|
||||||
// Fill the gap left by the scrolling
|
// Fill the gap left by the scrolling
|
||||||
if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor);
|
if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor);
|
||||||
@@ -1199,6 +1364,11 @@ void TFT_eSprite::fillSprite(uint32_t color)
|
|||||||
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
memset(_img8, (uint8_t)color, _iwidth * _iheight);
|
memset(_img8, (uint8_t)color, _iwidth * _iheight);
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint8_t c = ((color & 0x0F) | (((color & 0x0F) << 4) & 0xF0));
|
||||||
|
memset(_img4, c, (_iwidth * _iheight) >> 1);
|
||||||
|
}
|
||||||
else if (_bpp == 1)
|
else if (_bpp == 1)
|
||||||
{
|
{
|
||||||
if(color) memset(_img8, 0xFF, (_iwidth>>3) * _iheight + 1);
|
if(color) memset(_img8, 0xFF, (_iwidth>>3) * _iheight + 1);
|
||||||
@@ -1301,6 +1471,19 @@ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color)
|
|||||||
{
|
{
|
||||||
_img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
_img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint8_t c = color & 0x0F;
|
||||||
|
int index = 0;
|
||||||
|
if ((x & 0x01) == 0) {
|
||||||
|
index = (x+y*_iwidth)>>1;
|
||||||
|
_img4[index] = (uint8_t)(((c << 4) & 0xF0) | (_img4[index] & 0x0F));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = (x-1+y*_iwidth)>>1;
|
||||||
|
_img4[index] = (uint8_t)(c | (_img4[index] & 0xF0));
|
||||||
|
}
|
||||||
|
}
|
||||||
else // 1 bpp
|
else // 1 bpp
|
||||||
{
|
{
|
||||||
if (_rotation == 1)
|
if (_rotation == 1)
|
||||||
@@ -1409,6 +1592,24 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
|||||||
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
while (h--) _img8[x + _iwidth * y++] = (uint8_t) color;
|
while (h--) _img8[x + _iwidth * y++] = (uint8_t) color;
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
if ((x & 0x01) == 0)
|
||||||
|
{
|
||||||
|
uint8_t c = (uint8_t) (color & 0xF) << 4;
|
||||||
|
while (h--) {
|
||||||
|
_img4[(x + _iwidth * y)>>1] = (uint8_t) (c | _img4[(x + _iwidth * y)>>1] & 0x0F);
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint8_t c = (uint8_t)color & 0xF;
|
||||||
|
while (h--) {
|
||||||
|
_img4[(x - 1 + _iwidth * y)>>1] = (uint8_t) (c | _img4[(x - 1 + _iwidth * y)>>1] & 0xF0); // x is odd; new color goes into the low bits.
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (h--)
|
while (h--)
|
||||||
@@ -1445,8 +1646,28 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
|
|||||||
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
|
||||||
memset(_img8+_iwidth * y + x, (uint8_t)color, w);
|
memset(_img8+_iwidth * y + x, (uint8_t)color, w);
|
||||||
}
|
}
|
||||||
else
|
else if (_bpp == 4)
|
||||||
{
|
{
|
||||||
|
uint8_t c = (uint8_t)color & 0x0F;
|
||||||
|
uint8_t c2 = (c | ((c << 4) & 0xF0));
|
||||||
|
if ((x & 0x01) == 1)
|
||||||
|
{
|
||||||
|
drawPixel(x, y, color);
|
||||||
|
x++; w--;
|
||||||
|
if (w < 1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((w + x) & 0x01) == 1)
|
||||||
|
{
|
||||||
|
// handle the extra one at the other end
|
||||||
|
drawPixel(x + w - 1, y, color);
|
||||||
|
w--;
|
||||||
|
if (w < 1) return;
|
||||||
|
}
|
||||||
|
memset(_img4 + ((_iwidth * y + x) >> 1), c2, (w >> 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
while (w--)
|
while (w--)
|
||||||
{
|
{
|
||||||
drawPixel(x, y, color);
|
drawPixel(x, y, color);
|
||||||
@@ -1498,6 +1719,56 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
|
|||||||
yp += _iwidth;
|
yp += _iwidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (_bpp == 4)
|
||||||
|
{
|
||||||
|
uint8_t c1 = (uint8_t)color & 0x0F;
|
||||||
|
uint8_t c2 = c1 | ((c1 << 4) & 0xF0);
|
||||||
|
if ((x & 0x01) == 0 && (w & 0x01) == 0)
|
||||||
|
{
|
||||||
|
yp = (yp >> 1);
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
memset(_img4 + yp, c2, (w>>1));
|
||||||
|
yp += (_iwidth >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((x & 0x01) == 0)
|
||||||
|
{
|
||||||
|
// same as above but you have a hangover on the right.
|
||||||
|
yp = (yp >> 1);
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
if (w > 1)
|
||||||
|
memset(_img4 + yp, c2, (w-1)>>1);
|
||||||
|
// handle the rightmost pixel by calling drawPixel
|
||||||
|
drawPixel(x+w-1, y+h, c1);
|
||||||
|
yp += (_iwidth >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((w & 0x01) == 1)
|
||||||
|
{
|
||||||
|
yp = (yp + 1) >> 1;
|
||||||
|
while (h--) {
|
||||||
|
drawPixel(x, y+h-1, color & 0x0F);
|
||||||
|
if (w > 1)
|
||||||
|
memset(_img4 + (yp + ((x-1)>>1)), c2, (w-1)>>1);
|
||||||
|
// same as above but you have a hangover on the left instead
|
||||||
|
yp += (_iwidth >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yp = (yp + 1) >> 1;
|
||||||
|
while (h--) {
|
||||||
|
drawPixel(x, y+h-1, color & 0x0F);
|
||||||
|
drawPixel(x+w-1, y+h-1, color & 0x0F);
|
||||||
|
if (w > 2)
|
||||||
|
memset(_img4 + (yp + ((x-1)>>1)), c2, (w-2)>>1);
|
||||||
|
// maximal hacking, single pixels on left and right.
|
||||||
|
yp += (_iwidth >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (h--)
|
while (h--)
|
||||||
|
@@ -32,11 +32,20 @@ class TFT_eSprite : public TFT_eSPI {
|
|||||||
// Returns a pointer to the Sprite frame buffer
|
// Returns a pointer to the Sprite frame buffer
|
||||||
void* frameBuffer(int8_t f);
|
void* frameBuffer(int8_t f);
|
||||||
|
|
||||||
// Set or get the colour depth to 8 or 16 bits. Can be used to change depth an existing
|
// Set or get the colour depth to 4, 8 or 16 bits. Can be used to change depth an existing
|
||||||
// sprite, but clears it to black, returns a new pointer if sprite is re-created.
|
// sprite, but clears it to black, returns a new pointer if sprite is re-created.
|
||||||
void* setColorDepth(int8_t b);
|
void* setColorDepth(int8_t b);
|
||||||
int8_t getColorDepth(void);
|
int8_t getColorDepth(void);
|
||||||
|
|
||||||
|
// Set the palette for a 4 bit depth sprite. Only the first 16 colours in the map are used.
|
||||||
|
void createPalette(uint16_t *palette, int colors = 16);
|
||||||
|
|
||||||
|
// Set a single palette index to the given color
|
||||||
|
void setPaletteColor(uint8_t index, uint16_t color);
|
||||||
|
|
||||||
|
// Get the color at the given palette index
|
||||||
|
uint16_t getPaletteColor(uint8_t index);
|
||||||
|
|
||||||
// Set foreground and background colours for 1 bit per pixel Sprite
|
// Set foreground and background colours for 1 bit per pixel Sprite
|
||||||
void setBitmapColor(uint16_t fg, uint16_t bg);
|
void setBitmapColor(uint16_t fg, uint16_t bg);
|
||||||
|
|
||||||
@@ -100,7 +109,10 @@ class TFT_eSprite : public TFT_eSPI {
|
|||||||
// Read the colour of a pixel at x,y and return value in 565 format
|
// Read the colour of a pixel at x,y and return value in 565 format
|
||||||
uint16_t readPixel(int32_t x0, int32_t y0);
|
uint16_t readPixel(int32_t x0, int32_t y0);
|
||||||
|
|
||||||
// Write an image (colour bitmap) to the sprite
|
// return the color map index of the pixel at x,y (used when scrolling)
|
||||||
|
uint8_t readPixelValue(int32_t x, int32_t y);
|
||||||
|
|
||||||
|
// Write an image (colour bitmap) to the sprite. Not implemented for _bpp == 4.
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data);
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data);
|
||||||
|
|
||||||
@@ -141,9 +153,12 @@ class TFT_eSprite : public TFT_eSPI {
|
|||||||
uint8_t _bpp; // bits per pixel (1, 8 or 16)
|
uint8_t _bpp; // bits per pixel (1, 8 or 16)
|
||||||
uint16_t *_img; // pointer to 16 bit sprite
|
uint16_t *_img; // pointer to 16 bit sprite
|
||||||
uint8_t *_img8; // pointer to 8 bit sprite
|
uint8_t *_img8; // pointer to 8 bit sprite
|
||||||
|
uint8_t *_img4; // pointer to 4 bit sprite (uses color map)
|
||||||
uint8_t *_img8_1; // pointer to frame 1
|
uint8_t *_img8_1; // pointer to frame 1
|
||||||
uint8_t *_img8_2; // pointer to frame 2
|
uint8_t *_img8_2; // pointer to frame 2
|
||||||
|
|
||||||
|
uint16_t *_colorMap; // color map: 16 entries, used with 4 bit color map.
|
||||||
|
|
||||||
int16_t _xpivot; // x pivot point coordinate
|
int16_t _xpivot; // x pivot point coordinate
|
||||||
int16_t _ypivot; // y pivot point coordinate
|
int16_t _ypivot; // y pivot point coordinate
|
||||||
|
|
||||||
|
197
TFT_eSPI.cpp
197
TFT_eSPI.cpp
@@ -296,15 +296,15 @@ void TFT_eSPI::init(uint8_t tc)
|
|||||||
#if defined (TFT_DC) && (TFT_DC >= 0)
|
#if defined (TFT_DC) && (TFT_DC >= 0)
|
||||||
dcpinmask = (uint32_t) digitalPinToBitMask(TFT_DC);
|
dcpinmask = (uint32_t) digitalPinToBitMask(TFT_DC);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (TFT_WR) && (TFT_WR >= 0)
|
#if defined (TFT_WR) && (TFT_WR >= 0)
|
||||||
wrpinmask = (uint32_t) digitalPinToBitMask(TFT_WR);
|
wrpinmask = (uint32_t) digitalPinToBitMask(TFT_WR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (TFT_SCLK) && (TFT_SCLK >= 0)
|
#if defined (TFT_SCLK) && (TFT_SCLK >= 0)
|
||||||
sclkpinmask = (uint32_t) digitalPinToBitMask(TFT_SCLK);
|
sclkpinmask = (uint32_t) digitalPinToBitMask(TFT_SCLK);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (TFT_SPI_OVERLAP) && defined (ESP8266)
|
#if defined (TFT_SPI_OVERLAP) && defined (ESP8266)
|
||||||
// Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS
|
// Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS
|
||||||
// pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss);
|
// pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss);
|
||||||
@@ -372,7 +372,7 @@ void TFT_eSPI::init(uint8_t tc)
|
|||||||
delay(150); // Wait for reset to complete
|
delay(150); // Wait for reset to complete
|
||||||
|
|
||||||
spi_begin();
|
spi_begin();
|
||||||
|
|
||||||
tc = tc; // Supress warning
|
tc = tc; // Supress warning
|
||||||
|
|
||||||
// This loads the driver specific initialisation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
|
// This loads the driver specific initialisation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
|
||||||
@@ -599,7 +599,7 @@ uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
|
|||||||
uint8_t reg = 0;
|
uint8_t reg = 0;
|
||||||
#ifdef TFT_PARALLEL_8_BIT
|
#ifdef TFT_PARALLEL_8_BIT
|
||||||
|
|
||||||
writecommand(cmd_function); // Sets DC and CS high
|
writecommand(cmd_function); // Sets DC and CS high
|
||||||
|
|
||||||
busDir(dir_mask, INPUT);
|
busDir(dir_mask, INPUT);
|
||||||
|
|
||||||
@@ -676,7 +676,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
|||||||
readAddrWindow(x0, y0, 1, 1); // Sets CS low
|
readAddrWindow(x0, y0, 1, 1); // Sets CS low
|
||||||
|
|
||||||
// Set masked pins D0- D7 to input
|
// Set masked pins D0- D7 to input
|
||||||
busDir(dir_mask, INPUT);
|
busDir(dir_mask, INPUT);
|
||||||
|
|
||||||
// Dummy read to throw away don't care value
|
// Dummy read to throw away don't care value
|
||||||
readByte();
|
readByte();
|
||||||
@@ -727,7 +727,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
|||||||
|
|
||||||
// Dummy read to throw away don't care value
|
// Dummy read to throw away don't care value
|
||||||
tft_Read_8();
|
tft_Read_8();
|
||||||
|
|
||||||
//#if !defined (ILI9488_DRIVER)
|
//#if !defined (ILI9488_DRIVER)
|
||||||
|
|
||||||
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
|
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
|
||||||
@@ -940,7 +940,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d
|
|||||||
|
|
||||||
if (x < 0) { dw += x; dx = -x; x = 0; }
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
||||||
if (y < 0) { dh += y; dy = -y; y = 0; }
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
||||||
|
|
||||||
if ((x + dw) > _width ) dw = _width - x;
|
if ((x + dw) > _width ) dw = _width - x;
|
||||||
if ((y + dh) > _height) dh = _height - y;
|
if ((y + dh) > _height) dh = _height - y;
|
||||||
|
|
||||||
@@ -1073,7 +1073,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1
|
|||||||
|
|
||||||
if (x < 0) { dw += x; dx = -x; x = 0; }
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
||||||
if (y < 0) { dh += y; dy = -y; y = 0; }
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
||||||
|
|
||||||
if ((x + dw) > _width ) dw = _width - x;
|
if ((x + dw) > _width ) dw = _width - x;
|
||||||
if ((y + dh) > _height) dh = _height - y;
|
if ((y + dh) > _height) dh = _height - y;
|
||||||
|
|
||||||
@@ -1128,10 +1128,11 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1
|
|||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: pushImage
|
** Function name: pushImage
|
||||||
** Description: plot 8 bit image or sprite using a line buffer
|
** Description: plot 8 bit or 4 bit or 1 bit image or sprite using a line buffer
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8)
|
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 >= _width) || (y >= (int32_t)_height)) return;
|
||||||
|
|
||||||
int32_t dx = 0;
|
int32_t dx = 0;
|
||||||
@@ -1141,7 +1142,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da
|
|||||||
|
|
||||||
if (x < 0) { dw += x; dx = -x; x = 0; }
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
||||||
if (y < 0) { dh += y; dy = -y; y = 0; }
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
||||||
|
|
||||||
if ((x + dw) > _width ) dw = _width - x;
|
if ((x + dw) > _width ) dw = _width - x;
|
||||||
if ((y + dh) > _height) dh = _height - y;
|
if ((y + dh) > _height) dh = _height - y;
|
||||||
|
|
||||||
@@ -1192,7 +1193,59 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da
|
|||||||
data += w;
|
data += w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (cmap != nullptr)
|
||||||
|
{
|
||||||
|
bool swap = _swapBytes; _swapBytes = true;
|
||||||
|
|
||||||
|
w = (w+1) & 0xFFFE; // if this is a sprite, w will already be even; this does no harm.
|
||||||
|
bool splitFirst = (dx & 0x01) != 0; // split first means we have to push a single px from the left of the sprite / image
|
||||||
|
|
||||||
|
if (splitFirst) {
|
||||||
|
data += ((dx - 1 + dy * w) >> 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data += ((dx + dy * w) >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dh--) {
|
||||||
|
uint32_t len = dw;
|
||||||
|
uint8_t * ptr = data;
|
||||||
|
uint16_t *linePtr = lineBuf;
|
||||||
|
uint8_t colors; // two colors in one byte
|
||||||
|
uint16_t index;
|
||||||
|
|
||||||
|
if (splitFirst) {
|
||||||
|
colors = *ptr;
|
||||||
|
index = (colors & 0x0F);
|
||||||
|
*linePtr++ = cmap[index];
|
||||||
|
len--;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
colors = *ptr;
|
||||||
|
index = ((colors & 0xF0) >> 4) & 0x0F;
|
||||||
|
*linePtr++ = cmap[index];
|
||||||
|
|
||||||
|
if (len--)
|
||||||
|
{
|
||||||
|
index = colors & 0x0F;
|
||||||
|
*linePtr++ = cmap[index];
|
||||||
|
} else {
|
||||||
|
break; // nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushPixels(lineBuf, dw);
|
||||||
|
data += (w >> 1);
|
||||||
|
}
|
||||||
|
_swapBytes = swap; // Restore old value
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
while (dh--) {
|
while (dh--) {
|
||||||
w = (w+7) & 0xFFF8;
|
w = (w+7) & 0xFFF8;
|
||||||
|
|
||||||
@@ -1228,9 +1281,9 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da
|
|||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: pushImage
|
** Function name: pushImage
|
||||||
** Description: plot 8 or 1 bit image or sprite with a transparent colour
|
** Description: plot 8 or 4 or 1 bit image or sprite with a transparent colour
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transp, bool bpp8)
|
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 >= _width) || (y >= _height)) return;
|
||||||
|
|
||||||
@@ -1241,7 +1294,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da
|
|||||||
|
|
||||||
if (x < 0) { dw += x; dx = -x; x = 0; }
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
||||||
if (y < 0) { dh += y; dy = -y; y = 0; }
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
||||||
|
|
||||||
if ((x + dw) > _width ) dw = _width - x;
|
if ((x + dw) > _width ) dw = _width - x;
|
||||||
if ((y + dh) > _height) dh = _height - y;
|
if ((y + dh) > _height) dh = _height - y;
|
||||||
|
|
||||||
@@ -1311,6 +1364,97 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da
|
|||||||
data += w;
|
data += w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (cmap != nullptr) // 4bpp with color map
|
||||||
|
{
|
||||||
|
bool swap = _swapBytes; _swapBytes = true;
|
||||||
|
|
||||||
|
w = (w+1) & 0xFFFE; // here we try to recreate iwidth from dwidth.
|
||||||
|
bool splitFirst = ((dx & 0x01) != 0);
|
||||||
|
if (splitFirst) {
|
||||||
|
data += ((dx - 1 + dy * w) >> 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data += ((dx + dy * w) >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dh--) {
|
||||||
|
uint32_t len = dw;
|
||||||
|
uint8_t * ptr = data;
|
||||||
|
|
||||||
|
int32_t px = x;
|
||||||
|
bool move = true;
|
||||||
|
uint16_t np = 0;
|
||||||
|
|
||||||
|
uint8_t index; // index into cmap.
|
||||||
|
|
||||||
|
if (splitFirst) {
|
||||||
|
index = (*ptr & 0x0F); // odd = bits 3 .. 0
|
||||||
|
if (index != transp) {
|
||||||
|
move = false; setWindow(px, y, xe, ye);
|
||||||
|
lineBuf[np] = cmap[index];
|
||||||
|
np++;
|
||||||
|
}
|
||||||
|
px++; ptr++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
uint8_t color = *ptr;
|
||||||
|
|
||||||
|
// find the actual color you care about. There will be two pixels here!
|
||||||
|
// but we may only want one at the end of the row
|
||||||
|
uint16_t index = ((color & 0xF0) >> 4) & 0x0F; // high bits are the even numbers
|
||||||
|
if (index != transp) {
|
||||||
|
if (move) {
|
||||||
|
move = false; setWindow(px, y, xe, ye);
|
||||||
|
}
|
||||||
|
lineBuf[np] = cmap[index];
|
||||||
|
np++; // added a pixel
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
move = true;
|
||||||
|
if (np) {
|
||||||
|
pushPixels(lineBuf, np);
|
||||||
|
np = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
px++;
|
||||||
|
|
||||||
|
if (len--)
|
||||||
|
{
|
||||||
|
index = color & 0x0F; // the odd number is 3 .. 0
|
||||||
|
if (index != transp) {
|
||||||
|
if (move) {
|
||||||
|
move = false; setWindow(px, y, xe, ye);
|
||||||
|
}
|
||||||
|
lineBuf[np] = cmap[index];
|
||||||
|
np++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
move = true;
|
||||||
|
if (np) {
|
||||||
|
pushPixels(lineBuf, np);
|
||||||
|
np = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
px++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break; // we are done with this row.
|
||||||
|
}
|
||||||
|
ptr++; // we only increment ptr once in the loop (deliberate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (np) {
|
||||||
|
pushPixels(lineBuf, np);
|
||||||
|
np = 0;
|
||||||
|
}
|
||||||
|
data += (w>>1);
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
_swapBytes = swap; // Restore old value
|
||||||
|
}
|
||||||
else { // 1 bit per pixel
|
else { // 1 bit per pixel
|
||||||
w = (w+7) & 0xFFF8;
|
w = (w+7) & 0xFFF8;
|
||||||
while (dh--) {
|
while (dh--) {
|
||||||
@@ -1357,7 +1501,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da
|
|||||||
spi_end();
|
spi_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: setSwapBytes
|
** Function name: setSwapBytes
|
||||||
** Description: Used by 16 bit pushImage() to swap byte order in colours
|
** Description: Used by 16 bit pushImage() to swap byte order in colours
|
||||||
@@ -1566,7 +1709,7 @@ void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
|
|||||||
drawFastHLine(x0 - x, y0 - r, 2 * x+1, color);
|
drawFastHLine(x0 - x, y0 - r, 2 * x+1, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
inTransaction = false;
|
inTransaction = false;
|
||||||
spi_end(); // Does nothing if Sprite class uses this function
|
spi_end(); // Does nothing if Sprite class uses this function
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1756,7 +1899,7 @@ void TFT_eSPI::drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t
|
|||||||
drawCircleHelper(x + w - r - 1, y + r , r, 2, color);
|
drawCircleHelper(x + w - r - 1, y + r , r, 2, color);
|
||||||
drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
|
drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
|
||||||
drawCircleHelper(x + r , y + h - r - 1, r, 8, color);
|
drawCircleHelper(x + r , y + h - r - 1, r, 8, color);
|
||||||
|
|
||||||
inTransaction = false;
|
inTransaction = false;
|
||||||
spi_end(); // Does nothing if Sprite class uses this function
|
spi_end(); // Does nothing if Sprite class uses this function
|
||||||
}
|
}
|
||||||
@@ -1778,7 +1921,7 @@ void TFT_eSPI::fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t
|
|||||||
// draw four corners
|
// draw four corners
|
||||||
fillCircleHelper(x + r, y + h - r - 1, r, 1, w - r - r - 1, color);
|
fillCircleHelper(x + r, y + h - r - 1, r, 1, w - r - r - 1, color);
|
||||||
fillCircleHelper(x + r , y + r, r, 2, w - r - r - 1, color);
|
fillCircleHelper(x + r , y + r, r, 2, w - r - r - 1, color);
|
||||||
|
|
||||||
inTransaction = false;
|
inTransaction = false;
|
||||||
spi_end(); // Does nothing if Sprite class uses this function
|
spi_end(); // Does nothing if Sprite class uses this function
|
||||||
}
|
}
|
||||||
@@ -2396,7 +2539,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32
|
|||||||
yo = pgm_read_byte(&glyph->yOffset);
|
yo = pgm_read_byte(&glyph->yOffset);
|
||||||
uint8_t xx, yy, bits=0, bit=0;
|
uint8_t xx, yy, bits=0, bit=0;
|
||||||
int16_t xo16 = 0, yo16 = 0;
|
int16_t xo16 = 0, yo16 = 0;
|
||||||
|
|
||||||
if(size > 1) {
|
if(size > 1) {
|
||||||
xo16 = xo;
|
xo16 = xo;
|
||||||
yo16 = yo;
|
yo16 = yo;
|
||||||
@@ -2644,7 +2787,7 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
|
|||||||
{
|
{
|
||||||
spi_begin();
|
spi_begin();
|
||||||
if (swap) {swap = _swapBytes; _swapBytes = true; }
|
if (swap) {swap = _swapBytes; _swapBytes = true; }
|
||||||
|
|
||||||
pushPixels(data, len);
|
pushPixels(data, len);
|
||||||
|
|
||||||
_swapBytes = swap; // Restore old value
|
_swapBytes = swap; // Restore old value
|
||||||
@@ -2736,7 +2879,7 @@ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
|||||||
setWindow(x, y, x, y + h - 1);
|
setWindow(x, y, x, y + h - 1);
|
||||||
|
|
||||||
pushBlock(color, h);
|
pushBlock(color, h);
|
||||||
|
|
||||||
spi_end();
|
spi_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2761,7 +2904,7 @@ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
|
|||||||
setWindow(x, y, x + w - 1, y);
|
setWindow(x, y, x + w - 1, y);
|
||||||
|
|
||||||
pushBlock(color, w);
|
pushBlock(color, w);
|
||||||
|
|
||||||
spi_end();
|
spi_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2774,7 +2917,7 @@ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col
|
|||||||
{
|
{
|
||||||
// Clipping
|
// Clipping
|
||||||
if ((x >= _width) || (y >= _height)) return;
|
if ((x >= _width) || (y >= _height)) return;
|
||||||
|
|
||||||
if (x < 0) { w += x; x = 0; }
|
if (x < 0) { w += x; x = 0; }
|
||||||
if (y < 0) { h += y; y = 0; }
|
if (y < 0) { h += y; y = 0; }
|
||||||
|
|
||||||
@@ -3790,7 +3933,7 @@ void TFT_eSPI::setFreeFont(const GFXfont *f)
|
|||||||
glyph_ab = 0;
|
glyph_ab = 0;
|
||||||
glyph_bb = 0;
|
glyph_bb = 0;
|
||||||
uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first);
|
uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first);
|
||||||
|
|
||||||
// Find the biggest above and below baseline offsets
|
// Find the biggest above and below baseline offsets
|
||||||
for (uint8_t c = 0; c < numChars; c++) {
|
for (uint8_t c = 0; c < numChars; c++) {
|
||||||
GFXglyph *glyph1 = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
|
GFXglyph *glyph1 = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
|
||||||
@@ -3814,7 +3957,7 @@ void TFT_eSPI::setTextFont(uint8_t f)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: setFreeFont
|
** Function name: setFreeFont
|
||||||
** Descriptions: Sets the GFX free font to use
|
** Descriptions: Sets the GFX free font to use
|
||||||
|
@@ -399,13 +399,14 @@ class TFT_eSPI : public Print {
|
|||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data);
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint16_t transparent);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint16_t transparent);
|
||||||
|
|
||||||
|
|
||||||
// These are used to render images stored in FLASH (PROGMEM)
|
// These are used to render images stored in FLASH (PROGMEM)
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent);
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data);
|
||||||
|
|
||||||
// These are used by pushSprite for 1 and 8 bit colours
|
// These are used by pushSprite for 1, 4 and 8 bit colours (color map needed for 4 bit)
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data, bool bpp8 = true);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data, bool bpp8 = true, uint16_t *cmap = nullptr);
|
||||||
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true);
|
void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true, uint16_t *cmap = nullptr);
|
||||||
|
|
||||||
// Write a solid block of a single colour
|
// Write a solid block of a single colour
|
||||||
void pushBlock(uint16_t color, uint32_t len);
|
void pushBlock(uint16_t color, uint32_t len);
|
||||||
|
208
examples/Sprite/Sprite_colorMap/Sprite_colorMap.ino
Normal file
208
examples/Sprite/Sprite_colorMap/Sprite_colorMap.ino
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Sketch to show how a Sprite is created, how to draw pixels
|
||||||
|
and text within the Sprite and then push the Sprite onto
|
||||||
|
the display screen.
|
||||||
|
|
||||||
|
Example for library:
|
||||||
|
https://github.com/Bodmer/TFT_eSPI
|
||||||
|
|
||||||
|
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 Sprite occupies (2 * width * height) bytes in RAM.
|
||||||
|
|
||||||
|
On a ESP8266 Sprite sizes up to 126 x 160 can be accomodated,
|
||||||
|
this size requires 40kBytes of RAM for a 16 bit color depth.
|
||||||
|
|
||||||
|
When 8 bit color depth sprites are created they occupy
|
||||||
|
(width * height) bytes in RAM, so larger sprites can be
|
||||||
|
created, or the RAM required is halved.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set delay after plotting the sprite
|
||||||
|
#define DELAY 1000
|
||||||
|
|
||||||
|
// Width and height of sprite
|
||||||
|
#define WIDTH 128
|
||||||
|
#define HEIGHT 128
|
||||||
|
|
||||||
|
#include <TFT_eSPI.h> // Include the graphics library (this includes the sprite functions)
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI(); // Declare object "tft"
|
||||||
|
|
||||||
|
TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object
|
||||||
|
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(250000);
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// Initialise the TFT registers
|
||||||
|
tft.init();
|
||||||
|
|
||||||
|
spr.setColorDepth(4);
|
||||||
|
|
||||||
|
// Create a sprite of defined size
|
||||||
|
spr.createSprite(WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
// Clear the TFT screen to blue
|
||||||
|
tft.fillScreen(TFT_BLUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(void)
|
||||||
|
{
|
||||||
|
// Fill the whole sprite with color 5 (Sprite is in memory so not visible yet)
|
||||||
|
spr.fillSprite(10);
|
||||||
|
|
||||||
|
// create a color map with known colors
|
||||||
|
uint16_t cmap[16];
|
||||||
|
|
||||||
|
|
||||||
|
cmap[0] = TFT_BLACK;
|
||||||
|
cmap[1] = TFT_NAVY;
|
||||||
|
cmap[2] = TFT_DARKGREEN;
|
||||||
|
cmap[3] = TFT_DARKCYAN;
|
||||||
|
cmap[4] = TFT_MAROON;
|
||||||
|
cmap[5] = TFT_PURPLE;
|
||||||
|
cmap[6] = TFT_OLIVE;
|
||||||
|
cmap[7] = TFT_LIGHTGREY;
|
||||||
|
cmap[8] = TFT_DARKGREY;
|
||||||
|
cmap[9] = TFT_BLUE;
|
||||||
|
cmap[10] = TFT_GREEN;
|
||||||
|
cmap[11] = TFT_CYAN;
|
||||||
|
cmap[12] = TFT_RED;
|
||||||
|
cmap[13] = TFT_MAGENTA;
|
||||||
|
cmap[14] = TFT_YELLOW;
|
||||||
|
cmap[15] = TFT_WHITE;
|
||||||
|
|
||||||
|
spr.createPalette(cmap, 16);
|
||||||
|
|
||||||
|
spr.pushSprite(-40, -40);
|
||||||
|
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2, 10);
|
||||||
|
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
|
||||||
|
|
||||||
|
// Number of pixels to draw
|
||||||
|
uint16_t n = 100;
|
||||||
|
// Draw 100 random color pixels at random positions in sprite
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
uint16_t color = random(0x10); // Returns color 0 - 0x0F
|
||||||
|
int16_t x = random(WIDTH); // Random x coordinate
|
||||||
|
int16_t y = random(HEIGHT); // Random y coordinate
|
||||||
|
spr.drawPixel( x, y, color); // Draw pixel in sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
spr.pushSprite(-40, -40);
|
||||||
|
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2);
|
||||||
|
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
|
||||||
|
|
||||||
|
delay(DELAY);
|
||||||
|
|
||||||
|
// Draw some lines
|
||||||
|
spr.drawLine(1, 0, WIDTH, HEIGHT-1, 6);
|
||||||
|
spr.drawLine(0, 0, WIDTH, HEIGHT, 6);
|
||||||
|
spr.drawLine(0, 1, WIDTH-1, HEIGHT, 2);
|
||||||
|
spr.drawLine(0, HEIGHT-1, WIDTH-1, 0, 2);
|
||||||
|
spr.drawLine(0, HEIGHT, WIDTH, 0, 3);
|
||||||
|
spr.drawLine(1, HEIGHT, WIDTH, 1, 3);
|
||||||
|
spr.drawLine(4, 0, 4, HEIGHT-1, 11);
|
||||||
|
spr.drawLine(0, 16, WIDTH-1, 16, 13);
|
||||||
|
|
||||||
|
// draw some circles with random colors.
|
||||||
|
spr.drawCircle(20, 60, 10, 6);
|
||||||
|
spr.drawCircle(80, 60, 15, 7);
|
||||||
|
spr.drawCircle(50, 108, 5, 9);
|
||||||
|
spr.drawCircle(45, 86, 3, 8);
|
||||||
|
spr.fillCircle(102, 56, 4, 11);
|
||||||
|
|
||||||
|
spr.fillRect(28, 32, 40, 4, 5);
|
||||||
|
//spr.fillRect(27, 42, 40, 14, 6);
|
||||||
|
//spr.fillRect(33, 55, 3, 4, 7);
|
||||||
|
//spr.fillRect(34, 32, 7, 4, 8);
|
||||||
|
|
||||||
|
// Draw some text with Middle Centre datum
|
||||||
|
spr.setTextDatum(MC_DATUM);
|
||||||
|
spr.drawString("Sprite", WIDTH / 2, HEIGHT / 2, 1);
|
||||||
|
|
||||||
|
// Now push the sprite to the TFT at position 0,0 on screen
|
||||||
|
spr.pushSprite(-40, -40);
|
||||||
|
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2);
|
||||||
|
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
|
||||||
|
|
||||||
|
delay(DELAY * 4);
|
||||||
|
|
||||||
|
// create a new color map and use it instead
|
||||||
|
|
||||||
|
for (auto i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
cmap[i] = random(0x10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
spr.createPalette(cmap, 16);
|
||||||
|
// Now push the sprite to the TFT at position 0,0 on screen
|
||||||
|
|
||||||
|
spr.pushSprite(-40, -40);
|
||||||
|
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2);
|
||||||
|
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
|
||||||
|
|
||||||
|
delay(DELAY);
|
||||||
|
|
||||||
|
// Fill TFT screen with blue
|
||||||
|
tft.fillScreen(TFT_BLUE);
|
||||||
|
|
||||||
|
// Draw a blue rectangle in sprite so when we move it 1 pixel it does not leave a trail
|
||||||
|
// on the blue screen background
|
||||||
|
cmap[14] = TFT_BLUE;
|
||||||
|
spr.createPalette(cmap, 16);
|
||||||
|
|
||||||
|
spr.drawRect(0, 0, WIDTH, HEIGHT, 14);
|
||||||
|
|
||||||
|
int x = tft.width() / 2 - WIDTH / 2;
|
||||||
|
int y = tft.height() / 2 - HEIGHT / 2;
|
||||||
|
|
||||||
|
uint32_t updateTime = 0; // time for next update
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Random movement direction
|
||||||
|
int dx = 1; if (random(2)) dx = -1;
|
||||||
|
int dy = 1; if (random(2)) dy = -1;
|
||||||
|
|
||||||
|
// Pull it back onto screen if it wanders off
|
||||||
|
if (x < -WIDTH/2) dx = 1;
|
||||||
|
if (x >= tft.width()-WIDTH/2) dx = -1;
|
||||||
|
if (y < -HEIGHT/2) dy = 1;
|
||||||
|
if (y >= tft.height()-HEIGHT/2) dy = -1;
|
||||||
|
|
||||||
|
// Draw it 50 time, moving in random direct or staying still
|
||||||
|
n = 50;
|
||||||
|
int wait = random (50);
|
||||||
|
while (n)
|
||||||
|
{
|
||||||
|
if (updateTime <= millis())
|
||||||
|
{
|
||||||
|
// Use time delay so sprite does not move fast when not all on screen
|
||||||
|
updateTime = millis() + wait;
|
||||||
|
|
||||||
|
// Push the sprite to the TFT screen
|
||||||
|
spr.pushSprite(x, y);
|
||||||
|
|
||||||
|
// Change coord for next loop
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
n--;
|
||||||
|
yield(); // Stop watchdog reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Infinite while, will not exit!
|
||||||
|
}
|
||||||
|
|
141
examples/Sprite/Sprite_scroll_cmap/Sprite_scroll_cmap.ino
Normal file
141
examples/Sprite/Sprite_scroll_cmap/Sprite_scroll_cmap.ino
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
Sketch to show scrolling of the graphics in sprites.
|
||||||
|
Scrolling in this way moves the pixels in a defined rectangle
|
||||||
|
within the Sprite. By defalt the whole sprite is scrolled.
|
||||||
|
The gap left by scrolling is filled with a defined colour.
|
||||||
|
|
||||||
|
Example for library:
|
||||||
|
https://github.com/Bodmer/TFT_eSPI
|
||||||
|
|
||||||
|
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 Sprite occupies (2 * width * height) bytes in RAM.
|
||||||
|
|
||||||
|
An 8 bit Sprite occupies (width * height) bytes in RAM.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <TFT_eSPI.h>
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI();
|
||||||
|
|
||||||
|
TFT_eSprite graph1 = TFT_eSprite(&tft); // Sprite object graph1
|
||||||
|
|
||||||
|
TFT_eSprite stext1 = TFT_eSprite(&tft); // Sprite object stext1
|
||||||
|
|
||||||
|
TFT_eSprite stext2 = TFT_eSprite(&tft); // Sprite object stext2
|
||||||
|
|
||||||
|
int graphVal = 1;
|
||||||
|
int delta = 1;
|
||||||
|
int grid = 0;
|
||||||
|
int tcount = 0;
|
||||||
|
|
||||||
|
uint16_t cmap[16];
|
||||||
|
|
||||||
|
//==========================================================================================
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(250000);
|
||||||
|
tft.init();
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
cmap[0] = TFT_BLACK;
|
||||||
|
cmap[1] = TFT_ORANGE;
|
||||||
|
cmap[2] = TFT_DARKGREEN;
|
||||||
|
cmap[3] = TFT_DARKCYAN;
|
||||||
|
cmap[4] = TFT_MAROON;
|
||||||
|
cmap[5] = TFT_PURPLE;
|
||||||
|
cmap[6] = TFT_OLIVE;
|
||||||
|
cmap[7] = TFT_DARKGREY;
|
||||||
|
cmap[8] = TFT_ORANGE;
|
||||||
|
cmap[9] = TFT_BLUE;
|
||||||
|
cmap[10] = TFT_GREEN;
|
||||||
|
cmap[11] = TFT_CYAN;
|
||||||
|
cmap[12] = TFT_RED;
|
||||||
|
cmap[13] = TFT_NAVY;
|
||||||
|
cmap[14] = TFT_YELLOW;
|
||||||
|
cmap[15] = TFT_WHITE;
|
||||||
|
|
||||||
|
// Create a sprite for the graph
|
||||||
|
graph1.setColorDepth(4);
|
||||||
|
graph1.createSprite(128, 61);
|
||||||
|
graph1.createPalette(cmap, 16);
|
||||||
|
graph1.fillSprite(9); // Note: Sprite is filled with black when created
|
||||||
|
|
||||||
|
// The scroll area is set to the full sprite size upon creation of the sprite
|
||||||
|
// but we can change that by defining a smaller area using "setScrollRect()"if needed
|
||||||
|
// parameters are x,y,w,h,color as in drawRect(), the color fills the gap left by scrolling
|
||||||
|
//graph1.setScrollRect(64, 0, 64, 61, TFT_DARKGREY); // Try this line to change the graph scroll area
|
||||||
|
|
||||||
|
// Create a sprite for the scrolling numbers
|
||||||
|
stext1.setColorDepth(4);
|
||||||
|
stext1.createSprite(32, 64);
|
||||||
|
stext1.createPalette(cmap, 16);
|
||||||
|
stext1.fillSprite(9); // Fill sprite with blue
|
||||||
|
stext1.setScrollRect(0, 0, 32, 64, 9); // here we set scroll gap fill color to blue
|
||||||
|
stext1.setTextColor(15); // White text, no background
|
||||||
|
stext1.setTextDatum(BR_DATUM); // Bottom right coordinate datum
|
||||||
|
|
||||||
|
// Create a sprite for Hello World
|
||||||
|
stext2.setColorDepth(4);
|
||||||
|
stext2.createSprite(80, 16);
|
||||||
|
stext2.createPalette(cmap, 16);
|
||||||
|
stext2.fillSprite(7);
|
||||||
|
stext2.setScrollRect(0, 0, 40, 16, 7); // Scroll the "Hello" in the first 40 pixels
|
||||||
|
stext2.setTextColor(15); // White text, no background
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================================
|
||||||
|
void loop() {
|
||||||
|
// Draw point in graph1 sprite at far right edge (this will scroll left later)
|
||||||
|
graph1.drawFastVLine(127,60-graphVal,2,14); // draw 2 pixel point on graph
|
||||||
|
|
||||||
|
// Draw number in stext1 sprite at 31,63 (bottom right datum set)
|
||||||
|
stext1.drawNumber(graphVal, 31, 63, 2); // plot value in font 2
|
||||||
|
|
||||||
|
// Push the sprites onto the TFT at specied coordinates
|
||||||
|
graph1.pushSprite(0, 0);
|
||||||
|
stext1.pushSprite(0, 64);
|
||||||
|
stext2.pushSprite(40, 70);
|
||||||
|
|
||||||
|
// Change the value to plot
|
||||||
|
graphVal+=delta;
|
||||||
|
|
||||||
|
// If the value reaches a limit, then change delta of value
|
||||||
|
if (graphVal >= 60) delta = -1; // ramp down value
|
||||||
|
else if (graphVal <= 1) delta = +1; // ramp up value
|
||||||
|
|
||||||
|
delay(50); // wait so things do not scroll too fast
|
||||||
|
|
||||||
|
// Now scroll the sprites scroll(dt, dy) where:
|
||||||
|
// dx is pixels to scroll, left = negative value, right = positive value
|
||||||
|
// dy is pixels to scroll, up = negative value, down = positive value
|
||||||
|
graph1.scroll(-1, 0); // scroll graph 1 pixel left, 0 up/down
|
||||||
|
stext1.scroll(0,-16); // scroll stext 0 pixels left/right, 16 up
|
||||||
|
stext2.scroll(1); // scroll stext 1 pixel right, up/down default is 0
|
||||||
|
|
||||||
|
// Draw the grid on far right edge of sprite as graph has now moved 1 pixel left
|
||||||
|
grid++;
|
||||||
|
if (grid >= 10)
|
||||||
|
{ // Draw a vertical line if we have scrolled 10 times (10 pixels)
|
||||||
|
grid = 0;
|
||||||
|
graph1.drawFastVLine(127, 0, 61, 13); // draw line on graph
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Otherwise draw points spaced 10 pixels for the horizontal grid lines
|
||||||
|
for (int p = 0; p <= 60; p += 10) graph1.drawPixel(127, p, 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcount--;
|
||||||
|
if (tcount <=0)
|
||||||
|
{ // If we have scrolled 40 pixels the redraw text
|
||||||
|
tcount = 40;
|
||||||
|
stext2.drawString("Hello World", 6, 0, 2); // draw at 6,0 in sprite, font 2
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Loop back and do it all again
|
||||||
|
//==========================================================================================
|
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
Sketch to show creation of a sprite with a transparent
|
||||||
|
background, then plot it on the TFT.
|
||||||
|
|
||||||
|
Example for library:
|
||||||
|
https://github.com/Bodmer/TFT_eSPI
|
||||||
|
|
||||||
|
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 Sprite occupies (2 * width * height) bytes in RAM.
|
||||||
|
|
||||||
|
On a ESP8266 Sprite sizes up to 126 x 160 can be accomodated,
|
||||||
|
this size requires 40kBytes of RAM for a 16 bit colour depth.
|
||||||
|
|
||||||
|
When 8 bit colour depth sprites are created they occupy
|
||||||
|
(width * height) bytes in RAM, so larger sprites can be
|
||||||
|
created, or the RAM required is halved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
TFT_eSprite img2 = TFT_eSprite(&tft);
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(250000);
|
||||||
|
|
||||||
|
tft.init();
|
||||||
|
|
||||||
|
tft.setRotation(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
tft.fillScreen(TFT_NAVY);
|
||||||
|
|
||||||
|
img.setColorDepth(4);
|
||||||
|
|
||||||
|
// Draw 10 sprites containing a "transparent" colour
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
int x = random(240-70);
|
||||||
|
int y = random(320-80);
|
||||||
|
int c = random(0x0F); // Random colour (4 bit index into color map). Leave 15 for transparent.
|
||||||
|
drawStar(x, y, c); // note: not random; should be c
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
uint32_t dt = millis();
|
||||||
|
|
||||||
|
// Now go bananas and draw 500 nore
|
||||||
|
for (int i = 0; i < 500; i++)
|
||||||
|
{
|
||||||
|
int x = random(240-70);
|
||||||
|
int y = random(320-80);
|
||||||
|
int c = random(0x10); // Random colour
|
||||||
|
drawStar(x, y, c);
|
||||||
|
yield(); // Stop watchdog reset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show time in milliseconds to draw and then push 1 sprite to TFT screen
|
||||||
|
numberBox( 10, 10, (millis()-dt)/500.0 );
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################################################################
|
||||||
|
// Create sprite, plot graphics in it, plot to screen, then delete sprite
|
||||||
|
// #########################################################################
|
||||||
|
void drawStar(int x, int y, int star_color)
|
||||||
|
{
|
||||||
|
// Create an 8 bit sprite 70x 80 pixels (uses 5600 bytes of RAM)
|
||||||
|
img.setColorDepth(4);
|
||||||
|
img.createSprite(70, 80);
|
||||||
|
|
||||||
|
uint16_t cmap[16];
|
||||||
|
|
||||||
|
cmap[0] = TFT_BLACK;
|
||||||
|
cmap[1] = TFT_ORANGE;
|
||||||
|
cmap[2] = TFT_DARKGREEN;
|
||||||
|
cmap[3] = TFT_DARKCYAN;
|
||||||
|
cmap[4] = TFT_MAROON;
|
||||||
|
cmap[5] = TFT_PURPLE;
|
||||||
|
cmap[6] = TFT_OLIVE;
|
||||||
|
cmap[7] = TFT_LIGHTGREY;
|
||||||
|
cmap[8] = TFT_DARKGREY;
|
||||||
|
cmap[9] = TFT_BLUE;
|
||||||
|
cmap[10] = TFT_GREEN;
|
||||||
|
cmap[11] = TFT_CYAN;
|
||||||
|
cmap[12] = TFT_RED;
|
||||||
|
cmap[13] = TFT_MAGENTA;
|
||||||
|
cmap[14] = TFT_YELLOW;
|
||||||
|
cmap[15] = TFT_WHITE; // this one will be transparent.
|
||||||
|
|
||||||
|
img.createPalette(cmap, 16);
|
||||||
|
|
||||||
|
// Fill Sprite with a "transparent" colour
|
||||||
|
// TFT_TRANSPARENT is already defined for convenience
|
||||||
|
// We could also fill with any colour as "transparent" and later specify that
|
||||||
|
// same colour when we push the Sprite onto the screen.
|
||||||
|
img.fillSprite(15);
|
||||||
|
|
||||||
|
// Draw 2 triangles to create a filled in star
|
||||||
|
img.fillTriangle(35, 0, 0,59, 69,59, star_color);
|
||||||
|
img.fillTriangle(35,79, 0,20, 69,20, star_color);
|
||||||
|
|
||||||
|
// Punch a star shaped hole in the middle with a smaller transparent star
|
||||||
|
// this one damages on pixel in the second triangle
|
||||||
|
img.fillTriangle(35, 7, 6,56, 63,56, 15);
|
||||||
|
img.fillTriangle(35,73, 6,24, 63,24, 15);
|
||||||
|
|
||||||
|
// Push sprite to TFT screen at coordinate x,y (top left corner)
|
||||||
|
// Specify what colour from the map is to be treated as transparent.
|
||||||
|
img.pushSprite(x, y, 15);
|
||||||
|
|
||||||
|
// Delete it to free memory
|
||||||
|
img.deleteSprite();
|
||||||
|
}
|
||||||
|
|
||||||
|
// #########################################################################
|
||||||
|
// Draw a number in a rounded rectangle with some transparent pixels
|
||||||
|
// #########################################################################
|
||||||
|
void numberBox(int x, int y, float num )
|
||||||
|
{
|
||||||
|
|
||||||
|
// Size of sprite
|
||||||
|
#define IWIDTH 80
|
||||||
|
#define IHEIGHT 35
|
||||||
|
|
||||||
|
// Create a 8 bit sprite 80 pixels wide, 35 high (2800 bytes of RAM needed)
|
||||||
|
img.setColorDepth(8);
|
||||||
|
img.createSprite(IWIDTH, IHEIGHT);
|
||||||
|
|
||||||
|
// Fill it with black (this will be the transparent colour this time)
|
||||||
|
img.fillSprite(TFT_BLACK);
|
||||||
|
|
||||||
|
// Draw a background for the numbers
|
||||||
|
img.fillRoundRect( 0, 0, 80, 35, 15, TFT_RED);
|
||||||
|
img.drawRoundRect( 0, 0, 80, 35, 15, TFT_WHITE);
|
||||||
|
|
||||||
|
// Set the font parameters
|
||||||
|
img.setTextSize(1); // Font size scaling is x1
|
||||||
|
img.setTextColor(TFT_WHITE); // White text, no background colour
|
||||||
|
|
||||||
|
// Set text coordinate datum to middle right
|
||||||
|
img.setTextDatum(MR_DATUM);
|
||||||
|
|
||||||
|
// Draw the number to 3 decimal places at 70,20 in font 4
|
||||||
|
img.drawFloat(num, 3, 70, 20, 4);
|
||||||
|
|
||||||
|
// Push sprite to TFT screen CGRAM at coordinate x,y (top left corner)
|
||||||
|
// All black pixels will not be drawn hence will show as "transparent"
|
||||||
|
img.pushSprite(x, y, TFT_BLACK);
|
||||||
|
|
||||||
|
// Delete sprite to free up the RAM
|
||||||
|
img.deleteSprite();
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user