Srite class updates + others

Add 2 new pushSprite functions:
1. Sprite to sprite
2. windowed are of sprite to screen
Examples to follow
Bug fixes to sprite class
This commit is contained in:
Bodmer
2020-08-05 20:06:44 +01:00
parent c124688ab1
commit dc114db01b
15 changed files with 507 additions and 230 deletions
+320 -115
View File
@@ -13,7 +13,7 @@
/***************************************************************************************
** Function name: TFT_eSprite
** Description: Class constructor
*************************************************************************************x*/
***************************************************************************************/
TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
{
_tft = tft; // Pointer to tft class so we can call member functions
@@ -47,14 +47,14 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
/***************************************************************************************
** Function name: createSprite
** Description: Create a sprite (bitmap) of defined width and height
*************************************************************************************x*/
***************************************************************************************/
// cast returned value to (uint8_t*) for 8 bit or (uint16_t*) for 16 bit colours
void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
{
if ( _created ) return _img8_1;
if ( w < 1 || h < 1 ) return NULL;
if ( w < 1 || h < 1 ) return nullptr;
_iwidth = _dwidth = _bitwidth = w;
_iheight = _dheight = h;
@@ -105,17 +105,28 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
if (_img8)
{
_created = true;
return _img8;
return _img8_1;
}
return NULL;
return nullptr;
}
/***************************************************************************************
** Function name: getPointer
** Description: Returns pointer to start of sprite memory area
***************************************************************************************/
void* TFT_eSprite::getPointer(void)
{
if (!_created) return nullptr;
return _img8_1;
}
/***************************************************************************************
** Function name: created
** Description: Returns true is sprite has been created
*************************************************************************************x*/
***************************************************************************************/
bool TFT_eSprite::created(void)
{
return _created;
@@ -125,7 +136,7 @@ bool TFT_eSprite::created(void)
/***************************************************************************************
** Function name: ~TFT_eSprite
** Description: Class destructor
*************************************************************************************x*/
***************************************************************************************/
TFT_eSprite::~TFT_eSprite(void)
{
deleteSprite();
@@ -139,14 +150,14 @@ TFT_eSprite::~TFT_eSprite(void)
/***************************************************************************************
** Function name: callocSprite
** Description: Allocate a memory area for the Sprite and return pointer
*************************************************************************************x*/
***************************************************************************************/
void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
{
// Add one extra "off screen" pixel to point out-of-bounds setWindow() coordinates
// this means push/writeColor functions do not need additional bounds checks and
// hence will run faster in normal circumstances.
uint8_t* ptr8 = NULL;
uint8_t* ptr8 = nullptr;
if (frames > 2) frames = 2; // Currently restricted to 2 frame buffers
if (frames < 1) frames = 1;
@@ -154,10 +165,17 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
if (_bpp == 16)
{
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
if ( psramFound() && this->_psram_enable && !_tft->DMA_Enabled) ptr8 = ( uint8_t*) ps_calloc(frames * w * h + frames, sizeof(uint16_t));
if ( psramFound() && this->_psram_enable && !_tft->DMA_Enabled)
{
ptr8 = ( uint8_t*) ps_calloc(frames * w * h + frames, sizeof(uint16_t));
//Serial.println("PSRAM");
}
else
#endif
ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint16_t));
{
ptr8 = ( uint8_t*) calloc(frames * w * h + frames, sizeof(uint16_t));
//Serial.println("Normal RAM");
}
}
else if (_bpp == 8)
@@ -203,7 +221,7 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
/***************************************************************************************
** Function name: createPalette (from RAM array)
** Description: Set a palette for a 4-bit per pixel sprite
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors)
{
@@ -223,7 +241,7 @@ void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors)
_colorMap = (uint16_t *)calloc(16, sizeof(uint16_t));
if (colors > 16) colors = 16;
// Copy map colors
for (uint8_t i = 0; i < colors; i++)
{
@@ -234,15 +252,10 @@ void TFT_eSprite::createPalette(uint16_t colorMap[], uint8_t colors)
/***************************************************************************************
** Function name: createPalette (from FLASH array)
** Description: Set a palette for a 4-bit per pixel sprite
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors)
{
if (_colorMap != nullptr)
{
free(_colorMap);
}
if (colorMap == nullptr)
{
// Create a color map using the default FLASH map
@@ -264,11 +277,11 @@ void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors)
/***************************************************************************************
** Function name: frameBuffer
** Description: For 1 bpp Sprites, select the frame used for graphics
*************************************************************************************x*/
***************************************************************************************/
// Frames are numbered 1 and 2
void* TFT_eSprite::frameBuffer(int8_t f)
{
if (!_created) return NULL;
if (!_created) return nullptr;
if ( f == 2 ) _img8 = _img8_2;
else _img8 = _img8_1;
@@ -285,34 +298,37 @@ void* TFT_eSprite::frameBuffer(int8_t f)
/***************************************************************************************
** Function name: setColorDepth
** Description: Set bits per pixel for colour (1, 8 or 16)
*************************************************************************************x*/
***************************************************************************************/
void* TFT_eSprite::setColorDepth(int8_t b)
{
// Can't change an existing sprite's colour depth so delete it
if (_created) free(_img8_1);
// Do not re-create the sprite if the colour depth does not change
if (_bpp == b) return _img8_1;
// Now define the new colour depth
// Validate the new colour depth
if ( b > 8 ) _bpp = 16; // Bytes per pixel
else if ( b > 4 ) _bpp = 8;
else if ( b > 1 ) _bpp = 4;
else _bpp = 1;
// Can't change an existing sprite's colour depth so delete it
if (_created) free(_img8_1);
// If it existed, re-create the sprite with the new colour depth
if (_created)
{
_created = false;
return createSprite(_iwidth, _iheight);
return createSprite(_dwidth, _dheight);
}
return NULL;
return nullptr;
}
/***************************************************************************************
** Function name: getColorDepth
** Description: Get bits per pixel for colour (1, 8 or 16)
*************************************************************************************x*/
***************************************************************************************/
int8_t TFT_eSprite::getColorDepth(void)
{
@@ -357,7 +373,7 @@ uint16_t TFT_eSprite::getPaletteColor(uint8_t index)
/***************************************************************************************
** Function name: deleteSprite
** Description: Delete the sprite to free up memory (RAM)
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::deleteSprite(void)
{
if (!_created ) return;
@@ -369,6 +385,8 @@ void TFT_eSprite::deleteSprite(void)
free(_img8_1);
_img8 = nullptr;
_created = false;
}
@@ -376,7 +394,7 @@ void TFT_eSprite::deleteSprite(void)
/***************************************************************************************
** Function name: setPivot
** Description: Set the pivot point in this Sprite
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::setPivot(int16_t x, int16_t y)
{
_xpivot = x;
@@ -407,7 +425,7 @@ int16_t TFT_eSprite::getPivotY(void)
/***************************************************************************************
** Function name: pushRotated - Fast fixed point integer maths version
** Description: Push rotated Sprite to TFT screen
*************************************************************************************x*/
***************************************************************************************/
#define FP_SCALE 10
bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp)
{
@@ -426,11 +444,11 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp)
int32_t xt = min_x - _tft->_xpivot;
int32_t yt = min_y - _tft->_ypivot;
uint32_t xe = _iwidth << FP_SCALE;
uint32_t ye = _iheight << FP_SCALE;
uint32_t xe = _dwidth << FP_SCALE;
uint32_t ye = _dheight << FP_SCALE;
uint32_t tpcolor = transp; // convert to unsigned
if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F];
tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes
_tft->startWrite(); // Avoid transaction overhead for every tft pixel
// Scan destination bounding box and fetch transformed pixels from source Sprite
@@ -447,8 +465,8 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp)
uint32_t rp;
int32_t xp = xs >> FP_SCALE;
int32_t yp = ys >> FP_SCALE;
if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; rp = rp>>8 | rp<<8; }
else rp = readPixel(xp, yp);
if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; }
else { rp = readPixel(xp, yp); rp = rp>>8 | rp<<8; }
if (tpcolor == rp) {
if (pixel_count) {
// TFT window is already clipped, so this is faster than pushImage()
@@ -458,7 +476,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp)
}
}
else {
sline_buffer[pixel_count++] = rp>>8 | rp<<8;
sline_buffer[pixel_count++] = rp;
}
} while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye);
if (pixel_count) {
@@ -477,7 +495,7 @@ bool TFT_eSprite::pushRotated(int16_t angle, int32_t transp)
/***************************************************************************************
** Function name: pushRotated - Fast fixed point integer maths version
** Description: Push a rotated copy of the Sprite to another Sprite
*************************************************************************************x*/
***************************************************************************************/
// Not compatible with 4bpp
bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp)
{
@@ -497,9 +515,9 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp)
int32_t xt = min_x - spr->_xpivot;
int32_t yt = min_y - spr->_ypivot;
uint32_t xe = _iwidth << FP_SCALE;
uint32_t ye = _iheight << FP_SCALE;
uint32_t tpcolor = transp; // convert to unsigned
uint32_t xe = _dwidth << FP_SCALE;
uint32_t ye = _dheight << FP_SCALE;
uint32_t tpcolor = transp>>8 | transp<<8; // convert to unsigned swapped bytes
bool oldSwapBytes = spr->getSwapBytes();
spr->setSwapBytes(false);
@@ -518,8 +536,8 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp)
uint32_t rp;
int32_t xp = xs >> FP_SCALE;
int32_t yp = ys >> FP_SCALE;
if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; rp = rp>>8 | rp<<8; }
else rp = readPixel(xp, yp);
if (_bpp == 16) rp = _img[xp + yp * _iwidth];
else { rp = readPixel(xp, yp); rp = rp>>8 | rp<<8; }
if (tpcolor == rp) {
if (pixel_count) {
spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer);
@@ -540,7 +558,7 @@ bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, int32_t transp)
/***************************************************************************************
** Function name: getRotatedBounds
** Description: Get TFT bounding box of a rotated Sprite wrt pivot
*************************************************************************************x*/
***************************************************************************************/
bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y,
int16_t *max_x, int16_t *max_y)
{
@@ -572,7 +590,7 @@ bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y
/***************************************************************************************
** Function name: getRotatedBounds
** Description: Get destination Sprite bounding box of a rotated Sprite wrt pivot
*************************************************************************************x*/
***************************************************************************************/
bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y,
int16_t *max_x, int16_t *max_y)
{
@@ -608,7 +626,7 @@ bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min
/***************************************************************************************
** Function name: rotatedBounds
** Description: Get bounding box of a rotated Sprite wrt pivot
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp,
int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y)
{
@@ -662,7 +680,7 @@ void TFT_eSprite::getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t
/***************************************************************************************
** Function name: pushSprite
** Description: Push the sprite to the TFT at x, y
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::pushSprite(int32_t x, int32_t y)
{
if (!_created) return;
@@ -671,7 +689,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y)
{
bool oldSwapBytes = _tft->getSwapBytes();
_tft->setSwapBytes(false);
_tft->pushImage(x, y, _iwidth, _iheight, _img );
_tft->pushImage(x, y, _dwidth, _dheight, _img );
_tft->setSwapBytes(oldSwapBytes);
}
else if (_bpp == 4)
@@ -685,7 +703,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y)
/***************************************************************************************
** Function name: pushSprite
** Description: Push the sprite to the TFT at x, y with transparent colour
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
{
if (!_created) return;
@@ -694,7 +712,7 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
{
bool oldSwapBytes = _tft->getSwapBytes();
_tft->setSwapBytes(false);
_tft->pushImage(x, y, _iwidth, _iheight, _img, transp );
_tft->pushImage(x, y, _dwidth, _dheight, _img, transp );
_tft->setSwapBytes(oldSwapBytes);
}
else if (_bpp == 8)
@@ -710,10 +728,171 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
}
/***************************************************************************************
** Function name: pushSprite
** Description: Push the sprite to another sprite at x, y
***************************************************************************************/
// Note: The following sprite to sprite colour depths are currently supported:
// Source Destination
// 16bpp -> 16bpp
// 16bpp -> 8bpp
// 4bpp -> 4bpp (note: color translation depends on the 2 sprites pallet colors)
// 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors)
bool TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y)
{
if (!_created) return false;
if (!spr->created()) return false;
// Check destination sprite compatibility
int8_t ds_bpp = spr->getColorDepth();
if (_bpp == 16 && ds_bpp != 16 && ds_bpp != 8) return false;
if (_bpp == 8) return false;
if (_bpp == 4 && ds_bpp != 4) return false;
if (_bpp == 1 && ds_bpp != 1) return false;
bool oldSwapBytes = spr->getSwapBytes();
spr->setSwapBytes(false);
spr->pushImage(x, y, _dwidth, _dheight, _img );
spr->setSwapBytes(oldSwapBytes);
return true;
}
/***************************************************************************************
** Function name: pushSprite
** Description: Push the sprite to another sprite at x, y with transparent colour
***************************************************************************************/
/* >>>>>> Using a transparent color is not supported at the moment <<<<<<
void TFT_eSprite::pushSprite(TFT_eSprite *spr, int32_t x, int32_t y, uint16_t transp)
{
if (!_created) return;
if (_bpp == 16)
{
bool oldSwapBytes = spr->getSwapBytes();
spr->setSwapBytes(false);
spr->pushImage(x, y, _dwidth, _dheight, _img, transp );
spr->setSwapBytes(oldSwapBytes);
}
else if (_bpp == 8)
{
transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3);
spr->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true);
}
else if (_bpp == 4)
{
spr->pushImage(x, y, _dwidth, _dheight, _img4, (uint8_t)(transp & 0x0F), false, _colorMap);
}
else spr->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false);
}
*/
/***************************************************************************************
** Function name: pushSprite
** Description: Push a cropped sprite to the TFT at tx, ty
***************************************************************************************/
bool TFT_eSprite::pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh)
{
if (!_created) return false;
// Perform window boundary checks and crop if needed
setWindow(sx, sy, sx + sw - 1, sy + sh - 1);
/* These global variables are now populated for the sprite
_xs = x start coordinate
_ys = y start coordinate
_xe = x end coordinate (inclusive)
_ye = y end coordinate (inclusive)
*/
// Calculate new sprite window bounding box width and height
sw = _xe - _xs + 1;
sh = _ye - _ys + 1;
if (_ys >= _iheight) return false;
if (_bpp == 16)
{
bool oldSwapBytes = _tft->getSwapBytes();
_tft->setSwapBytes(false);
// Check if a faster block copy to screen is possible
if ( sx == 0 && sw == _dwidth)
_tft->pushImage(tx, ty, sw, sh, _img + _iwidth * _ys );
else // Render line by line
while (sh--)
_tft->pushImage(tx, ty++, sw, 1, _img + _xs + _iwidth * _ys++ );
_tft->setSwapBytes(oldSwapBytes);
}
else if (_bpp == 8)
{
// Check if a faster block copy to screen is possible
if ( sx == 0 && sw == _dwidth)
_tft->pushImage(tx, ty, sw, sh, _img8 + _iwidth * _ys, true );
else // Render line by line
while (sh--)
_tft->pushImage(tx, ty++, sw, 1, _img8 + _xs + _iwidth * _ys++, true );
}
else if (_bpp == 4)
{
// Check if a faster block copy to screen is possible
if ( sx == 0 && sw == _dwidth)
_tft->pushImage(tx, ty, sw, sh, _img4 + (_iwidth>>1) * _ys, false, _colorMap );
else // Render line by line
{
uint32_t ds = _xs&1; // Odd x start pixel
uint32_t de = 0; // Odd x end pixel
if ((sw > ds) && (_xe&1)) de = 1;
uint32_t dm = 0; // Midsection pixel count
if (sw > (ds+de)) dm = sw - ds - de;
sw--;
uint32_t yp = (_xs + ds + _iwidth * _ys)>>1;
_tft->startWrite();
while (sh--)
{
if (ds) _tft->drawPixel(tx, ty, readPixel(_xs, _ys) );
if (dm) _tft->pushImage(tx + ds, ty, dm, 1, _img4 + yp, false, _colorMap );
if (de) _tft->drawPixel(tx + sw, ty, readPixel(_xe, _ys) );
_ys++;
ty++;
yp += (_iwidth>>1);
}
_tft->endWrite();
}
}
else // 1bpp
{
// Check if a faster block copy to screen is possible
if ( sx == 0 && sw == _dwidth)
_tft->pushImage(tx, ty, sw, sh, _img8 + (_iwidth>>3) * _ys, false );
else // Render line by line
{
_tft->startWrite();
_tft->setWindow(tx, ty, tx+sw-1, ty+sh-1);
while (sh--)
{
for (uint32_t dx = _xs; dx < _xs + sw; dx++) _tft->pushColor(readPixel(dx, _ys));
ty++;
_ys++;
}
_tft->endWrite();
}
}
return true;
}
/***************************************************************************************
** Function name: readPixelValue
** Description: Read the color map index of a pixel at defined coordinates
*************************************************************************************x*/
***************************************************************************************/
uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y)
{
if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFF;
@@ -732,6 +911,7 @@ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y)
if (_bpp == 4)
{
if (x >= _dwidth) return 0xFF;
if ((x & 0x01) == 0)
return _img4[((x+y*_iwidth)>>1)] >> 4; // even index = bits 7 .. 4
else
@@ -740,6 +920,7 @@ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y)
if (_bpp == 1)
{
// Note: _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used)
if (_rotation == 1)
{
uint16_t tx = x;
@@ -767,7 +948,7 @@ uint16_t TFT_eSprite::readPixelValue(int32_t x, int32_t y)
/***************************************************************************************
** Function name: readPixel
** Description: Read 565 colour of a pixel at defined coordinates
*************************************************************************************x*/
***************************************************************************************/
uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
{
if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFFFF;
@@ -777,7 +958,7 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
uint16_t color = _img[x + y * _iwidth];
return (color >> 8) | (color << 8);
}
if (_bpp == 8)
{
uint16_t color = _img8[x + y * _iwidth];
@@ -793,6 +974,7 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
if (_bpp == 4)
{
if (x >= _dwidth) return 0xFFFF;
uint16_t color;
if ((x & 0x01) == 0)
color = _colorMap[_img4[((x+y*_iwidth)>>1)] >> 4]; // even index = bits 7 .. 4
@@ -801,6 +983,8 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
return color;
}
// Note: Must be 1bpp
// _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used)
if (_rotation == 1)
{
uint16_t tx = x;
@@ -828,18 +1012,19 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
/***************************************************************************************
** Function name: pushImage
** Description: push 565 colour image into a defined area of a sprite
*************************************************************************************x*/
** Description: push image into a defined area of a sprite
***************************************************************************************/
void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
{
if ((x >= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0) || !_created) return;
if (data == nullptr || !_created) return;
if ((x >= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0)) return;
if ((x + w < 0) || (y + h < 0)) return;
int32_t xo = 0;
int32_t yo = 0;
int32_t xo = 0;
int32_t yo = 0;
int32_t xs = x;
int32_t ys = y;
int32_t xs = x;
int32_t ys = y;
int32_t ws = w;
int32_t hs = h;
@@ -852,17 +1037,34 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite
{
for (int32_t yp = yo; yp < yo + hs; yp++)
// Pointer within original image
uint8_t *ptro = (uint8_t *)data + ((xo + yo * w) << 1);
// Pointer within sprite image
uint8_t *ptrs = (uint8_t *)_img + ((xs + ys * _iwidth) << 1);
if(_iswapBytes)
{
x = xs;
for (int32_t xp = xo; xp < xo + ws; xp++)
while (hs--)
{
uint16_t color = data[xp + yp * w];
if(_iswapBytes) color = color<<8 | color>>8;
_img[x + ys * _iwidth] = color;
x++;
// Fast copy with a 1 byte shift
memcpy(ptrs+1, ptro, (ws<<1) - 1);
// Now correct just the even numbered bytes
for (int32_t xp = 0; xp < (ws<<1); xp+=2)
{
ptrs[xp] = ptro[xp+1];;
}
ptro += w<<1;
ptrs += _iwidth<<1;
}
}
else
{
while (hs--)
{
memcpy(ptrs, ptro, ws<<1);
ptro += w << 1;
ptrs += _iwidth << 1;
}
ys++;
}
}
else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite
@@ -873,8 +1075,9 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
for (int32_t xp = xo; xp < xo + ws; xp++)
{
uint16_t color = data[xp + yp * w];
if(_iswapBytes) color = color<<8 | color>>8;
_img8[x + ys * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
// When data source is a sprite, the bytes are already swapped
if(!_iswapBytes) _img8[x + ys * _iwidth] = (uint8_t)((color & 0xE0) | (color & 0x07)<<2 | (color & 0x1800)>>11);
else _img8[x + ys * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
x++;
}
ys++;
@@ -882,13 +1085,13 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
}
else if (_bpp == 4)
{
// the image is assumed to be 4 bit, where each byte corresponds to two pixels.
// The image is assumed to be 4 bit, where each byte corresponds to two pixels.
// much faster when aligned to a byte boundary, because the alternative is slower, requiring
// tedious bit operations.
const uint8_t *dataBuf = (uint8_t *)data;
int sWidth = (_iwidth >> 1);
if ((xs & 0x01) == 0 && (xo & 0x01) == 0 && (ws & 0x01) == 0)
{
if ((ws & 0x01) == 0) // use memcpy for better perf.
@@ -906,6 +1109,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
}
else // not optimized
{
// _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used)
for (int32_t yp = yo; yp < yo + hs; yp++)
{
x = xs;
@@ -917,7 +1121,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
else
color = dataBuf[((xp-1+yp*w)>>1)] & 0x0F; // odd index = bits 3 .. 0.
drawPixel(x, ys, color);
x++;
x++;
}
ys++;
}
@@ -964,7 +1168,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
/***************************************************************************************
** Function name: pushImage
** Description: push 565 colour FLASH (PROGMEM) image into a defined area
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data)
{
#ifdef ESP32
@@ -1031,6 +1235,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u
else // 1bpp
{
// _dwidth and _dheight bounds not checked (rounded up -iwidth and _iheight used)
// Move coordinate rotation to support fn
if (_rotation == 1)
{
@@ -1090,26 +1295,26 @@ bool TFT_eSprite::getSwapBytes(void)
/***************************************************************************************
** Function name: setWindow
** Description: Set the bounds of a window for pushColor and writeColor
*************************************************************************************x*/
** Description: Set the bounds of a window in the sprite
***************************************************************************************/
void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
{
if (x0 > x1) swap_coord(x0, x1);
if (y0 > y1) swap_coord(y0, y1);
if ((x0 >= _iwidth) || (x1 < 0) || (y0 >= _iheight) || (y1 < 0))
if ((x0 >= _dwidth) || (x1 < 0) || (y0 >= _dheight) || (y1 < 0))
{ // Point to that extra "off screen" pixel
_xs = 0;
_ys = _iheight;
_ys = _dheight;
_xe = 0;
_ye = _iheight;
_ye = _dheight;
}
else
{
if (x0 < 0) x0 = 0;
if (x1 >= _iwidth) x1 = _iwidth - 1;
if (x1 >= _dwidth) x1 = _dwidth - 1;
if (y0 < 0) y0 = 0;
if (y1 >= _iheight) y1 = _iheight - 1;
if (y1 >= _dheight) y1 = _dheight - 1;
_xs = x0;
_ys = y0;
@@ -1125,7 +1330,7 @@ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
/***************************************************************************************
** Function name: pushColor
** Description: Send a new pixel to the set window
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::pushColor(uint32_t color)
{
if (!_created ) return;
@@ -1147,7 +1352,7 @@ void TFT_eSprite::pushColor(uint32_t color)
_img4[(_xptr + _yptr * _iwidth)>>1] = (_img4[(_xptr + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits
}
}
else drawPixel(_xptr, _yptr, color);
// Increment x
@@ -1167,7 +1372,7 @@ void TFT_eSprite::pushColor(uint32_t color)
/***************************************************************************************
** Function name: pushColor
** Description: Send a "len" new pixels to the set window
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
{
if (!_created ) return;
@@ -1189,7 +1394,7 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
/***************************************************************************************
** Function name: writeColor
** Description: Write a pixel with pre-formatted colour to the set window
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::writeColor(uint16_t color)
{
if (!_created ) return;
@@ -1227,7 +1432,7 @@ void TFT_eSprite::writeColor(uint16_t color)
/***************************************************************************************
** Function name: setScrollRect
** Description: Set scroll area within the sprite and the gap fill colour
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color)
{
if ((x >= _iwidth) || (y >= _iheight) || !_created ) return;
@@ -1238,7 +1443,7 @@ void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint
if ((x + w) > _iwidth ) w = _iwidth - x;
if ((y + h) > _iheight) h = _iheight - y;
if ( w < 1 || h < 1) return;
if ( w < 1 || h < 1) return;
_sx = x;
_sy = y;
@@ -1252,7 +1457,7 @@ void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint
/***************************************************************************************
** Function name: scroll
** Description: Scroll dx,dy pixels, positive right,down, negative left,up
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::scroll(int16_t dx, int16_t dy)
{
if (abs(dx) >= _sw || abs(dy) >= _sh)
@@ -1264,7 +1469,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
// Fetch the scroll area width and height set by setScrollRect()
uint32_t w = _sw - abs(dx); // line width to copy
uint32_t h = _sh - abs(dy); // lines to copy
int32_t iw = _iwidth; // width of sprite
int32_t iw = _iwidth; // rounded up width of sprite
// Fetch the x,y origin set by setScrollRect()
uint32_t tx = _sx; // to x
@@ -1350,7 +1555,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
/***************************************************************************************
** Function name: fillSprite
** Description: Fill the whole sprite with defined colour
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::fillSprite(uint32_t color)
{
if (!_created ) return;
@@ -1381,7 +1586,7 @@ void TFT_eSprite::fillSprite(uint32_t color)
/***************************************************************************************
** Function name: setCursor
** Description: Set the sprite text cursor x,y position
*************************************************************************************x*/
***************************************************************************************/
// Not needed - using TFT_eSPI class function and this->cursor_x/y
//void TFT_eSprite::setCursor(int16_t x, int16_t y)
//{
@@ -1393,13 +1598,13 @@ void TFT_eSprite::fillSprite(uint32_t color)
/***************************************************************************************
** Function name: width
** Description: Return the width of sprite
*************************************************************************************x*/
***************************************************************************************/
// Return the size of the display
int16_t TFT_eSprite::width(void)
{
if (!_created ) return 0;
if (_bpp > 1) return _iwidth;
if (_bpp > 1) return _dwidth;
if (_rotation == 1 || _rotation == 3) return _dheight;
@@ -1410,12 +1615,12 @@ int16_t TFT_eSprite::width(void)
/***************************************************************************************
** Function name: height
** Description: Return the height of sprite
*************************************************************************************x*/
***************************************************************************************/
int16_t TFT_eSprite::height(void)
{
if (!_created ) return 0;
if (_bpp > 1) return _iheight;
if (_bpp > 4) return _dheight;
if (_rotation == 1 || _rotation == 3) return _dwidth;
@@ -1426,7 +1631,7 @@ int16_t TFT_eSprite::height(void)
/***************************************************************************************
** Function name: setRotation
** Description: Rotate coordinate frame for 1bpp sprite
*************************************************************************************x*/
***************************************************************************************/
// Does nothing for 8 and 16 bpp sprites. TODO allow rotation of these sprites
void TFT_eSprite::setRotation(uint8_t rotation)
{
@@ -1443,7 +1648,7 @@ void TFT_eSprite::setRotation(uint8_t rotation)
/***************************************************************************************
** Function name: getRotation
** Description: Get rotation for 1bpp sprite
*************************************************************************************x*/
***************************************************************************************/
uint8_t TFT_eSprite::getRotation(void)
{
@@ -1454,7 +1659,7 @@ uint8_t TFT_eSprite::getRotation(void)
/***************************************************************************************
** Function name: drawPixel
** Description: push a single pixel at an arbitrary position
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color)
{
// Range checking
@@ -1510,7 +1715,7 @@ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color)
/***************************************************************************************
** Function name: drawLine
** Description: draw a line between 2 arbitrary points
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
{
if (!_created ) return;
@@ -1566,7 +1771,7 @@ void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint3
/***************************************************************************************
** Function name: drawFastVLine
** Description: draw a vertical line
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
{
@@ -1621,7 +1826,7 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
/***************************************************************************************
** Function name: drawFastHLine
** Description: draw a horizontal line
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
{
@@ -1677,13 +1882,13 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
/***************************************************************************************
** Function name: fillRect
** Description: draw a filled rectangle
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
{
if (!_created ) return;
if ((x >= _iwidth) || (y >= _iheight)) return;
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
@@ -1782,7 +1987,7 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
/***************************************************************************************
** Function name: write
** Description: draw characters piped through serial stream
*************************************************************************************x*/
***************************************************************************************/
size_t TFT_eSprite::write(uint8_t utf8)
{
uint16_t uniCode = decodeUTF8(utf8);
@@ -1864,7 +2069,7 @@ size_t TFT_eSprite::write(uint8_t utf8)
height = height * textsize;
if (utf8 == '\n')
if (utf8 == '\n')
{
this->cursor_y += height;
this->cursor_x = 0;
@@ -1919,7 +2124,7 @@ size_t TFT_eSprite::write(uint8_t utf8)
/***************************************************************************************
** Function name: drawChar
** Description: draw a single character in the Adafruit GLCD or freefont
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size)
{
if (!_created ) return;
@@ -2061,7 +2266,7 @@ void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uin
/***************************************************************************************
** Function name: drawChar
** Description: draw a unicode onto the screen
*************************************************************************************x*/
***************************************************************************************/
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y)
{
@@ -2258,7 +2463,7 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo
/***************************************************************************************
** Function name: drawGlyph
** Description: Write a character to the sprite cursor position
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::drawGlyph(uint16_t code)
{
if (code < 0x21)
@@ -2289,15 +2494,15 @@ void TFT_eSprite::drawGlyph(uint16_t code)
uint16_t gNum = 0;
bool found = this->getUnicodeIndex(code, &gNum);
uint16_t fg = this->textcolor;
uint16_t bg = this->textbgcolor;
if (found)
{
bool newSprite = !_created;
if (newSprite)
{
createSprite(this->gWidth[gNum], this->gFont.yAdvance);
@@ -2393,7 +2598,7 @@ void TFT_eSprite::drawGlyph(uint16_t code)
/***************************************************************************************
** Function name: printToSprite
** Description: Write a string to the sprite cursor position
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::printToSprite(String string)
{
if(!this->fontLoaded) return;
@@ -2408,14 +2613,14 @@ void TFT_eSprite::printToSprite(String string)
/***************************************************************************************
** Function name: printToSprite
** Description: Write a string to the sprite cursor position
*************************************************************************************x*/
***************************************************************************************/
void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string)
{
if(!this->fontLoaded) return;
uint16_t n = 0;
bool newSprite = !_created;
if (newSprite)
{
int16_t sWidth = 1;
@@ -2459,7 +2664,7 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string)
/***************************************************************************************
** Function name: printToSprite
** Description: Print character in a Sprite, create sprite if needed
*************************************************************************************x*/
***************************************************************************************/
int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index)
{
bool newSprite = !_created;