Add support for 1 bit per pixel in Sprite class

This is stage one of support for ePaper displays from Waveshare.
Examples for 1 bit per pixel Sprites and 2 or 3 colour ePaper displays
to follow soon.
This commit is contained in:
Bodmer 2018-03-26 01:02:23 +01:00
parent 1db0c30b81
commit 9276b0162d
12 changed files with 883 additions and 290 deletions

View File

@ -74,14 +74,14 @@ void TFT_eSPI::loadFont(String fontName)
*/
unloadFont();
_gFontFilename = "/" + fontName + ".vlw";
fontFile = SPIFFS.open( _gFontFilename, "r");
if(!fontFile) return;
//unloadFont();
fontFile.seek(0, fs::SeekSet);
gFont.gCount = (uint16_t)readInt32(); // glyph count in file
@ -230,7 +230,8 @@ void TFT_eSPI::unloadFont( void )
free(gBitmap);
gBitmap = NULL;
}
fontFile.close();
if(fontFile) fontFile.close();
fontLoaded = false;
}

View File

@ -20,7 +20,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
_iwidth = 0; // Initialise width and height to 0 (it does not exist yet)
_iheight = 0;
_bpp16 = true;
_bpp = 16;
_iswapBytes = false; // Do not swap pushImage colour bytes by default
_created = false;
@ -33,7 +33,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
_xptr = 0; // pushColor coordinate
_yptr = 0;
_icursor_y = _icursor_x = 0; // Text cursor position
this->cursor_y = this->cursor_x = 0; // Text cursor position
}
@ -42,22 +42,18 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
** 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)
void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
{
if ( _created )
{
if ( _bpp16 ) return _img;
return _img8;
}
if ( _created ) return _img8_1;
if ( w < 1 || h < 1 ) return NULL;
_iwidth = w;
_iheight = h;
_iwidth = _dwidth = w;
_iheight = _dheight = h;
_icursor_x = 0;
_icursor_y = 0;
this->cursor_x = 0;
this->cursor_y = 0;
// Default scroll rectangle and gap fill colour
_sx = 0;
@ -69,28 +65,76 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h)
// 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.
if(_bpp16)
if (_bpp == 16)
{
_img = (uint16_t*) calloc(w * h + 1, sizeof(uint16_t));
_img8_1 = ( uint8_t*) calloc(w * h + 1, sizeof(uint16_t));
_img8_2 = _img8_1;
_img = (uint16_t*) _img8_1;
if (_img)
{
_created = true;
return _img;
}
}
else
else if (_bpp == 8)
{
_img8 = ( uint8_t*) calloc(w * h + 1, sizeof(uint8_t));
_img8_1 = ( uint8_t*) calloc(w * h + 1, sizeof(uint8_t));
if (_img8_1)
{
_img8 = _img8_1;
_img8_2 = _img8_1;
_created = true;
return _img8;
}
}
else // Must be 1 bpp
{
//_dwidth Display width+height in pixels always in rotation 0 orientation
//_dheight Not swapped for sprite rotations
// Note: for 1bpp _iwidth and _iheight are swapped during Sprite rotations
w = (w+7) & 0xFFF8; // width should be the multiple of 8 bits to be compatible with epdpaint
_iwidth = w; // _iwidth is rounded up to be multiple of 8, so might not be = _dwidth
_bitwidth = w;
if (frames > 2) frames = 2; // Currently restricted to 2 frame buffers
if (frames < 1) frames = 1;
_img8 = ( uint8_t*) calloc(frames * (w>>3) * h + frames, sizeof(uint8_t)); // extra pixel added
if (_img8)
{
_created = true;
return _img8;
_img8_1 = _img8;
_img8_2 = _img8 + ( (w>>3) * h + 1 );
return _img8_1;
}
}
return NULL;
}
/***************************************************************************************
** 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 (_bpp == 16) return _img;
if (_bpp == 8) return _img8;
if ( f == 2 ) _img8 = _img8_2;
else _img8 = _img8_1;
return _img8;
}
/***************************************************************************************
** Function name: setDepth
@ -100,15 +144,12 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h)
void* TFT_eSprite::setColorDepth(int8_t b)
{
// Can't change an existing sprite's colour depth so delete it
if (_created)
{
if (_bpp16) free(_img);
else free(_img8);
}
if (_created) free(_img8_1);
// Now define the new colour depth
if ( b > 8 ) _bpp16 = true; // Bytes per pixel
else _bpp16 = false;
if ( b > 8 ) _bpp = 16; // Bytes per pixel
else if ( b > 1 ) _bpp = 8;
else _bpp = 1;
// If it existed, re-create the sprite with the new colour depth
if (_created)
@ -120,6 +161,17 @@ void* TFT_eSprite::setColorDepth(int8_t b)
return NULL;
}
/***************************************************************************************
** Function name: setBitmapColor
** Description: Set the foreground foreground and background colour
***************************************************************************************/
void TFT_eSprite::setBitmapColor(uint16_t c, uint16_t b)
{
if (c == b) b = ~c;
_tft->bitmap_fg = c;
_tft->bitmap_bg = b;
}
/***************************************************************************************
** Function name: deleteSprite
@ -129,8 +181,7 @@ void TFT_eSprite::deleteSprite(void)
{
if (!_created ) return;
if (_bpp16) free(_img);
else free(_img8);
free(_img8_1);
_created = false;
}
@ -142,11 +193,12 @@ void TFT_eSprite::deleteSprite(void)
*************************************************************************************x*/
void TFT_eSprite::pushSprite(int32_t x, int32_t y)
{
if (!_created ) return;
if (!_created) return;
if (_bpp == 16) _tft->pushImage(x, y, _iwidth, _iheight, _img );
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8));
if (_bpp16) _tft->pushImage(x, y, _iwidth, _iheight, _img );
//if (_bpp16) TFT_eSPI::pushImage(x, y, _iwidth, _iheight, _img );
else _tft->pushImage(x, y, _iwidth, _iheight, _img8);
}
@ -156,14 +208,15 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y)
*************************************************************************************x*/
void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
{
if (!_created ) return;
if (!_created) return;
if (_bpp16) _tft->pushImage(x, y, _iwidth, _iheight, _img, transp );
else
if (_bpp == 16) _tft->pushImage(x, y, _iwidth, _iheight, _img, transp );
else if (_bpp == 8)
{
transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3);
_tft->pushImage(x, y, _iwidth, _iheight, _img8, (uint8_t)transp);
_tft->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true);
}
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false);
}
@ -173,24 +226,48 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
*************************************************************************************x*/
uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
{
if (!_created ) return 0;
if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0;
if (_bpp16)
if (_bpp == 16)
{
uint16_t color = _img[x + y * _iwidth];
return (color >> 8) | (color << 8);
}
uint16_t color = _img8[x + y * _iwidth];
if (color != 0)
if (_bpp == 8)
{
uint16_t color = _img8[x + y * _iwidth];
if (color != 0)
{
uint8_t blue[] = {0, 11, 21, 31};
color = (color & 0xE0)<<8 | (color & 0xC0)<<5
| (color & 0x1C)<<6 | (color & 0x1C)<<3
| blue[color & 0x03];
color = (color & 0xE0)<<8 | (color & 0xC0)<<5
| (color & 0x1C)<<6 | (color & 0x1C)<<3
| blue[color & 0x03];
}
return color;
}
return color;
if (_rotation == 1)
{
uint16_t tx = x;
x = _dwidth - y - 1;
y = tx;
}
else if (_rotation == 2)
{
x = _dwidth - x - 1;
y = _dheight - y - 1;
}
else if (_rotation == 3)
{
uint16_t tx = x;
x = y;
y = _dheight - tx - 1;
}
uint16_t color = (_img8[(x + y * _bitwidth)>>3] << (x & 0x7)) & 0x80;
return color >> 7;
}
@ -198,11 +275,12 @@ 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*/
// TODO Need to add more area boundary checks
void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_t *data)
{
if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0) || !_created) return;
if ((x >= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0) || !_created) return;
if (_bpp16)
if (_bpp == 16)
{
for (uint32_t yp = y; yp < y + h; yp++)
{
@ -214,7 +292,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1
}
}
}
else
else if (_bpp == 8)
{
for (uint32_t yp = y; yp < y + h; yp++)
{
@ -226,6 +304,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1
}
}
}
// TODO Currently does nothing for 1 bpp
}
@ -233,11 +312,12 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1
** Function name: pushImage
** Description: push 565 colour FLASH (PROGMEM) image into a defined area
*************************************************************************************x*/
// TODO Need to add more area boundary checks
void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uint16_t *data)
{
if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0) || !_created) return;
if ((x >= _iwidth) || (y >= _iheight) || (w == 0) || (h == 0) || !_created) return;
if (_bpp16)
if (_bpp == 16)
{
for (uint32_t yp = y; yp < y + h; yp++)
{
@ -249,7 +329,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const
}
}
}
else
else if (_bpp == 8)
{
for (uint32_t yp = y; yp < y + h; yp++)
{
@ -261,6 +341,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const
}
}
}
// TODO Currently does nothing for 1 bpp
}
@ -334,11 +415,13 @@ void TFT_eSprite::pushColor(uint32_t color)
if (!_created ) return;
// Write the colour to RAM in set window
if (_bpp16)
if (_bpp == 16)
_img [_xptr + _yptr * _iwidth] = (uint16_t) (color >> 8) | (color << 8);
else
else if (_bpp == 8)
_img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
else drawPixel(_xptr, _yptr, color);
// Increment x
_xptr++;
@ -363,12 +446,14 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
if (!_created ) return;
uint16_t pixelColor;
if (_bpp16)
if (_bpp == 16)
pixelColor = (uint16_t) (color >> 8) | (color << 8);
else
else if (_bpp == 8)
pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
// else Nothing to do for 1bpp
while(len--) writeColor(pixelColor);
}
@ -382,10 +467,12 @@ void TFT_eSprite::writeColor(uint16_t color)
if (!_created ) return;
// Write 16 bit RGB 565 encoded colour to RAM
if (_bpp16) _img [_xptr + _yptr * _iwidth] = color;
if (_bpp == 16) _img [_xptr + _yptr * _iwidth] = color;
// Write 8 bit RGB 332 encoded colour to RAM
else _img8[_xptr + _yptr * _iwidth] = (uint8_t) color;
else if (_bpp == 8) _img8[_xptr + _yptr * _iwidth] = (uint8_t) color;
else drawPixel(_xptr, _yptr, color);
// Increment x
_xptr++;
@ -466,7 +553,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
uint32_t typ = tx + ty * _iwidth;
// Now move the pixels in RAM
if (_bpp16)
if (_bpp == 16)
{
while (h--)
{ // move pixel lines (to, from, byte count)
@ -475,7 +562,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
fyp += iw;
}
}
else
else if (_bpp == 8)
{
while (h--)
{ // move pixel lines (to, from, byte count)
@ -484,6 +571,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
fyp += iw;
}
}
else return; // TODO add scroll for 1 bpp
// Fill the gap left by the scrolling
if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor);
@ -502,13 +590,18 @@ void TFT_eSprite::fillSprite(uint32_t color)
if (!_created ) return;
// Use memset if possible as it is super fast
if(( (uint8_t)color == (uint8_t)(color>>8) ) && _bpp16)
if(( (uint8_t)color == (uint8_t)(color>>8) ) && _bpp == 16)
memset(_img, (uint8_t)color, _iwidth * _iheight * 2);
else if (!_bpp16)
else if (_bpp == 8)
{
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
memset(_img8, (uint8_t)color, _iwidth * _iheight);
}
else if (_bpp == 1)
{
if(color) memset(_img8, 0xFF, (_iwidth>>3) * _iheight + 1);
else memset(_img8, 0x00, (_iwidth>>3) * _iheight + 1);
}
else fillRect(0, 0, _iwidth, _iheight, color);
}
@ -518,11 +611,12 @@ void TFT_eSprite::fillSprite(uint32_t color)
** Function name: setCursor
** Description: Set the sprite text cursor x,y position
*************************************************************************************x*/
void TFT_eSprite::setCursor(int16_t x, int16_t y)
{
_icursor_x = x;
_icursor_y = y;
}
// Not needed - using TFT_eSPI class function and this->cursor_x/y
//void TFT_eSprite::setCursor(int16_t x, int16_t y)
//{
// this->cursor_x = x;
// this->cursor_y = y;
//}
/***************************************************************************************
@ -533,7 +627,12 @@ void TFT_eSprite::setCursor(int16_t x, int16_t y)
int16_t TFT_eSprite::width(void)
{
if (!_created ) return 0;
return _iwidth;
if (_bpp > 1) return _iwidth;
if (_rotation == 1 || _rotation == 3) return _dheight;
return _dwidth;
}
@ -544,7 +643,38 @@ int16_t TFT_eSprite::width(void)
int16_t TFT_eSprite::height(void)
{
if (!_created ) return 0;
return _iheight;
if (_bpp > 1) return _iheight;
if (_rotation == 1 || _rotation == 3) return _dwidth;
return _dheight;
}
/***************************************************************************************
** 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)
{
_rotation = rotation;
if (rotation == 0 && _iwidth > _iheight) swap_coord(_iwidth, _iheight);
if (rotation == 1 && _iwidth < _iheight) swap_coord(_iwidth, _iheight);
if (rotation == 2 && _iwidth > _iheight) swap_coord(_iwidth, _iheight);
if (rotation == 3 && _iwidth < _iheight) swap_coord(_iwidth, _iheight);
}
/***************************************************************************************
** Function name: getRotation
** Description: Get rotation for 1bpp sprite
*************************************************************************************x*/
uint8_t TFT_eSprite::getRotation(void)
{
return _rotation;
}
@ -558,15 +688,38 @@ void TFT_eSprite::drawPixel(uint32_t x, uint32_t y, uint32_t color)
// this make bounds checking a bit faster
if ((x >= _iwidth) || (y >= _iheight) || !_created) return;
if (_bpp16)
if (_bpp == 16)
{
color = (color >> 8) | (color << 8);
_img[x+y*_iwidth] = (uint16_t) color;
}
else
else if (_bpp == 8)
{
_img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
}
else // 1 bpp
{
if (_rotation == 1)
{
uint16_t tx = x;
x = _dwidth - y - 1;
y = tx;
}
else if (_rotation == 2)
{
x = _dwidth - x - 1;
y = _dheight - y - 1;
}
else if (_rotation == 3)
{
uint16_t tx = x;
x = y;
y = _dheight - tx - 1;
}
if (color) _img8[(x + y * _bitwidth)>>3] |= (0x80 >> (x & 0x7));
else _img8[(x + y * _bitwidth)>>3] &= ~(0x80 >> (x & 0x7));
}
}
@ -641,17 +794,25 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
if (h < 1) return;
if (_bpp16)
if (_bpp == 16)
{
color = (color >> 8) | (color << 8);
int32_t yp = x + _iwidth * y;
while (h--) {_img[yp] = (uint16_t) color; yp += _iwidth;}
}
else
else if (_bpp == 8)
{
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
while (h--) _img8[x + _iwidth * y++] = (uint8_t) color;
}
else
{
while (h--)
{
drawPixel(x, y, color);
y++;
}
}
}
@ -670,16 +831,24 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
if (w < 1) return;
if (_bpp16)
if (_bpp == 16)
{
color = (color >> 8) | (color << 8);
while (w--) _img[_iwidth * y + x++] = (uint16_t) color;
}
else
else if (_bpp == 8)
{
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
memset(_img8+_iwidth * y + x, (uint8_t)color, w);
}
else
{
while (w--)
{
drawPixel(x, y, color);
x++;
}
}
}
@ -700,7 +869,7 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
int32_t yp = _iwidth * y + x;
if (_bpp16)
if (_bpp == 16)
{
color = (color >> 8) | (color << 8);
uint32_t iw = w;
@ -713,15 +882,25 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
memcpy( _img+yp, _img+ys, w<<1);
}
}
else
else if (_bpp == 8)
{
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
while (h--)
{
memset(_img8 + yp, (uint8_t)color, w);
memset(_img8 + yp, (uint8_t)color, w);
yp += _iwidth;
}
}
else
{
while (h--)
{
int32_t ww = w;
int32_t xx = x;
while (ww--) drawPixel(xx++, y, color);
y++;
}
}
}
@ -734,21 +913,23 @@ size_t TFT_eSprite::write(uint8_t utf8)
if (utf8 == '\r') return 1;
#ifdef SMOOTH_FONT
if(fontLoaded)
if(this->fontLoaded)
{
uint16_t unicode = decodeUTF8(utf8);
if (unicode < 32 && utf8 != '\n') return 0;
fontFile = SPIFFS.open( _gFontFilename, "r" );
//fontFile = SPIFFS.open( _gFontFilename, "r" );
//fontFile = SPIFFS.open( this->_gFontFilename, "r" );
if(!fontFile)
{
fontLoaded = false;
return 0;
}
//if(!fontFile)
//{
// fontLoaded = false;
// return 0;
//}
//Serial.print("Decoded Unicode = 0x");Serial.println(unicode,HEX);
drawGlyph(unicode);
fontFile.close();
//fontFile.close();
return 0;
}
#endif
@ -818,18 +999,18 @@ size_t TFT_eSprite::write(uint8_t utf8)
if (utf8 == '\n')
{
_icursor_y += height;
_icursor_x = 0;
this->cursor_y += height;
this->cursor_x = 0;
}
else
{
if (textwrapX && (_icursor_x + width * textsize > _iwidth))
if (textwrapX && (this->cursor_x + width * textsize > _iwidth))
{
_icursor_y += height;
_icursor_x = 0;
this->cursor_y += height;
this->cursor_x = 0;
}
if (textwrapY && (_icursor_y >= _iheight)) _icursor_y = 0;
_icursor_x += drawChar(uniCode, _icursor_x, _icursor_y, textfont);
if (textwrapY && (this->cursor_y >= _iheight)) this->cursor_y = 0;
this->cursor_x += drawChar(uniCode, this->cursor_x, this->cursor_y, textfont);
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@ -839,8 +1020,8 @@ size_t TFT_eSprite::write(uint8_t utf8)
{
if(utf8 == '\n') {
_icursor_x = 0;
_icursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
this->cursor_x = 0;
this->cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else {
if (uniCode > (uint8_t)pgm_read_byte(&gfxFont->last )) return 0;
if (uniCode < (uint8_t)pgm_read_byte(&gfxFont->first)) return 0;
@ -851,15 +1032,15 @@ size_t TFT_eSprite::write(uint8_t utf8)
h = pgm_read_byte(&glyph->height);
if((w > 0) && (h > 0)) { // Is there an associated bitmap?
int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset);
if(textwrapX && ((_icursor_x + textsize * (xo + w)) > _iwidth)) {
if(textwrapX && ((this->cursor_x + textsize * (xo + w)) > _iwidth)) {
// Drawing character would go off right edge; wrap to new line
_icursor_x = 0;
_icursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
this->cursor_x = 0;
this->cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
if (textwrapY && (_icursor_y >= _iheight)) _icursor_y = 0;
drawChar(_icursor_x, _icursor_y, uniCode, textcolor, textbgcolor, textsize);
if (textwrapY && (this->cursor_y >= _iheight)) this->cursor_y = 0;
drawChar(this->cursor_x, this->cursor_y, uniCode, textcolor, textbgcolor, textsize);
}
_icursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
this->cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
}
}
#endif // LOAD_GFXFF
@ -1151,9 +1332,9 @@ int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font)
w *= height; // Now w is total number of pixels in the character
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
int16_t color;
if (_bpp16) color = (textcolor >> 8) | (textcolor << 8);
else color = ((textcolor & 0xE000)>>8 | (textcolor & 0x0700)>>6 | (textcolor & 0x0018)>>3);
int16_t color = textcolor;
if (_bpp == 16) color = (textcolor >> 8) | (textcolor << 8);
else if (_bpp == 8) color = ((textcolor & 0xE000)>>8 | (textcolor & 0x0700)>>6 | (textcolor & 0x0018)>>3);
int px = 0, py = pY; // To hold character block start and end column and row values
int pc = 0; // Pixel count
uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel
@ -1212,17 +1393,17 @@ void TFT_eSprite::drawGlyph(uint16_t code)
if (code < 0x21)
{
if (code == 0x20) {
if (_created) _icursor_x += _tft->gFont.spaceWidth;
else _tft->cursor_x += _tft->gFont.spaceWidth;
if (_created) this->cursor_x += this->gFont.spaceWidth;
else this->cursor_x += this->gFont.spaceWidth;
return;
}
if (code == '\n') {
if (_created)
{
_icursor_x = 0;
_icursor_y += _tft->gFont.yAdvance;
if (_icursor_y >= _height) _icursor_y = 0;
this->cursor_x = 0;
this->cursor_y += this->gFont.yAdvance;
if (this->cursor_y >= _height) this->cursor_y = 0;
return;
}
else
@ -1236,10 +1417,10 @@ void TFT_eSprite::drawGlyph(uint16_t code)
}
uint16_t gNum = 0;
bool found = _tft->getUnicodeIndex(code, &gNum);
bool found = this->getUnicodeIndex(code, &gNum);
uint16_t fg = _tft->textcolor;
uint16_t bg = _tft->textbgcolor;
uint16_t fg = this->textcolor;
uint16_t bg = this->textbgcolor;
if (found)
{
@ -1248,59 +1429,59 @@ void TFT_eSprite::drawGlyph(uint16_t code)
if (newSprite)
{
createSprite(_tft->gWidth[gNum], _tft->gFont.yAdvance);
createSprite(this->gWidth[gNum], this->gFont.yAdvance);
if(bg) fillSprite(bg);
_icursor_x = -_tft->gdX[gNum];
_icursor_y = 0;
this->cursor_x = -this->gdX[gNum];
this->cursor_y = 0;
}
fontFile.seek(_tft->gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift!
this->fontFile.seek(this->gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift!
uint8_t pbuffer[_tft->gWidth[gNum]];
uint8_t pbuffer[this->gWidth[gNum]];
uint16_t xs = 0;
uint16_t dl = 0;
for (int y = 0; y < _tft->gHeight[gNum]; y++)
for (int y = 0; y < this->gHeight[gNum]; y++)
{
fontFile.read(pbuffer, _tft->gWidth[gNum]);
for (int x = 0; x < _tft->gWidth[gNum]; x++)
this->fontFile.read(pbuffer, this->gWidth[gNum]);
for (int x = 0; x < this->gWidth[gNum]; x++)
{
uint8_t pixel = pbuffer[x];
if (pixel)
{
if (pixel != 0xFF)
{
if (dl) { drawFastHLine( xs, y + _icursor_y + _tft->gFont.maxAscent - _tft->gdY[gNum], dl, fg); dl = 0; }
drawPixel(x + _icursor_x + _tft->gdX[gNum], y + _icursor_y + _tft->gFont.maxAscent - _tft->gdY[gNum], alphaBlend(pixel, fg, bg));
if (dl) { drawFastHLine( xs, y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], dl, fg); dl = 0; }
if (pixel>127) drawPixel(x + this->cursor_x + this->gdX[gNum], y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], alphaBlend(pixel, fg, bg));
}
else
{
if (dl==0) xs = x + _icursor_x + _tft->gdX[gNum];
if (dl==0) xs = x + this->cursor_x + this->gdX[gNum];
dl++;
}
}
else
{
if (dl) { drawFastHLine( xs, y + _icursor_y + _tft->gFont.maxAscent - _tft->gdY[gNum], dl, fg); dl = 0; }
if (dl) { drawFastHLine( xs, y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], dl, fg); dl = 0; }
}
}
if (dl) { drawFastHLine( xs, y + _icursor_y + _tft->gFont.maxAscent - _tft->gdY[gNum], dl, fg); dl = 0; }
if (dl) { drawFastHLine( xs, y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], dl, fg); dl = 0; }
}
if (newSprite)
{
pushSprite(_tft->cursor_x + _tft->gdX[gNum], _tft->cursor_y, bg);
pushSprite(this->cursor_x + this->gdX[gNum], this->cursor_y, bg);
deleteSprite();
_tft->cursor_x += _tft->gxAdvance[gNum];
this->cursor_x += this->gxAdvance[gNum];
}
else _icursor_x += _tft->gxAdvance[gNum];
else this->cursor_x += this->gxAdvance[gNum];
}
else
{
// Not a Unicode in font so draw a rectangle and move on cursor
drawRect(_icursor_x, _icursor_y + _tft->gFont.maxAscent - _tft->gFont.ascent, _tft->gFont.spaceWidth, _tft->gFont.ascent, fg);
_icursor_x += _tft->gFont.spaceWidth + 1;
drawRect(this->cursor_x, this->cursor_y + this->gFont.maxAscent - this->gFont.ascent, this->gFont.spaceWidth, this->gFont.ascent, fg);
this->cursor_x += this->gFont.spaceWidth + 1;
}
}
@ -1311,7 +1492,7 @@ void TFT_eSprite::drawGlyph(uint16_t code)
*************************************************************************************x*/
void TFT_eSprite::printToSprite(String string)
{
if(!_tft->fontLoaded) return;
if(!this->fontLoaded) return;
int16_t len = string.length();
char cbuffer[len + 1]; // Add 1 for the null
string.toCharArray(cbuffer, len + 1); // Add 1 for the null, otherwise characters get dropped
@ -1325,13 +1506,13 @@ void TFT_eSprite::printToSprite(String string)
*************************************************************************************x*/
void TFT_eSprite::printToSprite(char *cbuffer, int len) //String string)
{
if(!_tft->fontLoaded) return;
if(!this->fontLoaded) return;
fontFile = SPIFFS.open( _tft->_gFontFilename, "r" );
//fontFile = SPIFFS.open( this->_gFontFilename, "r" );
if(!fontFile)
if(!this->fontFile)
{
_tft->fontLoaded = false;
this->fontLoaded = false;
return;
}
@ -1346,19 +1527,19 @@ void TFT_eSprite::printToSprite(char *cbuffer, int len) //String string)
while (n < len)
{
uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n);
if (_tft->getUnicodeIndex(unicode, &index))
if (this->getUnicodeIndex(unicode, &index))
{
if (n == 0) sWidth -= _tft->gdX[index];
if (n == len-1) sWidth += ( _tft->gWidth[index] + _tft->gdX[index]);
else sWidth += _tft->gxAdvance[index];
if (n == 0) sWidth -= this->gdX[index];
if (n == len-1) sWidth += ( this->gWidth[index] + this->gdX[index]);
else sWidth += this->gxAdvance[index];
}
else sWidth += _tft->gFont.spaceWidth + 1;
else sWidth += this->gFont.spaceWidth + 1;
}
createSprite(sWidth, _tft->gFont.yAdvance);
createSprite(sWidth, this->gFont.yAdvance);
uint16_t transparent = TFT_BLACK;
if (_tft->textbgcolor != TFT_BLACK) fillSprite(_tft->textbgcolor);
if (this->textbgcolor != TFT_BLACK) fillSprite(this->textbgcolor);
}
n = 0;
@ -1372,12 +1553,12 @@ void TFT_eSprite::printToSprite(char *cbuffer, int len) //String string)
}
if (newSprite)
{
{ // The sprite had to be created so place at TFT cursor
pushSprite(_tft->cursor_x, _tft->cursor_y);
deleteSprite();
}
fontFile.close();
//fontFile.close();
}
@ -1388,22 +1569,22 @@ void TFT_eSprite::printToSprite(char *cbuffer, int len) //String string)
int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index)
{
bool newSprite = !_created;
int16_t sWidth = _tft->gWidth[index];
int16_t sWidth = this->gWidth[index];
if (newSprite)
{
createSprite(sWidth, _tft->gFont.yAdvance);
createSprite(sWidth, this->gFont.yAdvance);
uint16_t transparent = TFT_BLACK;
if (_tft->textbgcolor != TFT_BLACK) fillSprite(_tft->textbgcolor);
if (this->textbgcolor != TFT_BLACK) fillSprite(this->textbgcolor);
drawGlyph(_tft->gUnicode[index]);
drawGlyph(this->gUnicode[index]);
pushSprite(x + _tft->gdX[index], y, _tft->textbgcolor);
pushSprite(x + this->gdX[index], y, this->textbgcolor);
deleteSprite();
}
else drawGlyph(_tft->gUnicode[index]);
else drawGlyph(this->gUnicode[index]);
return _tft->gxAdvance[index];
return this->gxAdvance[index];
}
#endif

View File

@ -14,15 +14,20 @@ class TFT_eSprite : public TFT_eSPI {
// 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
// RAM required is 1 byte per pixel for 8 bit colour depth, 2 bytes for 16 bit
void* createSprite(int16_t width, int16_t height);
void* createSprite(int16_t width, int16_t height, uint8_t frames = 1);
// Delete the sprite to free up the RAM
void deleteSprite(void);
// Select the frame buffer for graphics
void* frameBuffer(int8_t f);
// Set the colour depth to 8 or 16 bits. Can be used to change depth an existing
// sprite, but clears it to black, returns a new pointer if sprite is re-created.
void* setColorDepth(int8_t b);
void setBitmapColor(uint16_t c, uint16_t b);
void drawPixel(uint32_t x, uint32_t y, uint32_t color);
void drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size),
@ -49,10 +54,13 @@ class TFT_eSprite : public TFT_eSPI {
drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color),
drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color),
fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color),
fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
// Set the sprite text cursor position for print class (does not change the TFT screen cursor)
setCursor(int16_t x, int16_t y);
//setCursor(int16_t x, int16_t y);
void setRotation(uint8_t rotation);
uint8_t getRotation(void);
// Read the colour of a pixel at x,y and return value in 565 format
uint16_t readPixel(int32_t x0, int32_t y0);
@ -92,13 +100,17 @@ class TFT_eSprite : public TFT_eSPI {
protected:
uint16_t *_img; // pointer to 16 bit sprite
uint8_t *_img8; // pointer to 8 bit sprite
bool _created, _bpp16; // created and bits per pixel depth flags
uint8_t _bpp;
uint16_t *_img; // pointer to 16 bit sprite
uint8_t *_img8; // pointer to 8 bit sprite
uint8_t *_img8_1; // pointer to frame 1
uint8_t *_img8_2; // pointer to frame 2
bool _created; // created and bits per pixel depth flags
bool _gFont = false;
int32_t _icursor_x, _icursor_y;
// int32_t _icursor_x, _icursor_y;
uint8_t _rotation = 0;
int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; // for setWindow
int32_t _sx, _sy; // x,y for scroll zone
uint32_t _sw, _sh; // w,h for scroll zone
@ -106,6 +118,8 @@ class TFT_eSprite : public TFT_eSPI {
boolean _iswapBytes; // Swap the byte order for Sprite pushImage()
int32_t _iwidth, _iheight; // Sprite image width and height
int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations)
int32_t _dwidth, _dheight; // Real display width and height (for <8bpp Sprites)
int32_t _bitwidth; // Sprite image bit width for drawPixel (for <8bpp Sprites, not swapped)
};

27
TFT_Drivers/EPD_Defines.h Normal file
View File

@ -0,0 +1,27 @@
// Null set for ePaper
#define TFT_WIDTH 1000
#define TFT_HEIGHT 1000
#define TFT_INIT_DELAY 0
#define TFT_NOP 0x00
#define TFT_SWRST 0x00
#define TFT_CASET 0x00
#define TFT_PASET 0x00
#define TFT_RAMWR 0x00
#define TFT_RAMRD 0x00
#define TFT_IDXRD 0x00
#define TFT_MADCTL 0x00
#define TFT_MAD_MY 0x00
#define TFT_MAD_MX 0x00
#define TFT_MAD_MV 0x00
#define TFT_MAD_ML 0x00
#define TFT_MAD_BGR 0x00
#define TFT_MAD_MH 0x00
#define TFT_MAD_RGB 0x00
#define TFT_INVOFF 0x00
#define TFT_INVON 0x00

View File

@ -153,11 +153,11 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
_init_width = _width = w; // Set by specific xxxxx_Defines.h file or by users sketch
_init_height = _height = h; // Set by specific xxxxx_Defines.h file or by users sketch
rotation = 0;
cursor_y = cursor_x = 0;
cursor_y = cursor_x = 0;
textfont = 1;
textsize = 1;
textcolor = 0xFFFF; // White
textbgcolor = 0x0000; // Black
textcolor = bitmap_fg = 0xFFFF; // White
textbgcolor = bitmap_bg = 0x0000; // Black
padX = 0; // No padding
textwrapX = true; // Wrap text at end of line when using print stream
textwrapY = false; // Wrap text at bottom of screen when using print stream
@ -998,7 +998,7 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uin
** Function name: pushImage
** Description: plot 8 bit image or sprite using a line buffer
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data)
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data, bool bpp8)
{
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
@ -1020,45 +1020,79 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *
setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
data += dx + dy * w;
// Line buffer makes plotting faster
uint16_t lineBuf[dw];
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
_lastColor = -1; // Set to illegal value
// Used to store last shifted colour
uint8_t msbColor = 0;
uint8_t lsbColor = 0;
while (dh--)
if (bpp8)
{
uint32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
while(len--)
_lastColor = -1; // Set to illegal value
// Used to store last shifted colour
uint8_t msbColor = 0;
uint8_t lsbColor = 0;
data += dx + dy * w;
while (dh--)
{
uint32_t color = *ptr++;
uint32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
// Shifts are slow so check if colour has changed first
if (color != _lastColor) {
// =====Green===== ===============Red==============
msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
// =====Green===== =======Blue======
lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
_lastColor = color;
while(len--)
{
uint32_t color = *ptr++;
// Shifts are slow so check if colour has changed first
if (color != _lastColor) {
// =====Green===== ===============Red==============
msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
// =====Green===== =======Blue======
lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
_lastColor = color;
}
*linePtr++ = msbColor;
*linePtr++ = lsbColor;
}
*linePtr++ = msbColor;
*linePtr++ = lsbColor;
pushColors(lineBuf, dw, false);
data += w;
}
}
else
{
while (dh--)
{
w = (w+7) & 0xFFF8;
pushColors(lineBuf, dw, false);
int32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
uint8_t bits = 8;
while(len>0)
{
if (len < 8) bits = len;
uint32_t xp = dx;
for (uint16_t i = 0; i < bits; i++)
{
uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80;
if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;}
else {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;}
//if (col) drawPixel((dw-len)+xp,h-dh,bitmap_fg);
//else drawPixel((dw-len)+xp,h-dh,bitmap_bg);
xp++;
}
*ptr++;
len -= 8;
}
data += w;
pushColors(lineBuf, dw, false);
dy++;
}
}
CS_H;
@ -1070,9 +1104,9 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *
/***************************************************************************************
** Function name: pushImage
** Description: plot 8 bit image or sprite with 1 colour being transparent
** Description: plot 8 or 1 bit image or sprite with a transparent colour
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data, uint8_t transp)
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data, uint8_t transp, bool bpp8)
{
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
@ -1092,70 +1126,121 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *
spi_begin();
inTransaction = true;
data += dx + dy * w;
int32_t xe = x + dw - 1, ye = y + dh - 1;
// Line buffer makes plotting faster
uint16_t lineBuf[dw];
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
_lastColor = -1; // Set to illegal value
// Used to store last shifted colour
uint8_t msbColor = 0;
uint8_t lsbColor = 0;
int32_t spx = x, spy = y;
while (dh--)
if (bpp8)
{
int32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
data += dx + dy * w;
int32_t px = x;
boolean move = true;
uint16_t np = 0;
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
while (len--)
_lastColor = -1; // Set to illegal value
// Used to store last shifted colour
uint8_t msbColor = 0;
uint8_t lsbColor = 0;
int32_t spx = x, spy = y;
while (dh--)
{
if (transp != *ptr)
{
if (move) { move = false; setAddrWindow(px, y, xe, ye);}
uint8_t color = *ptr;
int32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
// Shifts are slow so check if colour has changed first
if (color != _lastColor) {
// =====Green===== ===============Red==============
msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
// =====Green===== =======Blue======
lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
_lastColor = color;
}
*linePtr++ = msbColor;
*linePtr++ = lsbColor;
np++;
}
else
int32_t px = x;
boolean move = true;
uint16_t np = 0;
while (len--)
{
move = true;
if (np)
if (transp != *ptr)
{
pushColors(lineBuf, np, false);
linePtr = (uint8_t*)lineBuf;
np = 0;
if (move) { move = false; setAddrWindow(px, y, xe, ye);}
uint8_t color = *ptr;
// Shifts are slow so check if colour has changed first
if (color != _lastColor) {
// =====Green===== ===============Red==============
msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
// =====Green===== =======Blue======
lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
_lastColor = color;
}
*linePtr++ = msbColor;
*linePtr++ = lsbColor;
np++;
}
else
{
move = true;
if (np)
{
pushColors(lineBuf, np, false);
linePtr = (uint8_t*)lineBuf;
np = 0;
}
}
px++;
ptr++;
}
px++;
ptr++;
if (np) pushColors(lineBuf, np, false);
y++;
data += w;
}
}
else
{
w = (w+7) & 0xFFF8;
while (dh--)
{
int32_t px = x;
boolean move = true;
uint16_t np = 0;
int32_t len = dw;
uint8_t* ptr = data;
uint8_t bits = 8;
while(len>0)
{
if (len < 8) bits = len;
uint32_t xp = dx;
uint32_t yp = (dy * w)>>3;
for (uint16_t i = 0; i < bits; i++)
{
//uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80;
if ((ptr[(xp>>3) + yp] << (xp & 0x7)) & 0x80)
{
if (move)
{
move = false;
setAddrWindow(px, y, xe, ye);
}
np++;
}
else
{
if (np)
{
pushColor(bitmap_fg, np);
np = 0;
move = true;
}
}
px++;
xp++;
}
*ptr++;
len -= 8;
}
if (np) pushColor(bitmap_fg, np);
y++;
dy++;
}
if (np) pushColors(lineBuf, np, false);
y++;
data += w;
}
CS_H;
@ -1769,6 +1854,18 @@ void TFT_eSPI::setTextColor(uint16_t c, uint16_t b)
}
/***************************************************************************************
** Function name: setBitmapColor
** Description: Set the foreground foreground and background colour
***************************************************************************************/
void TFT_eSPI::setBitmapColor(uint16_t c, uint16_t b)
{
if (c == b) b = ~c;
bitmap_fg = c;
bitmap_bg = b;
}
/***************************************************************************************
** Function name: setTextWrap
** Description: Define if text should wrap at end of line
@ -2978,7 +3075,7 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
#if defined (ESP32)
#ifdef ESP32_PARALLEL
if (swap) while ( len-- ) {tft_Write_16(*data); data++;}
else while ( len-- ) {transwap16(*data); data++;}
else while ( len-- ) {tft_Write_16S(*data); data++;}
#else
if (swap) SPI.writePixels(data,len<<1);
else SPI.writeBytes((uint8_t*)data,len<<1);
@ -3013,6 +3110,8 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
}
len -= 16;
// ESP8266 wait time here at 40MHz SPI is ~5.45us
while(SPI1CMD & SPIBUSY) {}
SPI1W0 = color[0];
SPI1W1 = color[1];
@ -4446,6 +4545,136 @@ void writeBlock(uint16_t color, uint32_t repeat)
#endif
/***************************************************************************************
** Function name: getSetup
** Description: Get the setup details for diagnostic and sketch access
***************************************************************************************/
void TFT_eSPI::getSetup(setup_t &tft_settings)
{
#if defined (ESP8266)
tft_settings.esp = 8266;
#elif defined (ESP32)
tft_settings.esp = 32;
#else
tft_settings.esp = -1;
#endif
#if defined (SUPPORT_TRANSACTIONS)
tft_settings.trans = true;
#else
tft_settings.trans = false;
#endif
#if defined (ESP32_PARALLEL)
tft_settings.serial = false;
tft_settings.tft_spi_freq = 0;
#else
tft_settings.serial = true;
tft_settings.tft_spi_freq = SPI_FREQUENCY/100000;
#endif
tft_settings.tft_driver = TFT_DRIVER;
tft_settings.tft_width = _init_width;
tft_settings.tft_height = _init_height;
#ifdef CGRAM_OFFSET
tft_settings.r0_x_offset = colstart;
tft_settings.r0_y_offset = rowstart;
tft_settings.r1_x_offset = 0;
tft_settings.r1_y_offset = 0;
tft_settings.r2_x_offset = 0;
tft_settings.r2_y_offset = 0;
tft_settings.r3_x_offset = 0;
tft_settings.r3_y_offset = 0;
#else
tft_settings.r0_x_offset = 0;
tft_settings.r0_y_offset = 0;
tft_settings.r1_x_offset = 0;
tft_settings.r1_y_offset = 0;
tft_settings.r2_x_offset = 0;
tft_settings.r2_y_offset = 0;
tft_settings.r3_x_offset = 0;
tft_settings.r3_y_offset = 0;
#endif
#if defined (TFT_MOSI)
tft_settings.pin_tft_mosi = TFT_MOSI;
#else
tft_settings.pin_tft_mosi = -1;
#endif
#if defined (TFT_MISO)
tft_settings.pin_tft_miso = TFT_MISO;
#else
tft_settings.pin_tft_miso = -1;
#endif
#if defined (TFT_SCLK)
tft_settings.pin_tft_clk = TFT_SCLK;
#else
tft_settings.pin_tft_clk = -1;
#endif
#if defined (TFT_CS)
tft_settings.pin_tft_cs = TFT_CS;
#else
tft_settings.pin_tft_cs = -1;
#endif
#if defined (TFT_DC)
tft_settings.pin_tft_dc = TFT_DC;
#else
tft_settings.pin_tft_dc = -1;
#endif
#if defined (TFT_RD)
tft_settings.pin_tft_rd = TFT_RD;
#else
tft_settings.pin_tft_rd = -1;
#endif
#if defined (TFT_WR)
tft_settings.pin_tft_wr = TFT_WR;
#else
tft_settings.pin_tft_wr = -1;
#endif
#if defined (TFT_RST)
tft_settings.pin_tft_rst = TFT_RST;
#else
tft_settings.pin_tft_rst = -1;
#endif
#if defined (ESP32_PARALLEL)
tft_settings.pin_tft_d0 = TFT_D0;
tft_settings.pin_tft_d1 = TFT_D1;
tft_settings.pin_tft_d2 = TFT_D2;
tft_settings.pin_tft_d3 = TFT_D3;
tft_settings.pin_tft_d4 = TFT_D4;
tft_settings.pin_tft_d5 = TFT_D5;
tft_settings.pin_tft_d6 = TFT_D6;
tft_settings.pin_tft_d7 = TFT_D7;
#else
tft_settings.pin_tft_d0 = -1;
tft_settings.pin_tft_d1 = -1;
tft_settings.pin_tft_d2 = -1;
tft_settings.pin_tft_d3 = -1;
tft_settings.pin_tft_d4 = -1;
tft_settings.pin_tft_d5 = -1;
tft_settings.pin_tft_d6 = -1;
tft_settings.pin_tft_d7 = -1;
#endif
#if defined (TOUCH_CS)
tft_settings.pin_tch_cs = TOUCH_CS;
tft_settings.tch_spi_freq = SPI_TOUCH_FREQUENCY/100000;
#else
tft_settings.pin_tch_cs = -1;
tft_settings.tch_spi_freq = 0;
#endif
}
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TOUCH_CS
#include "Extensions/Touch.cpp"

View File

@ -155,42 +155,42 @@
#endif
#ifdef ESP32_PARALLEL
#if defined (ESP32) && defined (ESP32_PARALLEL)
// Mask for the 8 data bits to set pin directions
#define dir_mask ((1 << TFT_D0) | (1 << TFT_D1) | (1 << TFT_D2) | (1 << TFT_D3) | (1 << TFT_D4) | (1 << TFT_D5) | (1 << TFT_D6) | (1 << TFT_D7))
// Data bits and the write line are cleared to 0 in one step
#define clr_mask (dir_mask | (1 << TFT_WR))
// A lookup table is used to set the different bit patterns, this uses 1kByte of RAM
#define set_mask(C) xset_mask[C] // 63fps Sprite rendering test 33% faster, graphicstest only 1.8% faster than shifting in real time
// Real-time shifting alternative to above to save 1KByte RAM, 47 fps Sprite rendering test
//#define set_mask(C) ((C&0x80)>>7)<<TFT_D7 | ((C&0x40)>>6)<<TFT_D6 | ((C&0x20)>>5)<<TFT_D5 | ((C&0x10)>>4)<<TFT_D4 | \
((C&0x08)>>3)<<TFT_D3 | ((C&0x04)>>2)<<TFT_D2 | ((C&0x02)>>1)<<TFT_D1 | ((C&0x01)>>0)<<TFT_D0
// Write 8 bits to TFT
#define tft_Write_8(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)C); WR_H
// Write 16 bits to TFT
#define tft_Write_16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)(C >> 8)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)(C >> 0)); WR_H
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t)(C >> 0)); WR_H
// 16 bit transfer with swapped bytes
#define transwap16(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 0)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 8)); WR_H
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 0)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 8)); WR_H
// Write 32 bits to TFT
#define tft_Write_32(C) GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 24)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 16)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 8)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 0)); WR_H
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 16)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 8)); WR_H; \
GPIO.out_w1tc = clr_mask; GPIO.out_w1ts = set_mask((uint8_t) (C >> 0)); WR_H
#ifdef TFT_RD
#if defined (ESP32)
#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 GPOC=rdpinmask
//#define RD_H GPOS=rdpinmask
#endif
#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)
#endif
#elif defined (SEND_16_BITS)
@ -330,9 +330,55 @@ template <typename T> static inline void
swap_coord(T& a, T& b) { T t = a; a = b; b = t; }
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
// This structure allows sketches to retrieve the user setup parameters at runtime
// by calling getSetup(), zero impact on code size unless used, mainly for diagnostics
typedef struct
{
int16_t esp;
uint8_t trans;
uint8_t serial;
uint16_t tft_driver; // Hexadecimal code
uint16_t tft_width; // Rotation 0 width and height
uint16_t tft_height;
uint8_t r0_x_offset; // Offsets, not all used yet
uint8_t r0_y_offset;
uint8_t r1_x_offset;
uint8_t r1_y_offset;
uint8_t r2_x_offset;
uint8_t r2_y_offset;
uint8_t r3_x_offset;
uint8_t r3_y_offset;
int8_t pin_tft_mosi;
int8_t pin_tft_miso;
int8_t pin_tft_clk;
int8_t pin_tft_cs;
int8_t pin_tft_dc;
int8_t pin_tft_rd;
int8_t pin_tft_wr;
int8_t pin_tft_rst;
int8_t pin_tft_d0;
int8_t pin_tft_d1;
int8_t pin_tft_d2;
int8_t pin_tft_d3;
int8_t pin_tft_d4;
int8_t pin_tft_d5;
int8_t pin_tft_d6;
int8_t pin_tft_d7;
int8_t pin_tch_cs;
int16_t tft_spi_freq;
int16_t tch_spi_freq;
} setup_t;
// This is a structure to conveniently hold information on the default fonts
// Stores pointer to font character image address table, width table and height
@ -444,6 +490,7 @@ class TFT_eSPI : public Print {
fillTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color),
drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color),
setBitmapColor(uint16_t c, uint16_t b), // For 1bpp sprites
setCursor(int16_t x, int16_t y),
setCursor(int16_t x, int16_t y, uint8_t font),
@ -489,9 +536,9 @@ class TFT_eSPI : public Print {
void pushImage(int32_t x0, int32_t y0, uint32_t w, uint32_t h, const uint16_t *data, uint16_t transparent);
void pushImage(int32_t x0, int32_t y0, uint32_t w, uint32_t h, const uint16_t *data);
// These are used by pushSprite for 8 bit colours
void pushImage(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint8_t *data);
void pushImage(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint8_t *data, uint8_t transparent);
// These are used by pushSprite for 1 and 8 bit colours
void pushImage(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint8_t *data, bool bpp8 = true);
void pushImage(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true);
// Swap the byte order for pushImage() - corrects endianness
void setSwapBytes(bool swap);
@ -543,8 +590,11 @@ class TFT_eSPI : public Print {
size_t write(uint8_t);
void getSetup(setup_t& tft_settings); // Sketch provides the instance to populate
int32_t cursor_x, cursor_y;
uint32_t textcolor, textbgcolor;
uint32_t bitmap_fg, bitmap_bg;
private:

View File

@ -40,7 +40,7 @@
//#include <User_Setups/Setup99.h>
//#include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting
// ePaper #include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting
#endif // USER_SETUP_LOADED
@ -58,39 +58,51 @@
// Load the right driver definition - do not tinker here !
#if defined (ILI9341_DRIVER)
#include <TFT_Drivers/ILI9341_Defines.h>
#define TFT_DRIVER 0x9341
#elif defined (ST7735_DRIVER)
#include <TFT_Drivers/ST7735_Defines.h>
#define TFT_DRIVER 0x7735
#elif defined (ILI9163_DRIVER)
#include <TFT_Drivers/ILI9163_Defines.h>
#define TFT_DRIVER 0x9163
#elif defined (S6D02A1_DRIVER)
#include <TFT_Drivers/S6D02A1_Defines.h>
#define TFT_DRIVER 0x6D02
#elif defined (RPI_ILI9486_DRIVER)
#include <TFT_Drivers/RPI_ILI9486_Defines.h>
#define TFT_DRIVER 0x9481
#elif defined (ILI9481_DRIVER)
#include <TFT_Drivers/ILI9481_Defines.h>
#define TFT_DRIVER 0x9481
#elif defined (ILI9488_DRIVER)
#include <TFT_Drivers/ILI9488_Defines.h>
#define TFT_DRIVER 0x9488
#elif defined (HX8357D_DRIVER)
#include "TFT_Drivers/HX8357D_Defines.h"
#define TFT_DRIVER 0x8357
#elif defined (EPD_DRIVER)
#include "TFT_Drivers/EPD_Defines.h"
#define TFT_DRIVER 0xE9D
#endif
// These are the pins for all ESP8266 boards
#define PIN_D0 16
#define PIN_D1 5
#define PIN_D2 4
#define PIN_D3 0
#define PIN_D4 2
#define PIN_D5 14
#define PIN_D6 12
#define PIN_D7 13
#define PIN_D8 15
#define PIN_D9 3
#define PIN_D10 1
// Name GPIO Function
#define PIN_D0 16 // WAKE
#define PIN_D1 5 // User purpose
#define PIN_D2 4 // User purpose
#define PIN_D3 0 // FLASH mode at boot time
#define PIN_D4 2 // TXD1 (Note: low on boot means go to FLASH mode)
#define PIN_D5 14 // HSCLK
#define PIN_D6 12 // HMISO
#define PIN_D7 13 // HMOSI RXD2
#define PIN_D8 15 // HCS TXD0
#define PIN_D9 3 // RXD0
#define PIN_D10 1 // TXD0
#define PIN_MOSI 8
#define PIN_MISO 7
#define PIN_SCLK 6
#define PIN_HWCS 0
#define PIN_MOSI 8 // SD1
#define PIN_MISO 7 // SD0
#define PIN_SCLK 6 // CLK
#define PIN_HWCS 0 // CMD
#define PIN_D11 9
#define PIN_D12 10
#define PIN_D11 9 // SD2
#define PIN_D12 10 // SD4

View File

@ -121,6 +121,10 @@
//#define TFT_RST 4 // Reset pin (could connect to RST pin)
//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
//#define TOUCH_CS 22 // Chip select pin (T_CS) of touch screen
//#define TFT_WR 21 // Write strobe for modified Raspberry Pi TFT only
// For the M5Stack module use these #define lines
//#define TFT_MISO 19
//#define TFT_MOSI 23
@ -130,9 +134,6 @@
//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
//#define TFT_BL 32 // LED back-light
//#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen
//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
// ##################################################################################
//
@ -199,6 +200,7 @@
// #define SPI_FREQUENCY 20000000
#define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3
// #define SPI_FREQUENCY 40000000 // Maximum to use SPIFFS
// #define SPI_FREQUENCY 53400000
// #define SPI_FREQUENCY 80000000
// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:

View File

@ -0,0 +1,76 @@
// USER DEFINED SETTINGS
// Set driver type, fonts to be loaded, pins used and SPI control method etc
//
// See the User_Setup_Select.h file if you wish to be able to define multiple
// setups and then easily select which setup file is used by the compiler.
//
// If this file is edited correctly then all the library example sketches should
// run without the need to make any more changes for a particular hardware setup!
// ##################################################################################
//
// Section 0. Call up the right driver file and any options for it
//
// ##################################################################################
// Only define one driver, the other ones must be commented out
#define EPD_DRIVER
// ##################################################################################
//
// Section 1. Define the pins that are used to interface with the display here
//
// ##################################################################################
// ePaper pins are not defined here - dummy set
//#define TFT_CS
//#define TFT_DC
//#define TFT_RST
// ##################################################################################
//
// Section 2. Not used
//
// ##################################################################################
// ##################################################################################
//
// Section 3. Define the fonts that are to be used here
//
// ##################################################################################
// Comment out the #defines below with // to stop that font being loaded
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
// normally necessary. If all fonts are loaded the extra FLASH space required is
// about 17Kbytes. To save FLASH space only enable the fonts you need!
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
//#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
//#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT
// ##################################################################################
//
// Section 4. Not used
//
// ##################################################################################
// ##################################################################################
//
// Section 5. Not used
//
// ##################################################################################

View File

@ -75,7 +75,6 @@ calibrateTouch KEYWORD2
setTouch KEYWORD2
validTouch KEYWORD2
TFT_eSPI_Button KEYWORD1
initButton KEYWORD2
@ -99,8 +98,14 @@ pushBitmap KEYWORD2
pushSprite KEYWORD2
setScrollRect KEYWORD2
scroll KEYWORD2
printToSprite KEYWORD2
frameBuffer KEYWORD2
setBitmapColor KEYWORD2
alphaBlend KEYWORD2
showFont KEYWORD2
loadFont KEYWORD2
unloadFont KEYWORD2
getUnicodeIndex KEYWORD2
decodeUTF8 KEYWORD2
drawGlyph KEYWORD2

View File

@ -14,10 +14,6 @@
"name": "Bodmer",
"email": "bodmer@anola.net",
"maintainer": true
},
{
"name": "Adafruit",
"url": "https://www.adafruit.com/"
}
],
"frameworks": "arduino",