diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index b5559e1..14ed796 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -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; } diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index ab5d368..90fadae 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -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 diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 85945ff..1ea7645 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -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) }; diff --git a/TFT_Drivers/EPD_Defines.h b/TFT_Drivers/EPD_Defines.h new file mode 100644 index 0000000..6a6838c --- /dev/null +++ b/TFT_Drivers/EPD_Defines.h @@ -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 diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index ccb9642..6348f65 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -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" diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 343a39a..49571eb 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -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)<>6)<>5)<>4)<>3)<>2)<>1)<>0)<> 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 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: diff --git a/Tools/Create_Smooth_Font/Create_font/FontFiles/Final-Frontier28.vlw b/Tools/Create_Smooth_Font/Create_font/FontFiles/Final-Frontier28.vlw new file mode 100644 index 0000000..2872fd5 Binary files /dev/null and b/Tools/Create_Smooth_Font/Create_font/FontFiles/Final-Frontier28.vlw differ diff --git a/User_Setup_Select.h b/User_Setup_Select.h index c4e720b..b8e7628 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -40,7 +40,7 @@ //#include -//#include // Setup file template for copying/editting +// ePaper #include // 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 + #define TFT_DRIVER 0x9341 #elif defined (ST7735_DRIVER) #include + #define TFT_DRIVER 0x7735 #elif defined (ILI9163_DRIVER) #include + #define TFT_DRIVER 0x9163 #elif defined (S6D02A1_DRIVER) #include + #define TFT_DRIVER 0x6D02 #elif defined (RPI_ILI9486_DRIVER) #include + #define TFT_DRIVER 0x9481 #elif defined (ILI9481_DRIVER) #include + #define TFT_DRIVER 0x9481 #elif defined (ILI9488_DRIVER) #include + #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 diff --git a/User_Setups/SetupX_Template.h b/User_Setups/SetupX_Template.h index 6214165..8b22cbc 100644 --- a/User_Setups/SetupX_Template.h +++ b/User_Setups/SetupX_Template.h @@ -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: diff --git a/User_Setups/ePaper_Template.h b/User_Setups/ePaper_Template.h new file mode 100644 index 0000000..e704621 --- /dev/null +++ b/User_Setups/ePaper_Template.h @@ -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 +// +// ################################################################################## + diff --git a/keywords.txt b/keywords.txt index 5d4f945..33da608 100644 --- a/keywords.txt +++ b/keywords.txt @@ -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 diff --git a/library.json b/library.json index 27cc221..74448e6 100644 --- a/library.json +++ b/library.json @@ -14,10 +14,6 @@ "name": "Bodmer", "email": "bodmer@anola.net", "maintainer": true - }, - { - "name": "Adafruit", - "url": "https://www.adafruit.com/" } ], "frameworks": "arduino",