mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-07 06:34:44 +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;
|
||||
_ypivot = 0;
|
||||
|
||||
_colorMap = nullptr;
|
||||
|
||||
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;
|
||||
_iheight = _dheight = h;
|
||||
|
||||
_colorMap = nullptr;
|
||||
|
||||
this->cursor_x = 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_2 = _img8;
|
||||
_img = (uint16_t*) _img8;
|
||||
_img4 = _img8;
|
||||
|
||||
// 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*
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
//_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;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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
|
||||
** 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 == 4) return _img4;
|
||||
|
||||
if ( f == 2 ) _img8 = _img8_2;
|
||||
else _img8 = _img8_1;
|
||||
|
||||
@@ -185,7 +230,8 @@ void* TFT_eSprite::setColorDepth(int8_t b)
|
||||
|
||||
// Now define the new colour depth
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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
|
||||
@@ -231,6 +299,11 @@ void TFT_eSprite::deleteSprite(void)
|
||||
{
|
||||
if (!_created ) return;
|
||||
|
||||
if (_colorMap != nullptr)
|
||||
{
|
||||
free(_colorMap);
|
||||
}
|
||||
|
||||
free(_img8_1);
|
||||
|
||||
_created = false;
|
||||
@@ -667,6 +740,13 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y)
|
||||
_tft->pushImage(x, y, _iwidth, _iheight, _img );
|
||||
_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));
|
||||
}
|
||||
@@ -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);
|
||||
_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);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** 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
|
||||
** 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
// Move coordinate rotation to support fn
|
||||
@@ -1007,6 +1137,17 @@ void TFT_eSprite::pushColor(uint32_t color)
|
||||
|
||||
else if (_bpp == 8)
|
||||
_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);
|
||||
|
||||
@@ -1040,7 +1181,7 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
|
||||
else if (_bpp == 8)
|
||||
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);
|
||||
}
|
||||
@@ -1060,6 +1201,15 @@ void TFT_eSprite::writeColor(uint16_t color)
|
||||
// Write 8 bit RGB 332 encoded colour to RAM
|
||||
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);
|
||||
|
||||
// Increment x
|
||||
@@ -1159,7 +1309,22 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
|
||||
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
|
||||
while (h--)
|
||||
@@ -1173,7 +1338,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
|
||||
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
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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
|
||||
{
|
||||
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;
|
||||
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
|
||||
{
|
||||
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;
|
||||
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--)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
while (h--)
|
||||
|
@@ -32,11 +32,20 @@ class TFT_eSprite : public TFT_eSPI {
|
||||
// Returns a pointer to the Sprite frame buffer
|
||||
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.
|
||||
void* setColorDepth(int8_t b);
|
||||
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
|
||||
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
|
||||
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, const uint16_t *data);
|
||||
|
||||
@@ -141,9 +153,12 @@ class TFT_eSprite : public TFT_eSPI {
|
||||
uint8_t _bpp; // bits per pixel (1, 8 or 16)
|
||||
uint16_t *_img; // pointer to 16 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_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 _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)
|
||||
dcpinmask = (uint32_t) digitalPinToBitMask(TFT_DC);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (TFT_WR) && (TFT_WR >= 0)
|
||||
wrpinmask = (uint32_t) digitalPinToBitMask(TFT_WR);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (TFT_SCLK) && (TFT_SCLK >= 0)
|
||||
sclkpinmask = (uint32_t) digitalPinToBitMask(TFT_SCLK);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (TFT_SPI_OVERLAP) && defined (ESP8266)
|
||||
// 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);
|
||||
@@ -372,7 +372,7 @@ void TFT_eSPI::init(uint8_t tc)
|
||||
delay(150); // Wait for reset to complete
|
||||
|
||||
spi_begin();
|
||||
|
||||
|
||||
tc = tc; // Supress warning
|
||||
|
||||
// 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;
|
||||
#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);
|
||||
|
||||
@@ -676,7 +676,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
||||
readAddrWindow(x0, y0, 1, 1); // Sets CS low
|
||||
|
||||
// Set masked pins D0- D7 to input
|
||||
busDir(dir_mask, INPUT);
|
||||
busDir(dir_mask, INPUT);
|
||||
|
||||
// Dummy read to throw away don't care value
|
||||
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
|
||||
tft_Read_8();
|
||||
|
||||
|
||||
//#if !defined (ILI9488_DRIVER)
|
||||
|
||||
// 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 (y < 0) { dh += y; dy = -y; y = 0; }
|
||||
|
||||
|
||||
if ((x + dw) > _width ) dw = _width - x;
|
||||
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 (y < 0) { dh += y; dy = -y; y = 0; }
|
||||
|
||||
|
||||
if ((x + dw) > _width ) dw = _width - x;
|
||||
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
|
||||
** 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;
|
||||
|
||||
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 (y < 0) { dh += y; dy = -y; y = 0; }
|
||||
|
||||
|
||||
if ((x + dw) > _width ) dw = _width - x;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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--) {
|
||||
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
|
||||
** 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;
|
||||
|
||||
@@ -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 (y < 0) { dh += y; dy = -y; y = 0; }
|
||||
|
||||
|
||||
if ((x + dw) > _width ) dw = _width - x;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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
|
||||
w = (w+7) & 0xFFF8;
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: setSwapBytes
|
||||
** 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);
|
||||
}
|
||||
|
||||
inTransaction = false;
|
||||
inTransaction = false;
|
||||
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 + h - r - 1, r, 4, color);
|
||||
drawCircleHelper(x + r , y + h - r - 1, r, 8, color);
|
||||
|
||||
|
||||
inTransaction = false;
|
||||
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
|
||||
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);
|
||||
|
||||
|
||||
inTransaction = false;
|
||||
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);
|
||||
uint8_t xx, yy, bits=0, bit=0;
|
||||
int16_t xo16 = 0, yo16 = 0;
|
||||
|
||||
|
||||
if(size > 1) {
|
||||
xo16 = xo;
|
||||
yo16 = yo;
|
||||
@@ -2644,7 +2787,7 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
|
||||
{
|
||||
spi_begin();
|
||||
if (swap) {swap = _swapBytes; _swapBytes = true; }
|
||||
|
||||
|
||||
pushPixels(data, len);
|
||||
|
||||
_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);
|
||||
|
||||
pushBlock(color, h);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
pushBlock(color, w);
|
||||
|
||||
|
||||
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
|
||||
if ((x >= _width) || (y >= _height)) return;
|
||||
|
||||
|
||||
if (x < 0) { w += x; x = 0; }
|
||||
if (y < 0) { h += y; y = 0; }
|
||||
|
||||
@@ -3790,7 +3933,7 @@ void TFT_eSPI::setFreeFont(const GFXfont *f)
|
||||
glyph_ab = 0;
|
||||
glyph_bb = 0;
|
||||
uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first);
|
||||
|
||||
|
||||
// Find the biggest above and below baseline offsets
|
||||
for (uint8_t c = 0; c < numChars; c++) {
|
||||
GFXglyph *glyph1 = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
|
||||
@@ -3814,7 +3957,7 @@ void TFT_eSPI::setTextFont(uint8_t f)
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: setFreeFont
|
||||
** 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, uint16_t transparent);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// These are used by pushSprite for 1 and 8 bit colours
|
||||
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, uint8_t transparent, bool bpp8 = true);
|
||||
// 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, 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, uint16_t *cmap = nullptr);
|
||||
|
||||
// Write a solid block of a single colour
|
||||
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