diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index dcb1027..26f2296 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -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; diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index ab4f1c1..723b557 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -10,6 +10,7 @@ class TFT_eSprite : public TFT_eSPI { public: TFT_eSprite(TFT_eSPI *tft); + ~TFT_eSprite(void); // Create a sprite of width x height pixels, return a pointer to the RAM area // Sketch can cast returned value to (uint16_t*) for 16 bit depth if needed @@ -18,9 +19,10 @@ class TFT_eSprite : public TFT_eSPI { // - 1 nibble per pixel for 4 bit colour // - 1 byte per pixel for 8 bit colour // - 2 bytes per pixel for 16 bit color depth - ~TFT_eSprite(void); + void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); - void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); + // Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type + void* getPointer(void); // Returns true if sprite has been created bool created(void); @@ -131,6 +133,13 @@ class TFT_eSprite : public TFT_eSPI { void pushSprite(int32_t x, int32_t y); void pushSprite(int32_t x, int32_t y, uint16_t transparent); + // Push the sprite to another sprite, this fn calls pushImage() in the destination sprite class. + // >>>>>> Using a transparent color is not supported at the moment <<<<<< + bool pushSprite(TFT_eSprite *spr, int32_t x, int32_t y); + + // Push a windowed area of the sprite to the TFT at tx, ty + bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh); + int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font), drawChar(uint16_t uniCode, int32_t x, int32_t y); diff --git a/Processors/TFT_eSPI_ESP32.c b/Processors/TFT_eSPI_ESP32.c index 30d3d51..d83424c 100644 --- a/Processors/TFT_eSPI_ESP32.c +++ b/Processors/TFT_eSPI_ESP32.c @@ -489,7 +489,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ //////////////////////////////////////////////////////////////////////////////////////// -#if defined ESP32_DMA && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS +#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////// /*************************************************************************************** diff --git a/Processors/TFT_eSPI_ESP32.h b/Processors/TFT_eSPI_ESP32.h index 3909b5f..d373bf2 100644 --- a/Processors/TFT_eSPI_ESP32.h +++ b/Processors/TFT_eSPI_ESP32.h @@ -77,10 +77,16 @@ #define DC_D // No macro allocated so it generates no code #else #if defined (TFT_PARALLEL_8_BIT) - #define DC_C GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts = (1 << TFT_DC) + // TFT_DC, by design, must be in range 0-31 for single register parallel write + #if (TFT_DC >= 0) && (TFT_DC < 32) + #define DC_C GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1ts = (1 << TFT_DC) + #else + #define DC_C + #define DC_D + #endif #else - #if TFT_DC >= 32 + #if (TFT_DC >= 32) #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change #define DC_C GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)); \ GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) @@ -90,16 +96,20 @@ #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) #endif - #elif TFT_DC >= 0 - #ifdef RPI_DISPLAY_TYPE // RPi ILI9486 display needs a slower DC change - #define DC_C GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1ts = (1 << TFT_DC) - #elif defined (RPI_DISPLAY_TYPE) // Other RPi displays need a slower C->D change - #define DC_C GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1ts = (1 << TFT_DC) + #elif (TFT_DC >= 0) + #if defined (RPI_DISPLAY_TYPE) + #if defined (ILI9486_DRIVER) + // RPi ILI9486 display needs a slower DC change + #define DC_C GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1ts = (1 << TFT_DC) + #else + // Other RPi displays need a slower C->D change + #define DC_C GPIO.out_w1tc = (1 << TFT_DC) + #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ + GPIO.out_w1ts = (1 << TFT_DC) + #endif #else #define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC) #define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (1 << TFT_DC) @@ -131,8 +141,8 @@ #define CS_H #endif #else - #if TFT_CS >= 32 - #ifdef RPI_DISPLAY_TYPE // RPi ILI9486 display needs a slower CS change + #if (TFT_CS >= 32) + #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change #define CS_L GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)); \ GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) #define CS_H GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); \ @@ -141,12 +151,12 @@ #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) #endif - #elif TFT_CS >= 0 - #ifdef RPI_DISPLAY_TYPE // RPi ILI9486 display needs a slower CS change + #elif (TFT_CS >= 0) + #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change #define CS_L GPIO.out_w1ts = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) #define CS_H GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1ts = (1 << TFT_CS) #else - #define CS_L GPIO.out_w1tc = (1 << TFT_CS);GPIO.out_w1tc = (1 << TFT_CS) + #define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS) #endif #else @@ -159,9 +169,18 @@ //////////////////////////////////////////////////////////////////////////////////////// // Define the WR (TFT Write) pin drive code //////////////////////////////////////////////////////////////////////////////////////// -#ifdef TFT_WR - #define WR_L GPIO.out_w1tc = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts = (1 << TFT_WR) +#if defined (TFT_WR) + #if (TFT_WR >= 0) + // TFT_WR, by design, must be in range 0-31 for single register parallel write + #define WR_L GPIO.out_w1tc = (1 << TFT_WR) + #define WR_H GPIO.out_w1ts = (1 << TFT_WR) + #else + #define WR_L + #define WR_H + #endif +#else + #define WR_L + #define WR_H #endif //////////////////////////////////////////////////////////////////////////////////////// @@ -302,10 +321,18 @@ // Read pin #ifdef TFT_RD - #define RD_L GPIO.out_w1tc = (1 << TFT_RD) - //#define RD_L digitalWrite(TFT_WR, LOW) - #define RD_H GPIO.out_w1ts = (1 << TFT_RD) - //#define RD_H digitalWrite(TFT_WR, HIGH) + #if (TFT_RD >= 32) + #define RD_L GPIO.out1_w1tc.val = = (1 << (TFT_RD - 32)) + #define RD_H GPIO.out1_w1ts.val = = (1 << (TFT_RD - 32)) + #elif (TFT_RD >= 0) + #define RD_L GPIO.out_w1tc = (1 << TFT_RD) + //#define RD_L digitalWrite(TFT_WR, LOW) + #define RD_H GPIO.out_w1ts = (1 << TFT_RD) + //#define RD_H digitalWrite(TFT_WR, HIGH) + #else + #define RD_L + #define RD_H + #endif #endif //////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_ESP8266.c b/Processors/TFT_eSPI_ESP8266.c index 7a7287c..31e87e7 100644 --- a/Processors/TFT_eSPI_ESP8266.c +++ b/Processors/TFT_eSPI_ESP8266.c @@ -304,7 +304,7 @@ return; SPI1U1 = (511 << SPILMOSI); while(len>31) { -#if defined SPI_FREQUENCY && (SPI_FREQUENCY == 80000000) +#if (defined (SPI_FREQUENCY) && (SPI_FREQUENCY == 80000000)) if(SPI1CMD & SPIBUSY) // added to sync with flag change #endif while(SPI1CMD & SPIBUSY) {} diff --git a/Processors/TFT_eSPI_ESP8266.h b/Processors/TFT_eSPI_ESP8266.h index f3065f1..3b475cf 100644 --- a/Processors/TFT_eSPI_ESP8266.h +++ b/Processors/TFT_eSPI_ESP8266.h @@ -19,7 +19,7 @@ #define DMA_BUSY_CHECK // DMA not available, leave blank // Initialise processor specific SPI functions, used by init() -#if !defined (SUPPORT_TRANSACTIONS) && defined (ESP8266) +#if (!defined (SUPPORT_TRANSACTIONS) && defined (ESP8266)) #define INIT_TFT_DATA_BUS \ spi.setBitOrder(MSBFIRST); \ spi.setDataMode(TFT_SPI_MODE); \ diff --git a/Processors/TFT_eSPI_Generic.h b/Processors/TFT_eSPI_Generic.h index ecf69de..1b44d02 100644 --- a/Processors/TFT_eSPI_Generic.h +++ b/Processors/TFT_eSPI_Generic.h @@ -58,6 +58,13 @@ #define CS_H digitalWrite(TFT_CS, HIGH) #endif +//////////////////////////////////////////////////////////////////////////////////////// +// Make sure TFT_RD is defined if not used to avoid an error message +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_RD + #define TFT_RD -1 +#endif + //////////////////////////////////////////////////////////////////////////////////////// // Define the WR (TFT Write) pin drive code //////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_STM32.c b/Processors/TFT_eSPI_STM32.c index 162e732..1982b84 100644 --- a/Processors/TFT_eSPI_STM32.c +++ b/Processors/TFT_eSPI_STM32.c @@ -131,7 +131,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ ***************************************************************************************/ void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) { -#ifdef STM_PORTA_DATA_BUS +#if defined (STM_PORTA_DATA_BUS) #if defined (STM32F1xx) if (mode == OUTPUT) GPIOA->CRL = 0x33333333; else GPIOA->CRL = 0x88888888; @@ -139,7 +139,7 @@ void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) if (mode == OUTPUT) GPIOA->MODER = (GPIOA->MODER & 0xFFFF0000) | 0x00005555; else GPIOA->MODER &= 0xFFFF0000; #endif -#elif STM_PORTB_DATA_BUS +#elif defined (STM_PORTB_DATA_BUS) #if defined (STM32F1xx) if (mode == OUTPUT) GPIOB->CRL = 0x33333333; else GPIOB->CRL = 0x88888888; @@ -194,12 +194,12 @@ uint8_t TFT_eSPI::readByte(void) uint8_t b = 0; RD_L; -#ifdef STM_PORTA_DATA_BUS +#if defined (STM_PORTA_DATA_BUS) b = GPIOA->IDR; b = GPIOA->IDR; b = GPIOA->IDR; b = (GPIOA->IDR) & 0xFF; -#elif STM_PORTB_DATA_BUS +#elif defined (STM_PORTB_DATA_BUS) b = GPIOB->IDR; b = GPIOB->IDR; b = GPIOB->IDR; diff --git a/Processors/TFT_eSPI_STM32.h b/Processors/TFT_eSPI_STM32.h index 6fcab87..6b627d8 100644 --- a/Processors/TFT_eSPI_STM32.h +++ b/Processors/TFT_eSPI_STM32.h @@ -243,12 +243,21 @@ // Define the RD (TFT Read) pin drive code //////////////////////////////////////////////////////////////////////////////////////// #ifdef TFT_RD - // Convert Arduino pin reference Dx or STM pin reference PXn to port and mask - #define RD_PORT digitalPinToPort(TFT_RD) - #define RD_PIN_MASK digitalPinToBitMask(TFT_RD) - // Use bit set reset register - #define RD_L RD_PORT->BSRR = RD_PIN_MASK<<16 - #define RD_H RD_PORT->BSRR = RD_PIN_MASK + #if (TFT_RD >= 0) + // Convert Arduino pin reference Dx or STM pin reference PXn to port and mask + #define RD_PORT digitalPinToPort(TFT_RD) + #define RD_PIN_MASK digitalPinToBitMask(TFT_RD) + // Use bit set reset register + #define RD_L RD_PORT->BSRR = RD_PIN_MASK<<16 + #define RD_H RD_PORT->BSRR = RD_PIN_MASK + #else + #define RD_L + #define RD_H + #endif +#else + #define TFT_RD -1 + #define RD_L + #define RD_H #endif //////////////////////////////////////////////////////////////////////////////////////// diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 0252d30..e3fb4c1 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -335,8 +335,6 @@ void TFT_eSPI::init(uint8_t tc) } // end of: if just _booted // Toggle RST low to reset - begin_tft_write(); - #ifdef TFT_RST if (TFT_RST >= 0) { digitalWrite(TFT_RST, HIGH); @@ -350,8 +348,6 @@ void TFT_eSPI::init(uint8_t tc) writecommand(TFT_SWRST); // Software reset #endif - end_tft_write(); - delay(150); // Wait for reset to complete begin_tft_write(); @@ -946,6 +942,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *d uint16_t lineBuf[dw]; // Use buffer to minimise setWindow call count + // The little endian transp color must be byte swapped if the image is big endian if (!_swapBytes) transp = transp >> 8 | transp << 8; while (dh--) @@ -1062,6 +1059,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint1 uint16_t lineBuf[dw]; + // The little endian transp color must be byte swapped if the image is big endian if (!_swapBytes) transp = transp >> 8 | transp << 8; while (dh--) { @@ -1247,7 +1245,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da } pushPixels(lineBuf, dw); - dy++; } _swapBytes = swap; // Restore old value diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 4bfa552..f5371e0 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -16,7 +16,7 @@ #ifndef _TFT_eSPIH_ #define _TFT_eSPIH_ -#define TFT_ESPI_VERSION "2.2.15" +#define TFT_ESPI_VERSION "2.2.16" /*************************************************************************************** ** Section 1: Load required header files diff --git a/User_Setup_Select.h b/User_Setup_Select.h index abbaa7f..a9f45b3 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -59,7 +59,7 @@ //#include // Setup for Nucleo board //#include // Setup for Nucleo board and parallel display //#include // Setup for Nucleo board and parallel display -//#include // Setup for "Blue Pill" +//#include // Setup for "Blue Pill" //#include // Setup for Nucleo board @@ -69,8 +69,8 @@ //#include // Setup file configured for ESP32 and RPi TFT with touch //#include // Setup file configured for my ST7735S 80x160 -//#include // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240 -//#include // Setup file for ESP32 and TTGO T-Watch ST7789 SPI bus TFT 240x240 +//#include // Setup file for ESP32 and TTGO T-CameraPlus ST7789 SPI bus TFT 240x240 +//#include // Setup file for ESP32 and TTGO T-Watch ST7789 SPI bus TFT 240x240 //#include // Setup file for ESP8266 and ST7789 135 x 240 TFT diff --git a/keywords.txt b/keywords.txt index 2debf03..0cd2511 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,27 +1,34 @@ +# TFT_eSPI core library + TFT_eSPI KEYWORD1 +begin KEYWORD2 init KEYWORD2 drawPixel KEYWORD2 drawChar KEYWORD2 -setAddrWindow KEYWORD2 -setWindow KEYWORD2 -startWrite KEYWORD2 -writeColor KEYWORD2 -endWrite KEYWORD2 -pushColor KEYWORD2 -pushColors KEYWORD2 -fillScreen KEYWORD2 -writeBegin KEYWORD2 -writeEnd KEYWORD2 drawLine KEYWORD2 drawFastVLine KEYWORD2 drawFastHLine KEYWORD2 -drawRect KEYWORD2 fillRect KEYWORD2 +height KEYWORD2 +width KEYWORD2 +setRotation KEYWORD2 +getRotation KEYWORD2 +invertDisplay KEYWORD2 +setAddrWindow KEYWORD2 +setWindow KEYWORD2 +pushColor KEYWORD2 +pushColors KEYWORD2 +pushBlock KEYWORD2 +pushPixels KEYWORD2 +readPixel KEYWORD2 +tft_Read_8 KEYWORD2 +begin_SDA_Read KEYWORD2 +end_SDA_Read KEYWORD2 +fillScreen KEYWORD2 +drawRect KEYWORD2 drawRoundRect KEYWORD2 fillRoundRect KEYWORD2 -setRotation KEYWORD2 -invertDisplay KEYWORD2 drawCircle KEYWORD2 drawCircleHelper KEYWORD2 fillCircle KEYWORD2 @@ -30,18 +37,40 @@ drawEllipse KEYWORD2 fillEllipse KEYWORD2 drawTriangle KEYWORD2 fillTriangle KEYWORD2 +setSwapBytes KEYWORD2 +getSwapBytes KEYWORD2 drawBitmap KEYWORD2 drawXBitmap KEYWORD2 +setPivot KEYWORD2 +getPivotX KEYWORD2 +getPivotY KEYWORD2 +readRect KEYWORD2 +pushRect KEYWORD2 +pushImage KEYWORD2 +readRectRGB KEYWORD2 +drawNumber KEYWORD2 +drawFloat KEYWORD2 +drawString KEYWORD2 +drawCentreString KEYWORD2 +drawRightString KEYWORD2 setCursor KEYWORD2 getCursorX KEYWORD2 getCursorY KEYWORD2 setTextColor KEYWORD2 setTextSize KEYWORD2 -setTextFont KEYWORD2 -setFreeFont KEYWORD2 setTextWrap KEYWORD2 setTextDatum KEYWORD2 +getTextDatum KEYWORD2 setTextPadding KEYWORD2 +getTextPadding KEYWORD2 +setFreeFont KEYWORD2 +setTextFont KEYWORD2 +textWidth KEYWORD2 +fontHeight KEYWORD2 +decodeUTF8 KEYWORD2 +write KEYWORD2 +setCallback KEYWORD2 +fontsLoaded KEYWORD2 spiwrite KEYWORD2 writecommand KEYWORD2 writedata KEYWORD2 @@ -49,56 +78,51 @@ commandList KEYWORD2 readcommand8 KEYWORD2 readcommand16 KEYWORD2 readcommand32 KEYWORD2 -readPixel KEYWORD2 -readRect KEYWORD2 -pushRect KEYWORD2 -pushImage KEYWORD2 -setSwapBytes KEYWORD2 -getSwapBytes KEYWORD2 -readRectRGB KEYWORD2 -getRotation KEYWORD2 -getTextDatum KEYWORD2 -fontsLoaded KEYWORD2 color565 KEYWORD2 -color16to8 KEYWORD2 color8to16 KEYWORD2 -drawNumber KEYWORD2 -drawFloat KEYWORD2 -drawString KEYWORD2 -drawCentreString KEYWORD2 -drawRightString KEYWORD2 -height KEYWORD2 -width KEYWORD2 -textWidth KEYWORD2 -fontHeight KEYWORD2 -getSetup KEYWORD2 -setAttribute KEYWORD2 -getAttribute KEYWORD2 +color16to8 KEYWORD2 +color16to24 KEYWORD2 +color24to16 KEYWORD2 alphaBlend KEYWORD2 - -getSPIinstance KEYWORD2 -pushBlock KEYWORD2 -pushPixels KEYWORD2 - +alphaBlend24 KEYWORD2 initDMA KEYWORD2 deInitDMA KEYWORD2 pushImageDMA KEYWORD2 -pushBlockDMA KEYWORD2 pushPixelsDMA KEYWORD2 dmaBusy KEYWORD2 dmaWait KEYWORD2 +startWrite KEYWORD2 +writeColor KEYWORD2 +endWrite KEYWORD2 +setAttribute KEYWORD2 +getAttribute KEYWORD2 +getSetup KEYWORD2 +getSPIinstance KEYWORD2 + + +# Touch functions getTouchRaw KEYWORD2 -convertRawXY KEYWORD2 getTouchRawZ KEYWORD2 +convertRawXY KEYWORD2 getTouch KEYWORD2 calibrateTouch KEYWORD2 setTouch KEYWORD2 + +# Smooth font functions + +loadFont KEYWORD2 +unloadFont KEYWORD2 +getUnicodeIndex KEYWORD2 +showFont KEYWORD2 + + +# Button class + TFT_eSPI_Button KEYWORD1 initButton KEYWORD2 -textcolor KEYWORD2 initButtonUL KEYWORD2 setLabelDatum KEYWORD2 drawButton KEYWORD2 @@ -109,31 +133,30 @@ justPressed KEYWORD2 justReleased KEYWORD2 +# Sprite class + TFT_eSprite KEYWORD1 createSprite KEYWORD2 -createPalette KEYWORD2 +getPointer KEYWORD2 +created KEYWORD2 +deleteSprite KEYWORD2 +frameBuffer KEYWORD2 setColorDepth KEYWORD2 getColorDepth KEYWORD2 -deleteSprite KEYWORD2 +createPalette KEYWORD2 +setPaletteColor KEYWORD2 +getPaletteColor KEYWORD2 +setBitmapColor KEYWORD2 +fillSprite KEYWORD2 +setScrollRect KEYWORD2 +scroll KEYWORD2 pushRotated KEYWORD2 -pushRotatedHP KEYWORD2 -rotatedBounds KEYWORD2 setPivot KEYWORD2 getPivotX KEYWORD2 getPivotY KEYWORD2 -fillSprite KEYWORD2 -pushBitmap KEYWORD2 -pushSprite KEYWORD2 -setScrollRect KEYWORD2 -scroll KEYWORD2 -printToSprite KEYWORD2 -frameBuffer KEYWORD2 -setBitmapColor KEYWORD2 - -showFont KEYWORD2 -loadFont KEYWORD2 -unloadFont KEYWORD2 -getUnicodeIndex KEYWORD2 -decodeUTF8 KEYWORD2 +getRotatedBounds KEYWORD2 +readPixelValue KEYWORD2 drawGlyph KEYWORD2 +printToSprite KEYWORD2 +pushSprite KEYWORD2 diff --git a/library.json b/library.json index 3709c76..7733bb7 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TFT_eSPI", - "version": "2.2.15", + "version": "2.2.16", "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", "repository": diff --git a/library.properties b/library.properties index 41f6a4f..736d8d5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TFT_eSPI -version=2.2.15 +version=2.2.16 author=Bodmer maintainer=Bodmer sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32