diff --git a/Keywords.txt b/Keywords.txt index 0dc74be..97f9b28 100644 --- a/Keywords.txt +++ b/Keywords.txt @@ -91,6 +91,7 @@ justReleased KEYWORD2 TFT_eSprite KEYWORD1 createSprite KEYWORD2 +setColorDepth KEYWORD2 deleteSprite KEYWORD2 fillSprite KEYWORD2 setWindow KEYWORD2 diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index edf7860..d84b966 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -552,11 +552,6 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) if (dw < 0 || dh < 0) return; - //Serial.print("dx="); Serial.println(dx); - //Serial.print("dy="); Serial.println(dy); - //Serial.print("dw="); Serial.println(dw); - //Serial.print("dh="); Serial.println(dh); - spi_begin(); setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR @@ -574,11 +569,71 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) */ uint32_t len = dw * 2; uint8_t* ptr = (uint8_t*)data; + // Push pixels into window rectangle, data is a 16 bit pointer thus increment is halved while ( len>32) { SPI.writePattern(ptr, 32, 1); len -= 32; ptr += 32; } if (len) SPI.writePattern((uint8_t*)ptr, len, 1); data += w; + } + + CS_H; + + spi_end(); +} + + void TFT_eSPI::pushSprite(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data) +{ + + if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return; + + int32_t dx = 0; + int32_t dy = 0; + int32_t dw = w; + int32_t dh = h; + + if (x < 0) { dw += x; dx = -x; x = 0; } + if (y < 0) { dh += y; dy = -y; y = 0; } + + if ((x + w) >= _width ) dw = _width - x; + if ((y + h) >= _height) dh = _height - y; + + if (dw < 0 || dh < 0) return; + + spi_begin(); + + setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR + + data += dx + dy * w; + +#ifdef ESP8266 + uint32_t spimask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); + SPI1U1 = (SPI1U1 & spimask) | (15 << SPILMOSI) | (15 << SPILMISO); +#endif + + while (dh--) + { + uint32_t len = dw; + uint8_t* ptr = data; + + while(len--) + { + uint16_t color = *ptr++; + color = (color & 0xE0)<<8 | (color & 0xC0)<<5 + | (color & 0x1C)<<6 | (color & 0x1C)<<3 + | (color & 0x03)<<3 | (color & 0x03)<<1 | (color & 0x03)>>1; + +#ifdef ESP32 + SPI.write16(color); +#else + color = (color<<8) | (color>>8); + SPI1W0 = color; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +#endif + } + data += w; + } CS_H; @@ -4108,8 +4163,8 @@ void TFT_eSPI_Button::press(boolean p) { currstate = p; } -boolean TFT_eSPI_Button::isPressed() { return currstate; } -boolean TFT_eSPI_Button::justPressed() { return (currstate && !laststate); } +boolean TFT_eSPI_Button::isPressed() { return currstate; } +boolean TFT_eSPI_Button::justPressed() { return (currstate && !laststate); } boolean TFT_eSPI_Button::justReleased() { return (!currstate && laststate); } @@ -4132,8 +4187,11 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) _iwidth = 0; // Initialise width and height to 0 (it does not exist yet) _iheight = 0; + _bpp16 = true; - _xs = 0; // window bounds for pushColor + _created = false; + + _xs = 0; // window bounds for pushColor _ys = 0; _xe = 0; _ye = 0; @@ -4149,13 +4207,30 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) ** Function name: createSprite ** Description: Create a sprite (bitmap) of defined width and height *************************************************************************************x*/ -uint16_t* TFT_eSprite::createSprite(int16_t w, int16_t h) +void TFT_eSprite::createSprite(int16_t w, int16_t h) { - if ( w < 1 || h < 1) return 0; + if ( w < 1 || h < 1) return; + _iwidth = w; _iheight = h; - _img = (uint16_t*) malloc(w * h * sizeof(uint16_t)); - return _img; + + if(_bpp16) _img = (uint16_t*) malloc(w * h * 2); + else _img8 = ( uint8_t*) malloc(w * h); + + _created = true; +} + + +/*************************************************************************************** +** Function name: setDepth +** Description: Set bits per pixel for colour (8 or 16) +*************************************************************************************x*/ + +void TFT_eSprite::setColorDepth(int8_t b) +{ + if (_created) deleteSprite(); + if ( b > 8 ) _bpp16 = true; // Bytes per pixel + else _bpp16 = false; } @@ -4165,7 +4240,10 @@ uint16_t* TFT_eSprite::createSprite(int16_t w, int16_t h) *************************************************************************************x*/ void TFT_eSprite::deleteSprite(void) { - free(_img); + if (!_created ) return; + if (_bpp16) free(_img); + else free(_img8); + _created = false; } @@ -4175,18 +4253,30 @@ void TFT_eSprite::deleteSprite(void) *************************************************************************************x*/ void TFT_eSprite::pushSprite(int32_t x, int32_t y) { - _tft->pushSprite(x, y, _iwidth, _iheight, _img); + if (_bpp16) _tft->pushSprite(x, y, _iwidth, _iheight, _img ); + else _tft->pushSprite(x, y, _iwidth, _iheight, _img8); } /*************************************************************************************** ** Function name: readPixel -** Description: Read 565 colour of a pixel at deined coordinates +** Description: Read 565 colour of a pixel at defined coordinates *************************************************************************************x*/ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) { - uint16_t color = _img[x + y * _iwidth]; - return (color >> 8) | (color << 8); + if (_bpp16) + { + uint16_t color = _img[x + y * _iwidth]; + return (color >> 8) | (color << 8); + } + + uint16_t color = _img8[x + y * _iwidth]; + if (color != 0) + color = (color & 0xE0)<<8 | (color & 0xC0)<<5 + | (color & 0x1C)<<6 | (color & 0x1C)<<3 + | (color & 0x03)<<3 | (color & 0x03)<<1 | (color & 0x03)>>1; + + return color; } @@ -4198,11 +4288,25 @@ void TFT_eSprite::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint { if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0)) return; - for (uint32_t yp = y; yp < y + h; yp++) + if (_bpp16) { - for (uint32_t xp = x; xp < x + w; xp++) + for (uint32_t yp = y; yp < y + h; yp++) { - _img[xp + yp * _iwidth] = *data++; + for (uint32_t xp = x; xp < x + w; xp++) + { + _img[xp + yp * _iwidth] = *data++; + } + } + } + else + { + for (uint32_t yp = y; yp < y + h; yp++) + { + for (uint32_t xp = x; xp < x + w; xp++) + { + uint16_t color = *data++; + _img8[xp + yp * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + } } } } @@ -4214,28 +4318,29 @@ void TFT_eSprite::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint ***************************************************************************************/ void TFT_eSprite::pushBitmap(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data) { - if ((x > _iwidth) || (y > _iheight) || (w == 0) || (h == 0)) return; - - for (uint32_t yp = y; yp < y + h; yp++) - { - for (uint32_t xp = x; xp < x + w; xp++) - { - _img[xp + yp * _iwidth] = *data++; - } - } + pushRect(x, y, w, h, data); } /*************************************************************************************** -** Function name: spriteWindow -** Description: Set the bounds of a window for pushColor +** Function name: setWindow +** Description: Set the bounds of a window for pushColor and writeColor *************************************************************************************x*/ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { - // Bounds will be checked by drawPixel if (x0 > x1) swap_coord(x0, x1); if (y0 > y1) swap_coord(y0, y1); + if (x0 < 0) x0 = 0; + if (x0 >= _iwidth) x0 = _iwidth; + if (x1 < 0) x1 = 0; + if (x1 >= _iwidth) x1 = _iwidth; + + if (y0 < 0) y0 = 0; + if (y0 >= _iheight) y0 = _iheight; + if (y1 < 0) y1 = 0; + if (y1 >= _iheight) y1 = _iheight; + _xs = x0; _ys = y0; _xe = x1; @@ -4248,20 +4353,69 @@ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) /*************************************************************************************** ** Function name: pushColor -** Description: Send a new pixel to the sprite window +** Description: Send a new pixel to the set window *************************************************************************************x*/ void TFT_eSprite::pushColor(uint32_t color) { - drawPixel(_xptr++, _yptr, color); - if (_xptr > _xe) { _xptr = _xs; _yptr++; } - if (_yptr > _ye) { _yptr = _ys; } + + // Write the colour to RAM in set window + if (_bpp16) + _img [_xptr + _yptr * _iwidth] = (uint16_t) (color >> 8) | (color << 8); + else + _img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + + // Increment x + _xptr++; + + // Wrap on x and y to start, increment y if needed + if (_xptr > _xe) + { + _xptr = _xs; + _yptr++; + if (_yptr > _ye) _yptr = _ys; + } + } + +/*************************************************************************************** +** Function name: pushColor +** Description: Send a "len" new pixels to the set window +*************************************************************************************x*/ void TFT_eSprite::pushColor(uint32_t color, uint16_t len) { - drawPixel(_xptr++, _yptr, color); - if (_xptr > _xe) { _xptr = _xs; _yptr++; } - if (_yptr > _ye) { _yptr = _ys; } + uint16_t pixelColor; + if (_bpp16) + pixelColor = (uint16_t) (color >> 8) | (color << 8); + else + pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + + while(len--) writeColor(pixelColor); +} + + +/*************************************************************************************** +** Function name: writeColor +** Description: Write a pixel with pre-formatted colour to the set window +*************************************************************************************x*/ +void TFT_eSprite::writeColor(uint16_t color) +{ + // Write 16 bit RGB 565 encoded colour to RAM + if (_bpp16) _img [_xptr + _yptr * _iwidth] = color; + + // Write 8 bit RGB 332 encoded colour to RAM + else _img8[_xptr + _yptr * _iwidth] = (uint8_t) color; + + // Increment x + _xptr++; + + // Wrap on x and y to start, increment y if needed + if (_xptr > _xe) + { + _xptr = _xs; + _yptr++; + if (_yptr > _ye) _yptr = _ys; + } } @@ -4272,7 +4426,10 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len) void TFT_eSprite::fillSprite(uint32_t color) { // Use memset if possible as it is super fast - if((uint8_t)color == (color>>8)) memset(_img, (uint8_t)color, _iwidth * _iheight * 2); + if(( (uint8_t)color == (uint8_t)(color>>8) ) && _bpp16) + memset(_img, (uint8_t)color, _iwidth * _iheight * 2); + else if (!_bpp16) memset(_img8, (uint8_t)color, _iwidth * _iheight); + else fillRect(0, 0, _iwidth, _iheight, color); } @@ -4289,7 +4446,7 @@ void TFT_eSprite::setCursor(int16_t x, int16_t y) /*************************************************************************************** -** Function name: width or spriteWidth +** Function name: width ** Description: Return the width of sprite *************************************************************************************x*/ // Return the size of the display @@ -4298,16 +4455,9 @@ int16_t TFT_eSprite::width(void) return _iwidth; } -/* -// Return the size of the display -int16_t TFT_eSprite::spriteWidth(void) -{ - return _iwidth; -} -*/ /*************************************************************************************** -** Function name: height or spriteHeight +** Function name: height ** Description: Return the height of sprite *************************************************************************************x*/ int16_t TFT_eSprite::height(void) @@ -4315,12 +4465,6 @@ int16_t TFT_eSprite::height(void) return _iheight; } -/* -int16_t TFT_eSprite::spriteHeight(void) -{ - return _iheight; -} -*/ /*************************************************************************************** ** Function name: drawChar @@ -4471,8 +4615,16 @@ void TFT_eSprite::drawPixel(uint32_t x, uint32_t y, uint32_t color) // x and y are unsigned so that -ve coordinates turn into large positive ones // this make bounds checking a bit faster if ((x >= _iwidth) || (y >= _iheight)) return; - color = (color >> 8) | (color << 8); - _img[x+y*_iwidth] = (uint16_t) color; + + if (_bpp16) + { + color = (color >> 8) | (color << 8); + _img[x+y*_iwidth] = (uint16_t) color; + } + else + { + _img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + } } @@ -4541,8 +4693,17 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) if ((y + h) > _iheight) h = _iheight - y; if (h < 1) return; - color = (color >> 8) | (color << 8); - while (h--) _img[x + _iwidth * y++] = (uint16_t) color; + + if (_bpp16) + { + color = (color >> 8) | (color << 8); + while (h--) _img[x + _iwidth * y++] = (uint16_t) color; + } + else + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + while (h--) _img8[x + _iwidth * y++] = (uint8_t) color; + } } @@ -4557,8 +4718,18 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) if ((x + w) > _iwidth) w = _iwidth - x; if (w < 1) return; - color = (color >> 8) | (color << 8); - while (w--) _img[_iwidth * y + x++] = (uint16_t) color; + + if (_bpp16) + { + color = (color >> 8) | (color << 8); + while (w--) _img[_iwidth * y + x++] = (uint16_t) color; + } + else + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + //while (w--) _img8[_iwidth * y + x++] = (uint8_t) color; + memset(_img8+_iwidth * y + x, (uint8_t)color, w); + } } @@ -4574,12 +4745,27 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t if ((x + w) > _iwidth) w = _iwidth - x; if ((y + h) > _iheight) h = _iheight - y; if ((w < 1) || (h < 1)) return; - color = (color >> 8) | (color << 8); - while (h--) { + if (_bpp16) + { + color = (color >> 8) | (color << 8); + while (h--) + { int32_t ix = x, iw = w; while (iw--) _img[_iwidth * y + ix++] = (uint16_t) color; y++; + } + } + else + { + color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; + while (h--) + { + //int32_t ix = x, iw = w; + //while (iw--) _img8[_iwidth * y + ix++] = (uint8_t) color; + memset(_img8 + _iwidth * y + x, (uint8_t)color, w); + y++; + } } } @@ -4708,7 +4894,7 @@ size_t TFT_eSprite::write(uint8_t utf8) *************************************************************************************x*/ int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y) { - return drawChar(uniCode, x, y, textfont); + return drawChar(uniCode, x, y, textfont); } int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font) @@ -4842,11 +5028,13 @@ 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); int px = 0, py = pY; // To hold character block start and end column and row values int pc = 0; // Pixel count byte np = textsize * textsize; // Number of pixels in a drawn pixel - byte tnp = 0; // Temporary copy of np for while loop byte ts = textsize - 1; // Temporary copy of textsize // 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area // w is total number of pixels to plot to fill character block @@ -4869,15 +5057,9 @@ int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font) pc++; setWindow(px, py, px + ts, py + ts); - if (ts) { - tnp = np; - while (tnp--) { - pushColor(textcolor); - } - } - else { - pushColor(textcolor); - } + if (ts) while (np--) writeColor(color); + else writeColor(color); + px += textsize; if (px >= (x + width * textsize)) diff --git a/TFT_eSPI.h b/TFT_eSPI.h index ffb1c23..3042561 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -344,9 +344,6 @@ class TFT_eSPI : public Print { height(void), width(void); - virtual size_t write(uint8_t); - - // The TFT_eSprite class inherits the following functions void pushColors(uint16_t *data, uint8_t len), pushColors(uint8_t *data, uint32_t len), @@ -408,7 +405,7 @@ class TFT_eSPI : public Print { // Write a block of pixels to the screen void pushRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data); void pushSprite(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint16_t *data); - + void pushSprite(int32_t x0, int32_t y0, uint32_t w, uint32_t h, uint8_t *data); // This next function has been used successfully to dump the TFT screen to a PC for documentation purposes // It reads a screen area and returns the RGB 8 bit colour values of each pixel // Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes @@ -453,6 +450,7 @@ class TFT_eSPI : public Print { void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); void setTouch(uint16_t *data); + size_t write(uint8_t); private: @@ -556,9 +554,12 @@ class TFT_eSprite : public TFT_eSPI { TFT_eSprite(TFT_eSPI *tft); - uint16_t* createSprite(int16_t w, int16_t y); // 16 bpp + void createSprite(int16_t w, int16_t y); // 2 bytes per pixel + void deleteSprite(void); + void setColorDepth(int8_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), @@ -568,6 +569,7 @@ class TFT_eSprite : public TFT_eSPI { setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1), pushColor(uint32_t color), pushColor(uint32_t color, uint16_t len), + writeColor(uint16_t color), drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), @@ -601,10 +603,12 @@ class TFT_eSprite : public TFT_eSPI { protected: uint16_t *_img; + uint8_t *_img8; + bool _created; int32_t _icursor_x, _icursor_y, _xs, _ys, _xe, _ye, _xptr, _yptr; - int32_t _iwidth, _iheight; // Display w/h as modified by current rotation + uint32_t _iwidth, _iheight, _bpp16; }; diff --git a/examples/Sprite/Sprite_scroll_text/Sprite_scroll_text.ino b/examples/Sprite/Sprite_scroll_16bit/Sprite_scroll_16bit.ino similarity index 100% rename from examples/Sprite/Sprite_scroll_text/Sprite_scroll_text.ino rename to examples/Sprite/Sprite_scroll_16bit/Sprite_scroll_16bit.ino diff --git a/examples/Sprite/Sprite_scroll_8bit/Sprite_scroll_8bit.ino b/examples/Sprite/Sprite_scroll_8bit/Sprite_scroll_8bit.ino new file mode 100644 index 0000000..beca732 --- /dev/null +++ b/examples/Sprite/Sprite_scroll_8bit/Sprite_scroll_8bit.ino @@ -0,0 +1,205 @@ +/* + Display "flicker free" scrolling text and updating number + + This sketch uses 8 bit colour sprites to save RAM. + + Example for library: + https://github.com/Bodmer/TFT_eSPI + + The sketch has been tested on a 320x240 ILI9341 based TFT, it + coule be adapted for other screen sizes. + + A Sprite is notionally an invisible graphics screen that is + kept in the processors RAM. Graphics can be drawn into the + Sprite just as it can be drawn directly to the screen. Once + the Sprite is completed it can be plotted onto the screen in + any position. If there is sufficient RAM then the Sprite can + be the same size as the screen and used as a frame buffer. + + A 16 bit colour Sprite occupies (2 * width * height) bytes. + + An 8 bit colour Sprite occupies (width * height) bytes. + + On a ESP8266, 16 bit Sprite sizes up to 128 x 160 can be accomodated, + this size requires 128*160*2 bytes (40kBytes) of RAM. + + This sketch sets the colour depth to 8 bits so larger sprites can be + created. 8 bit colour sprites use half amount of RAM. If the colour + depth is not specified then 16 bits is assumed. + + You need to make the sprite small enough to fit, with RAM spare for + any "local variables" that may be needed by your sketch and libraries. + + Created by Bodmer 21/11/17 + + ######################################################################### + ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ###### + ######################################################################### +*/ + +// Size of sprite image for the scrolling text, this requires ~14 Kbytes of RAM +#define IWIDTH 240 +#define IHEIGHT 30 + +// Pause in milliseconds to set scroll speed +#define WAIT 0 + +#include // Include the graphics library (this includes the sprite functions) + +TFT_eSPI tft = TFT_eSPI(); // Create object "tft" + +TFT_eSprite img = TFT_eSprite(&tft); // Create Sprite object "img" with pointer to "tft" object +// // the pointer is used by pushSprite() to push it onto the TFT + +// ------------------------------------------------------------------------- +// Setup +// ------------------------------------------------------------------------- +void setup(void) { + tft.init(); + tft.setRotation(0); + + tft.fillScreen(TFT_BLUE); +} + +// ------------------------------------------------------------------------- +// Main loop +// ------------------------------------------------------------------------- +void loop() { + + while (1) + { + // Set colour depth of Sprite to 8 (or 16) bits + img.setColorDepth(8); + + // Create the sprite and clear background to black + img.createSprite(IWIDTH, IHEIGHT); + //img.fillSprite(TFT_BLACK); // Optional here as we fill the sprite later anyway + + for (int pos = IWIDTH; pos > 0; pos--) + { + build_banner("Hello World", pos); + img.pushSprite(0, 0); + + build_banner("TFT_eSPI sprite" , pos); + img.pushSprite(0, 50); + + delay(WAIT); + } + + // Delete sprite to free up the memory + img.deleteSprite(); + + // Create a sprite of a different size + numberBox(random(100), 60, 100); + + } +} + +// ######################################################################### +// Build the scrolling sprite image from scratch, draw text at x = xpos +// ######################################################################### + +void build_banner(String msg, int xpos) +{ + int h = IHEIGHT; + + // We could just use fillSprite(color) but lets be a bit more creative... + + // Fill with rainbow stripes + while (h--) img.drawFastHLine(0, h, IWIDTH, rainbow(h * 4)); + + // Draw some graphics, the text will apear to scroll over these + img.fillRect (IWIDTH / 2 - 20, IHEIGHT / 2 - 10, 40, 20, TFT_YELLOW); + img.fillCircle(IWIDTH / 2, IHEIGHT / 2, 10, TFT_ORANGE); + + // Now print text on top of the graphics + img.setTextSize(1); // Font size scaling is x1 + img.setTextFont(4); // Font 4 selected + img.setTextColor(TFT_BLACK); // Black text, no background colour + img.setTextWrap(false); // Turn of wrap so we can print past end of sprite + + // Need to print twice so text appears to wrap around at left and right edges + img.setCursor(xpos, 2); // Print text at xpos + img.print(msg); + + img.setCursor(xpos - IWIDTH, 2); // Print text at xpos - sprite width + img.print(msg); +} + +// ######################################################################### +// Create sprite, plot graphics in it, plot to screen, then delete sprite +// ######################################################################### +void numberBox(int num, int x, int y) +{ + // Create a sprite 80 pixels wide, 50 high (8kbytes of RAM needed) + img.createSprite(80, 50); + + // Fill it with black + img.fillSprite(TFT_BLACK); + + // Draw a backgorund of 2 filled triangles + img.fillTriangle( 0, 0, 0, 49, 40, 25, TFT_RED); + img.fillTriangle( 79, 0, 79, 49, 40, 25, TFT_DARKGREEN); + + // Set the font parameters + img.setTextSize(1); // Font size scaling is x1 + img.setFreeFont(&FreeSerifBoldItalic24pt7b); // Select free font + img.setTextColor(TFT_WHITE); // White text, no background colour + + // Set text coordinate datum to middle centre + img.setTextDatum(MC_DATUM); + + // Draw the number in middle of 80 x 50 sprite + img.drawNumber(num, 40, 25); + + // Push sprite to TFT screen CGRAM at coordinate x,y (top left corner) + img.pushSprite(x, y); + + // Delete sprite to free up the RAM + img.deleteSprite(); +} + + +// ######################################################################### +// Return a 16 bit rainbow colour +// ######################################################################### +unsigned int rainbow(byte value) +{ + // Value is expected to be in range 0-127 + // The value is converted to a spectrum colour from 0 = red through to 127 = blue + + byte red = 0; // Red is the top 5 bits of a 16 bit colour value + byte green = 0;// Green is the middle 6 bits + byte blue = 0; // Blue is the bottom 5 bits + + byte sector = value >> 5; + byte amplit = value & 0x1F; + + switch (sector) + { + case 0: + red = 0x1F; + green = amplit; + blue = 0; + break; + case 1: + red = 0x1F - amplit; + green = 0x1F; + blue = 0; + break; + case 2: + red = 0; + green = 0x1F; + blue = amplit; + break; + case 3: + red = 0; + green = 0x1F - amplit; + blue = 0x1F; + break; + } + + return red << 11 | green << 6 | blue; +} + +