Add sprite class

Sprites (images) can now be created in RAM, written to with text and
graphics and rendered to screen quickly, this makes it easier to get
flicker frre screen updates.
ESP8266 can typically create up to a 160x128 sprite, and ESP32 about
200x200 pixels. 16 bit colour only at the moment, may soon implement 8
bit colour to reduce RAM.
This commit is contained in:
Bodmer
2017-11-15 20:26:22 +00:00
parent 62c02b67f7
commit 943c18facf
8 changed files with 1625 additions and 136 deletions

View File

@@ -5,6 +5,7 @@ drawPixel KEYWORD2
drawChar KEYWORD2 drawChar KEYWORD2
setAddrWindow KEYWORD2 setAddrWindow KEYWORD2
setWindow KEYWORD2 setWindow KEYWORD2
readAddrWindow KEYWORD2
pushColor KEYWORD2 pushColor KEYWORD2
pushColor KEYWORD2 pushColor KEYWORD2
pushColors KEYWORD2 pushColors KEYWORD2
@@ -49,8 +50,10 @@ readcommand32 KEYWORD2
readPixel KEYWORD2 readPixel KEYWORD2
readRect KEYWORD2 readRect KEYWORD2
pushRect KEYWORD2 pushRect KEYWORD2
pushSprite KEYWORD2
readRectRGB KEYWORD2 readRectRGB KEYWORD2
getRotation KEYWORD2 getRotation KEYWORD2
getTextDatum KEYWORD2
fontsLoaded KEYWORD2 fontsLoaded KEYWORD2
color565 KEYWORD2 color565 KEYWORD2
drawChar KEYWORD2 drawChar KEYWORD2
@@ -64,3 +67,32 @@ width KEYWORD2
textWidth KEYWORD2 textWidth KEYWORD2
fontHeight KEYWORD2 fontHeight KEYWORD2
getTouchRaw KEYWORD2
getTouchRawZ KEYWORD2
getTouch KEYWORD2
calibrateTouch KEYWORD2
setTouch KEYWORD2
validTouch KEYWORD2
TFT_eSPI_Button KEYWORD1
initButton KEYWORD2
textcolor KEYWORD2
initButtonUL KEYWORD2
drawButton KEYWORD2
contains KEYWORD2
press KEYWORD2
isPressed KEYWORD2
justPressed KEYWORD2
justReleased KEYWORD2
TFT_eSprite KEYWORD1
createSprite KEYWORD2
deleteSprite KEYWORD2
fillSprite KEYWORD2
setWindow KEYWORD2
pushBitmap KEYWORD2
pushSprite KEYWORD2

View File

@@ -512,13 +512,14 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
***************************************************************************************/ ***************************************************************************************/
void TFT_eSPI::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data) void TFT_eSPI::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
{ {
if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return; if ((x >= _width) || (y >= _height) || (w == 0) || (h == 0)) return;
spi_begin(); spi_begin();
setAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low and sent RAMWR setAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low and sent RAMWR
uint32_t len = w * h * 2; uint32_t len = w * h * 2;
// Push pixels into window rectangle, data is a 16 bit pointer thus increment is halved // Push pixels into window rectangle, data is a 16 bit pointer thus increment is halved
while ( len >=32 ) {SPI.writeBytes((uint8_t*)data, 32); data += 16; len -= 32; } while ( len >=32 ) {SPI.writeBytes((uint8_t*)data, 32); data += 16; len -= 32; }
if (len) SPI.writeBytes((uint8_t*)data, len); if (len) SPI.writeBytes((uint8_t*)data, len);
@@ -529,6 +530,62 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
} }
/***************************************************************************************
** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: push 565 pixel colours into a defined area
***************************************************************************************/
void TFT_eSPI::pushSprite(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_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;
//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
data += dx + dy * w;
while (dh--)
{
/*
uint32_t len = dw;
uint16_t* ptr = data;
// Push pixels into window rectangle, data is a 16 bit pointer thus increment is halved
while ( len--) SPI.write16(*ptr++, 0);
data += w;
*/
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();
}
/*************************************************************************************** /***************************************************************************************
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101") ** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read RGB pixel colours from a defined area ** Description: Read RGB pixel colours from a defined area
@@ -3906,7 +3963,7 @@ void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t
parameters[2] = touchCalibration_y0; parameters[2] = touchCalibration_y0;
parameters[3] = touchCalibration_y1; parameters[3] = touchCalibration_y1;
parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2); parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2);
} }
} }
@@ -4057,134 +4114,787 @@ boolean TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }
/***************************************************************************************
// The following class creates Sprites in RAM, graphics can then be drawn in the Sprite
// and rendered quickly onto the TFT screen. The class inherits the graphics functions
// from the TFT_eSPI class. Some functions are overridden by this class so that the
// graphics are written to the Sprite rather than the TFT.
// Coded by Bodmer
***************************************************************************************/
/***************************************************************************************
** Function name: TFT_eSprite
** Description: Class constructor
*************************************************************************************x*/
TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
{
_tft = tft; // Pointer to tft class so we can call member functions
_iwidth = 0; // Initialise width and height to 0 (it does not exist yet)
_iheight = 0;
_xs = 0; // window bounds for pushColor
_ys = 0;
_xe = 0;
_ye = 0;
_xptr = 0; // pushColor coordinate
_yptr = 0;
_icursor_y = _icursor_x = 0; // Text cursor position
}
/***************************************************************************************
/*************************************************** ** Function name: createSprite
The majority of code in this file is "FunWare", the only condition of use of ** Description: Create a sprite (bitmap) of defined width and height
those portions is that users have fun! Most of the effort has been spent on *************************************************************************************x*/
the creation and incorporation of the proportional Run Length Encoded fonts uint16_t* TFT_eSprite::createSprite(int16_t w, int16_t h)
that can be rendered over an SPI bus at high speeds. {
if ( w < 1 || h < 1) return 0;
A significant number of new features have been added to the original source _iwidth = w;
libraries. Functions names have been retained where practical to allow old _iheight = h;
Adafruit_GFX TFT screen compatible sketches to be easily adapted. _img = (uint16_t*) malloc(w * h * sizeof(uint16_t));
return _img;
A significant level of effort has been made to optimise the library for speed }
so that graphics intensive sketches can run at an acceptable speed over the
SPI bus. SPI bus speeds up to 80MHz can be used with some driver chips. At
this clock rate screen and block clears can achieve an average bit rate of
75Mbps.
The functions incldued are comaptible with the JPEGDecoder library here:
https://github.com/Bodmer/JPEGDecoder
This allows allows the ESP8266 (or ESP32) sketches to retrieve images from the
internet, store them in SPIFFS and render the images to the screen at an
acceptable speed. So some really cool IoT sketches are possible without tedious
manual loading of images.
Other portions of code are protected by the licenses as noted below.
The library would not have been created without the initial inspiration from
Adafruit_ILI9341 and Adafruit_GFX libraries.
If any other conditions of use have been missed then please raise this as an /***************************************************************************************
issue on GitHub: ** Function name: deleteSprite
** Description: Delete the sprite to free up memory (RAM)
*************************************************************************************x*/
void TFT_eSprite::deleteSprite(void)
{
free(_img);
}
/*************************************************** /***************************************************************************************
The Adafruit_ILI9341 library has been used as a starting point ** Function name: pushSprite
for this library. ** Description: Delete the sprite to free up memory (RAM)
*************************************************************************************x*/
ORIGINAL LIBRARY HEADER void TFT_eSprite::pushSprite(int32_t x, int32_t y)
{
This is our library for the Adafruit ILI9341 Breakout and Shield _tft->pushSprite(x, y, _iwidth, _iheight, _img);
----> http://www.adafruit.com/products/1651 }
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
/**************************************************** /***************************************************************************************
** Function name: readPixel
Some member funtions have been imported from the Adafruit_GFX ** Description: Read 565 colour of a pixel at deined coordinates
library. The license associated with these is reproduced below. *************************************************************************************x*/
uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
ORIGINAL LIBRARY HEADER from Adafruit_GFX.cpp {
uint16_t color = _img[x + y * _iwidth];
This is the core graphics library for all our displays, providing a common return (color >> 8) | (color << 8);
set of graphics primitives (points, lines, circles, etc.). It needs to be }
paired with a hardware-specific library for each display device we carry
(to handle the lower-level functions).
Adafruit invests time and resources providing this open source code, please
support Adafruit & open-source hardware by purchasing products from Adafruit!
Copyright (c) 2013 Adafruit Industries. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
****************************************************/
/**************************************************** /***************************************************************************************
** Function name: pushRect (same as pushBitmap)
** Description: push 565 colour bitmap into a defined area
*************************************************************************************x*/
void TFT_eSprite::pushRect(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;
In compliance with the licence.txt file for the Adafruit_GFX library the for (uint32_t yp = y; yp < y + h; yp++)
following is included. {
for (uint32_t xp = x; xp < x + w; xp++)
{
_img[xp + yp * _iwidth] = *data++;
}
}
}
Software License Agreement (BSD License)
Copyright (c) 2012 Adafruit Industries. All rights reserved. /***************************************************************************************
** Function name: pushBitmap (same as pushRect)
** Description: push 565 colour bitmap into a defined area
***************************************************************************************/
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;
Redistribution and use in source and binary forms, with or without for (uint32_t yp = y; yp < y + h; yp++)
modification, are permitted provided that the following conditions are met: {
for (uint32_t xp = x; xp < x + w; xp++)
{
_img[xp + yp * _iwidth] = *data++;
}
}
}
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" /***************************************************************************************
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** Function name: spriteWindow
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ** Description: Set the bounds of a window for pushColor
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE *************************************************************************************x*/
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF {
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // Bounds will be checked by drawPixel
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN if (x0 > x1) swap_coord(x0, x1);
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) if (y0 > y1) swap_coord(y0, y1);
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. _xs = x0;
_ys = y0;
_xe = x1;
_ye = y1;
_xptr = _xs;
_yptr = _ys;
}
/***************************************************************************************
** Function name: pushColor
** Description: Send a new pixel to the sprite window
*************************************************************************************x*/
void TFT_eSprite::pushColor(uint32_t color)
{
drawPixel(_xptr++, _yptr, color);
if (_xptr > _xe) { _xptr = _xs; _yptr++; }
if (_yptr > _ye) { _yptr = _ys; }
}
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; }
}
/***************************************************************************************
** Function name: fillSprite
** Description: Fill the whole sprite with defined colour
*************************************************************************************x*/
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);
else fillRect(0, 0, _iwidth, _iheight, 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;
}
/***************************************************************************************
** Function name: width or spriteWidth
** Description: Return the width of sprite
*************************************************************************************x*/
// Return the size of the display
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
** Description: Return the height of sprite
*************************************************************************************x*/
int16_t TFT_eSprite::height(void)
{
return _iheight;
}
/*
int16_t TFT_eSprite::spriteHeight(void)
{
return _iheight;
}
*/
/***************************************************************************************
** Function name: drawChar
** Description: draw a single character in the Adafruit GLCD or freefont
*************************************************************************************x*/
void TFT_eSprite::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size)
{
if ((x >= (int16_t)_iwidth) || // Clip right
(y >= (int16_t)_iheight) || // Clip bottom
((x + 6 * size - 1) < 0) || // Clip left
((y + 8 * size - 1) < 0)) // Clip top
return;
#ifdef LOAD_GLCD
//>>>>>>>>>>>>>>>>>>
#ifdef LOAD_GFXFF
if(!gfxFont) { // 'Classic' built-in font
#endif
//>>>>>>>>>>>>>>>>>>
boolean fillbg = (bg != color);
if ((size==1) && fillbg)
{
byte column[6];
byte mask = 0x1;
for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i);
column[5] = 0;
int8_t j, k;
for (j = 0; j < 8; j++) {
for (k = 0; k < 5; k++ ) {
if (column[k] & mask) {
drawPixel(x + k, y + j, color);
}
else {
drawPixel(x + k, y + j, bg);
}
}
mask <<= 1;
drawPixel(x + k, y + j, bg);
}
}
else
{
for (int8_t i = 0; i < 6; i++ ) {
uint8_t line;
if (i == 5)
line = 0x0;
else
line = pgm_read_byte(font + (c * 5) + i);
if (size == 1) // default size
{
for (int8_t j = 0; j < 8; j++) {
if (line & 0x1) drawPixel(x + i, y + j, color);
line >>= 1;
}
}
else { // big size
for (int8_t j = 0; j < 8; j++) {
if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color);
else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg);
line >>= 1;
}
}
}
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
#ifdef LOAD_GFXFF
} else { // Custom font
#endif
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
#endif // LOAD_GLCD
#ifdef LOAD_GFXFF
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Character is assumed previously filtered by write() to eliminate
// newlines, returns, non-printable characters, etc. Calling drawChar()
// directly with 'bad' characters of font may cause mayhem!
if (c > pgm_read_byte(&gfxFont->last)) c = pgm_read_byte(&gfxFont->first);;
c -= pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap);
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height),
xa = pgm_read_byte(&glyph->xAdvance);
int8_t xo = pgm_read_byte(&glyph->xOffset),
yo = pgm_read_byte(&glyph->yOffset);
uint8_t xx, yy, bits, bit=0;
int16_t xo16, yo16;
if(size > 1) {
xo16 = xo;
yo16 = yo;
}
uint16_t hpc = 0; // Horizontal foreground pixel count
for(yy=0; yy<h; yy++) {
for(xx=0; xx<w; xx++) {
if(bit == 0) {
bits = pgm_read_byte(&bitmap[bo++]);
bit = 0x80;
}
if(bits & bit) hpc++;
else {
if (hpc) {
if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
hpc=0;
}
}
bit >>= 1;
}
// Draw pixels for this line as we are about to increment yy
if (hpc) {
if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
hpc=0;
}
}
#endif
#ifdef LOAD_GLCD
#ifdef LOAD_GFXFF
} // End classic vs custom font
#endif
#endif
}
/***************************************************************************************
** Function name: drawPixel
** Description: push a single pixel at an arbitrary position
*************************************************************************************x*/
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;
}
/***************************************************************************************
** Function name: drawLine
** Description: draw a line between 2 arbitrary points
*************************************************************************************x*/
void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
{
boolean steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
swap_coord(x0, y0);
swap_coord(x1, y1);
}
if (x0 > x1) {
swap_coord(x0, x1);
swap_coord(y0, y1);
}
int32_t dx = x1 - x0, dy = abs(y1 - y0);;
int32_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
if (y0 < y1) ystep = 1;
// Split into steep and not steep for FastH/V separation
if (steep) {
for (; x0 <= x1; x0++) {
dlen++;
err -= dy;
if (err < 0) {
err += dx;
if (dlen == 1) drawPixel(y0, xs, color);
else drawFastVLine(y0, xs, dlen, color);
dlen = 0; y0 += ystep; xs = x0 + 1;
}
}
if (dlen) drawFastVLine(y0, xs, dlen, color);
}
else
{
for (; x0 <= x1; x0++) {
dlen++;
err -= dy;
if (err < 0) {
err += dx;
if (dlen == 1) drawPixel(xs, y0, color);
else drawFastHLine(xs, y0, dlen, color);
dlen = 0; y0 += ystep; xs = x0 + 1;
}
}
if (dlen) drawFastHLine(xs, y0, dlen, color);
}
}
/***************************************************************************************
** Function name: drawFastVLine
** Description: draw a vertical line
*************************************************************************************x*/
void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
{
if ((x < 0) || (x >= _iwidth) || (y >= _iheight)) return;
if (y < 0) { h += y; y = 0; }
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;
}
/***************************************************************************************
** Function name: drawFastHLine
** Description: draw a horizontal line
*************************************************************************************x*/
void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
{
if ((y < 0) || (x >= _iwidth) || (y >= _iheight)) return;
if (x < 0) { w += x; x = 0; }
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;
}
/***************************************************************************************
** Function name: fillRect
** Description: draw a filled rectangle
*************************************************************************************x*/
void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
{
if (x < 0) { w += x; x = 0; }
if ((x < 0) || (y < 0) || (x >= _iwidth) || (y >= _iheight)) return;
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--) {
int32_t ix = x, iw = w;
while (iw--) _img[_iwidth * y + ix++] = (uint16_t) color;
y++;
}
}
/***************************************************************************************
** Function name: write
** Description: draw characters piped through serial stream
*************************************************************************************x*/
size_t TFT_eSprite::write(uint8_t utf8)
{
if (utf8 == '\r') return 1;
uint8_t uniCode = utf8; // Work with a copy
if (utf8 == '\n') uniCode+=22; // Make it a valid space character to stop errors
uint16_t width = 0;
uint16_t height = 0;
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//Serial.print((uint8_t) uniCode); // Debug line sends all printed TFT text to serial port
//Serial.println(uniCode, HEX); // Debug line sends all printed TFT text to serial port
//delay(5); // Debug optional wait for serial port to flush through
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#ifdef LOAD_GFXFF
if(!gfxFont) {
#endif
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#ifdef LOAD_FONT2
if (textfont == 2)
{
// This is 20us faster than using the fontdata structure (0.443ms per character instead of 0.465ms)
width = pgm_read_byte(widtbl_f16 + uniCode-32);
height = chr_hgt_f16;
// Font 2 is rendered in whole byte widths so we must allow for this
width = (width + 6) / 8; // Width in whole bytes for font 2, should be + 7 but must allow for font width change
width = width * 8; // Width converted back to pixles
}
#ifdef LOAD_RLE
else
#endif
#endif
#ifdef LOAD_RLE
{
if ((textfont>2) && (textfont<9))
{
// Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
// A tad slower than above but this is not significant and is more convenient for the RLE fonts
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
height= pgm_read_byte( &fontdata[textfont].height );
}
}
#endif
#ifdef LOAD_GLCD
if (textfont==1)
{
width = 6;
height = 8;
}
#else
if (textfont==1) return 0;
#endif
height = height * textsize;
if (utf8 == '\n')
{
_icursor_y += height;
_icursor_x = 0;
}
else
{
if (textwrap && (_icursor_x + width * textsize > _iwidth))
{
_icursor_y += height;
_icursor_x = 0;
}
_icursor_x += drawChar(uniCode, _icursor_x, _icursor_y, textfont);
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#ifdef LOAD_GFXFF
} // Custom GFX font
else
{
if(utf8 == '\n') {
_icursor_x = 0;
_icursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else if(uniCode != '\r') {
if (uniCode > (uint8_t)pgm_read_byte(&gfxFont->last)) uniCode = pgm_read_byte(&gfxFont->first);
if(uniCode >= pgm_read_byte(&gfxFont->first)) {
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
uint8_t w = pgm_read_byte(&glyph->width),
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(textwrap && ((_icursor_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);
}
drawChar(_icursor_x, _icursor_y, uniCode, textcolor, textbgcolor, textsize);
}
_icursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
}
}
}
#endif // LOAD_GFXFF
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return 1;
}
/***************************************************************************************
** Function name: drawChar
** Description: draw a unicode onto the screen
*************************************************************************************x*/
int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y)
{
return drawChar(uniCode, x, y, textfont);
}
int16_t TFT_eSprite::drawChar(unsigned int uniCode, int x, int y, int font)
{
if (font==1)
{
#ifdef LOAD_GLCD
#ifndef LOAD_GFXFF
drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
return 6 * textsize;
#endif
#else
#ifndef LOAD_GFXFF
return 0;
#endif
#endif
#ifdef LOAD_GFXFF
drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
if(!gfxFont) { // 'Classic' built-in font
#ifdef LOAD_GLCD
return 6 * textsize;
#else
return 0;
#endif
}
else
{
if (uniCode > pgm_read_byte(&gfxFont->last)) uniCode = pgm_read_byte(&gfxFont->first);
if(uniCode >= pgm_read_byte(&gfxFont->first))
{
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
return pgm_read_byte(&glyph->xAdvance) * textsize;
}
else
{
return 0;
}
}
#endif
}
int width = 0;
int height = 0;
uint32_t flash_address = 0;
uniCode -= 32;
#ifdef LOAD_FONT2
if (font == 2)
{
// This is faster than using the fontdata structure
flash_address = pgm_read_dword(&chrtbl_f16[uniCode]);
width = pgm_read_byte(widtbl_f16 + uniCode);
height = chr_hgt_f16;
}
#ifdef LOAD_RLE
else
#endif
#endif
#ifdef LOAD_RLE
{
if ((font>2) && (font<9))
{
// This is slower than above but is more convenient for the RLE fonts
flash_address = pgm_read_dword( pgm_read_dword( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *) );
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[font].widthtbl ) ) + uniCode );
height= pgm_read_byte( &fontdata[font].height );
}
}
#endif
int w = width;
int pX = 0;
int pY = y;
byte line = 0;
#ifdef LOAD_FONT2 // chop out code if we do not need it
if (font == 2) {
w = w + 6; // Should be + 7 but we need to compensate for width increment
w = w / 8;
if (x + width * textsize >= (int16_t)_iwidth) return width * textsize ;
for (int i = 0; i < height; i++)
{
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize, textbgcolor);
for (int k = 0; k < w; k++)
{
line = pgm_read_byte((uint8_t *)flash_address + w * i + k);
if (line) {
if (textsize == 1) {
pX = x + k * 8;
if (line & 0x80) drawPixel(pX, pY, textcolor);
if (line & 0x40) drawPixel(pX + 1, pY, textcolor);
if (line & 0x20) drawPixel(pX + 2, pY, textcolor);
if (line & 0x10) drawPixel(pX + 3, pY, textcolor);
if (line & 0x08) drawPixel(pX + 4, pY, textcolor);
if (line & 0x04) drawPixel(pX + 5, pY, textcolor);
if (line & 0x02) drawPixel(pX + 6, pY, textcolor);
if (line & 0x01) drawPixel(pX + 7, pY, textcolor);
}
else {
pX = x + k * 8 * textsize;
if (line & 0x80) fillRect(pX, pY, textsize, textsize, textcolor);
if (line & 0x40) fillRect(pX + textsize, pY, textsize, textsize, textcolor);
if (line & 0x20) fillRect(pX + 2 * textsize, pY, textsize, textsize, textcolor);
if (line & 0x10) fillRect(pX + 3 * textsize, pY, textsize, textsize, textcolor);
if (line & 0x08) fillRect(pX + 4 * textsize, pY, textsize, textsize, textcolor);
if (line & 0x04) fillRect(pX + 5 * textsize, pY, textsize, textsize, textcolor);
if (line & 0x02) fillRect(pX + 6 * textsize, pY, textsize, textsize, textcolor);
if (line & 0x01) fillRect(pX + 7 * textsize, pY, textsize, textsize, textcolor);
}
}
}
pY += textsize;
}
}
#ifdef LOAD_RLE
else
#endif
#endif //FONT2
#ifdef LOAD_RLE //674 bytes of code
// Font is not 2 and hence is RLE encoded
{
w *= height; // Now w is total number of pixels in the character
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
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
while (pc < w)
{
line = pgm_read_byte((uint8_t *)flash_address);
flash_address++; // 20 bytes smaller by incrementing here
if (line & 0x80) {
line &= 0x7F;
line++;
if (ts) {
px = x + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow
py = y + textsize * (pc / width);
}
else {
px = x + pc % width; // Keep these px and py calculations outside the loop as they are slow
py = y + pc / width;
}
while (line--) {
pc++;
setWindow(px, py, px + ts, py + ts);
if (ts) {
tnp = np;
while (tnp--) {
pushColor(textcolor);
}
}
else {
pushColor(textcolor);
}
px += textsize;
if (px >= (x + width * textsize))
{
px = x;
py += textsize;
}
}
}
else {
line++;
pc += line;
}
}
}
// End of RLE font rendering
#endif
return width * textsize; // x +
}
*****************************************************/

View File

@@ -30,6 +30,11 @@
#define SPI_FREQUENCY 20000000 #define SPI_FREQUENCY 20000000
#endif #endif
// If the frequency is not defined, set a default
#ifndef SPI_TOUCH_FREQUENCY
#define SPI_TOUCH_FREQUENCY 2500000
#endif
// Only load the fonts defined in User_Setup.h (to save space) // Only load the fonts defined in User_Setup.h (to save space)
// Set flag so RLE rendering code is optionally compiled // Set flag so RLE rendering code is optionally compiled
#ifdef LOAD_GLCD #ifdef LOAD_GLCD
@@ -267,8 +272,11 @@ typedef struct {
// Now fill the structure // Now fill the structure
const PROGMEM fontinfo fontdata [] = { const PROGMEM fontinfo fontdata [] = {
#ifdef LOAD_GLCD
{ (const uint8_t *)font, widtbl_null, 0, 0 },
#else
{ (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 },
#endif
// GLCD font (Font 1) does not have all parameters // GLCD font (Font 1) does not have all parameters
{ (const uint8_t *)chrtbl_null, widtbl_null, 8, 7 }, { (const uint8_t *)chrtbl_null, widtbl_null, 8, 7 },
@@ -320,25 +328,32 @@ class TFT_eSPI : public Print {
void init(void), begin(void); // Same - begin included for backwards compatibility void init(void), begin(void); // Same - begin included for backwards compatibility
void drawPixel(uint32_t x, uint32_t y, uint32_t color); // These are virtual so the TFT_eSprite class can override them with sprite specific functions
virtual void drawPixel(uint32_t x, uint32_t y, uint32_t color),
drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t font),
setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1),
pushColor(uint16_t color),
pushColor(uint16_t color, uint16_t len),
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),
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);
void drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t font), virtual int16_t drawChar(unsigned int uniCode, int x, int y, int font),
setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1), drawChar(unsigned int uniCode, int x, int y),
height(void),
width(void);
pushColor(uint16_t color), virtual size_t write(uint8_t);
pushColor(uint16_t color, uint16_t len),
pushColors(uint16_t *data, uint8_t len),
// The TFT_eSprite class inherits the following functions
void pushColors(uint16_t *data, uint8_t len),
pushColors(uint8_t *data, uint32_t len), pushColors(uint8_t *data, uint32_t len),
fillScreen(uint32_t color), fillScreen(uint32_t color);
drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color), void drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color),
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),
drawRect(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),
drawRoundRect(int32_t x0, int32_t y0, int32_t w, int32_t h, int32_t radius, uint32_t color), drawRoundRect(int32_t x0, int32_t y0, int32_t w, int32_t h, int32_t radius, uint32_t color),
fillRoundRect(int32_t x0, int32_t y0, int32_t w, int32_t h, int32_t radius, uint32_t color), fillRoundRect(int32_t x0, int32_t y0, int32_t w, int32_t h, int32_t radius, uint32_t color),
@@ -392,6 +407,7 @@ class TFT_eSPI : public Print {
void readRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data); void readRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data);
// Write a block of pixels to the screen // 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 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);
// This next function has been used successfully to dump the TFT screen to a PC for documentation purposes // 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 // It reads a screen area and returns the RGB 8 bit colour values of each pixel
@@ -404,9 +420,7 @@ class TFT_eSPI : public Print {
uint16_t fontsLoaded(void), uint16_t fontsLoaded(void),
color565(uint8_t r, uint8_t g, uint8_t b); color565(uint8_t r, uint8_t g, uint8_t b);
int16_t drawChar(unsigned int uniCode, int x, int y, int font), int16_t drawNumber(long long_num,int poX, int poY, int font),
drawChar(unsigned int uniCode, int x, int y),
drawNumber(long long_num,int poX, int poY, int font),
drawNumber(long long_num,int poX, int poY), drawNumber(long long_num,int poX, int poY),
drawFloat(float floatNumber,int decimal,int poX, int poY, int font), drawFloat(float floatNumber,int decimal,int poX, int poY, int font),
drawFloat(float floatNumber,int decimal,int poX, int poY), drawFloat(float floatNumber,int decimal,int poX, int poY),
@@ -423,9 +437,7 @@ class TFT_eSPI : public Print {
drawCentreString(const String& string, int dX, int poY, int font), // Deprecated, use setTextDatum() and drawString() drawCentreString(const String& string, int dX, int poY, int font), // Deprecated, use setTextDatum() and drawString()
drawRightString(const String& string, int dX, int poY, int font); // Deprecated, use setTextDatum() and drawString() drawRightString(const String& string, int dX, int poY, int font); // Deprecated, use setTextDatum() and drawString()
int16_t height(void), int16_t textWidth(const char *string, int font),
width(void),
textWidth(const char *string, int font),
textWidth(const char *string), textWidth(const char *string),
textWidth(const String& string, int font), textWidth(const String& string, int font),
textWidth(const String& string), textWidth(const String& string),
@@ -441,7 +453,6 @@ class TFT_eSPI : public Print {
void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size);
void setTouch(uint16_t *data); void setTouch(uint16_t *data);
virtual size_t write(uint8_t);
private: private:
@@ -531,6 +542,74 @@ class TFT_eSPI_Button {
boolean currstate, laststate; boolean currstate, laststate;
}; };
/***************************************************************************************
// The following class creates Sprites in RAM, graphics can then be drawn in the Sprite
// and rendered quickly onto the TFT screen. The class inherits the graphics functions
// from the TFT_eSPI class. Some functions are overridden by this class so that the
// graphics are written to the Sprite rather than the TFT.
***************************************************************************************/
class TFT_eSprite : public TFT_eSPI {
public:
TFT_eSprite(TFT_eSPI *tft);
uint16_t* createSprite(int16_t w, int16_t y); // 16 bpp
void deleteSprite(void);
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),
fillSprite(uint32_t color),
setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1),
pushColor(uint32_t color),
pushColor(uint32_t color, uint16_t len),
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),
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),
setCursor(int16_t x, int16_t y);
// Read the colour of a pixel at x,y and return value in 565 format
uint16_t readPixel(int32_t x0, int32_t y0);
// Write a block of pixels to the sprite
void pushRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data);
void pushBitmap(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data);
void pushSprite(int32_t x, int32_t y);
int16_t drawChar(unsigned int uniCode, int x, int y, int font),
drawChar(unsigned int uniCode, int x, int y);
int16_t height(void),
width(void);
size_t write(uint8_t);
private:
TFT_eSPI *_tft;
protected:
uint16_t *_img;
int32_t _icursor_x, _icursor_y, _xs, _ys, _xe, _ye, _xptr, _yptr;
int32_t _iwidth, _iheight; // Display w/h as modified by current rotation
};
#endif #endif
/*************************************************** /***************************************************

View File

@@ -28,6 +28,7 @@
//#include <User_Setups/Setup8_ILI9163_128x128.h> // Setup file configured for my ILI9163 128x128 display //#include <User_Setups/Setup8_ILI9163_128x128.h> // Setup file configured for my ILI9163 128x128 display
//#include <User_Setups/Setup9_ST7735_Overlap.h> // Setup file configured for my ST7735 //#include <User_Setups/Setup9_ST7735_Overlap.h> // Setup file configured for my ST7735
//#include <User_Setups/Setup10_RPi_touch_ILI9486.h> // Setup file configured for my stock RPi TFT with touch //#include <User_Setups/Setup10_RPi_touch_ILI9486.h> // Setup file configured for my stock RPi TFT with touch
//#include <User_Setups/Setup11_RPi_touch_ILI9486.h> // Setup file configured for my stock RPi TFT with touch
//#include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting //#include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting

View File

@@ -0,0 +1,199 @@
/*
Display all the fast rendering fonts.
Make sure all the display driver and pin comnections are correct by
editting the User_Setup.h file in the TFT_eSPI library folder.
#########################################################################
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
#########################################################################
*/
// Create a sprite 160 x 128 pixels (needs 40Kbytes of RAM!)
#define IWIDTH 160
#define IHEIGHT 128
// New background colour
#define TFT_BROWN 0x38E0
// Pause in milliseconds between screens, change to 0 to time font rendering
#define WAIT 500
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFT_eSprite img = TFT_eSprite(&tft);
unsigned long targetTime = 0; // Used for testing draw times
void setup(void) {
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_BLUE);
img.createSprite(IWIDTH, IHEIGHT);
img.fillSprite(TFT_BLACK);
}
void loop() {
targetTime = millis();
// First we test them with a background colour set
img.setTextSize(1);
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_GREEN, TFT_BLACK);
img.drawString(" !\"#$%&'()*+,-./0123456", 0, 0, 2);
img.drawString("789:;<=>?@ABCDEFGHIJKL", 0, 16, 2);
img.drawString("MNOPQRSTUVWXYZ[\\]^_`", 0, 32, 2);
img.drawString("abcdefghijklmnopqrstuvw", 0, 48, 2);
int xpos = 0;
xpos += img.drawString("xyz{|}~", 0, 64, 2);
img.drawChar(127, xpos, 64, 2);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_GREEN, TFT_BLACK);
img.drawString(" !\"#$%&'()*+,-.", 0, 0, 4);
img.drawString("/0123456789:;", 0, 26, 4);
img.drawString("<=>?@ABCDE", 0, 52, 4);
img.drawString("FGHIJKLMNO", 0, 78, 4);
img.drawString("PQRSTUVWX", 0, 104, 4);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BLACK);
img.drawString("YZ[\\]^_`abc", 0, 0, 4);
img.drawString("defghijklmno", 0, 26, 4);
img.drawString("pqrstuvwxyz", 0, 52, 4);
xpos = 0;
xpos += img.drawString("{|}~", 0, 78, 4);
img.drawChar(127, xpos, 78, 4);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_BLUE, TFT_BLACK);
img.drawString("012345", 0, 0, 6);
img.drawString("6789", 0, 40, 6);
img.drawString("apm-:.", 0, 80, 6);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_RED, TFT_BLACK);
img.drawString("0123", 0, 0, 7);
img.drawString("4567", 0, 60, 7);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BLACK);
img.drawString("890:.", 0, 0, 7);
img.drawString("", 0, 60, 7);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BLACK);
img.setTextColor(TFT_YELLOW, TFT_BLACK);
img.drawString("01", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.drawString("23", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.drawString("45", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.drawString("67", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.drawString("89", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.drawString("0:.", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.setTextColor(TFT_WHITE);
img.drawNumber(millis() - targetTime, 0, 100, 4);
img.pushSprite(0, 0); delay(WAIT);
delay(4000);
// Now test them with transparent background
targetTime = millis();
img.setTextSize(1);
img.fillSprite(TFT_BROWN);
img.setTextColor(TFT_GREEN);
img.drawString(" !\"#$%&'()*+,-./0123456", 0, 0, 2);
img.drawString("789:;<=>?@ABCDEFGHIJKL", 0, 16, 2);
img.drawString("MNOPQRSTUVWXYZ[\\]^_`", 0, 32, 2);
img.drawString("abcdefghijklmnopqrstuvw", 0, 48, 2);
xpos = 0;
xpos += img.drawString("xyz{|}~", 0, 64, 2);
img.drawChar(127, xpos, 64, 2);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.setTextColor(TFT_GREEN);
img.drawString(" !\"#$%&'()*+,-.", 0, 0, 4);
img.drawString("/0123456789:;", 0, 26, 4);
img.drawString("<=>?@ABCDE", 0, 52, 4);
img.drawString("FGHIJKLMNO", 0, 78, 4);
img.drawString("PQRSTUVWX", 0, 104, 4);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.drawString("YZ[\\]^_`abc", 0, 0, 4);
img.drawString("defghijklmno", 0, 26, 4);
img.drawString("pqrstuvwxyz", 0, 52, 4);
xpos = 0;
xpos += img.drawString("{|}~", 0, 78, 4);
img.drawChar(127, xpos, 78, 4);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.setTextColor(TFT_BLUE);
img.drawString("012345", 0, 0, 6);
img.drawString("6789", 0, 40, 6);
img.drawString("apm-:.", 0, 80, 6);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.setTextColor(TFT_RED);
img.drawString("0123", 0, 0, 7);
img.drawString("4567", 0, 60, 7);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.drawString("890:.", 0, 0, 7);
img.drawString("", 0, 60, 7);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.setTextColor(TFT_YELLOW);
img.drawString("0123", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.drawString("4567", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.fillSprite(TFT_BROWN);
img.drawString("890:.", 0, 0, 8);
img.pushSprite(0, 0); delay(WAIT);
img.setTextColor(TFT_WHITE);
img.drawNumber(millis() - targetTime, 0, 100, 4);
img.pushSprite(0, 0); delay(WAIT);
delay(4000);;
}

View File

@@ -0,0 +1,140 @@
/*
An example showing rainbow colours on a 160x128 TFT LCD screen
and to show a basic example of font use.
This example plots the text in a sprite then pushes the sprite to the
TFT screen.
Make sure all the display driver and pin comnenctions are correct by
editting the User_Setup.h file in the TFT_eSPI library folder.
Note that yield() or delay(0) must be called in long duration for/while
loops to stop the ESP8266 watchdog triggering.
#########################################################################
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
#########################################################################
*/
#define IWIDTH 160
#define IHEIGHT 128
#include <TFT_eSPI.h> // Graphics and font library
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFT_eSprite img = TFT_eSprite(&tft);
unsigned long targetTime = 0;
byte red = 31;
byte green = 0;
byte blue = 0;
byte state = 0;
unsigned int colour = red << 11;
void setup(void) {
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
imgPtr = img.createSprite(IWIDTH, IHEIGHT);
img.fillSprite(TFT_BLACK);
targetTime = millis() + 1000;
}
void loop() {
if (targetTime < millis()) {
targetTime = millis() + 100;//10000;
// Colour changing state machine
for (int i = 0; i < 160; i++) {
img.drawFastVLine(i, 0, img.height(), colour);
switch (state) {
case 0:
green += 2;
if (green == 64) {
green = 63;
state = 1;
}
break;
case 1:
red--;
if (red == 255) {
red = 0;
state = 2;
}
break;
case 2:
blue ++;
if (blue == 32) {
blue = 31;
state = 3;
}
break;
case 3:
green -= 2;
if (green == 255) {
green = 0;
state = 4;
}
break;
case 4:
red ++;
if (red == 32) {
red = 31;
state = 5;
}
break;
case 5:
blue --;
if (blue == 255) {
blue = 0;
state = 0;
}
break;
}
colour = red << 11 | green << 5 | blue;
}
// The standard ADAFruit font still works as before
img.setTextColor(TFT_BLACK);
img.setCursor (12, 5);
img.print("Original ADAfruit font!");
// The new larger fonts do not use the .setCursor call, coords are embedded
img.setTextColor(TFT_BLACK, TFT_BLACK); // Do not plot the background colour
// Overlay the black text on top of the rainbow plot (the advantage of not drawing the backgorund colour!)
img.drawCentreString("Font size 2", 80, 14, 2); // Draw text centre at position 80, 12 using font 2
//img.drawCentreString("Font size 2",81,12,2); // Draw text centre at position 80, 12 using font 2
img.drawCentreString("Font size 4", 80, 30, 4); // Draw text centre at position 80, 24 using font 4
img.drawCentreString("12.34", 80, 54, 6); // Draw text centre at position 80, 24 using font 6
img.drawCentreString("12.34 is in font size 6", 80, 92, 2); // Draw text centre at position 80, 90 using font 2
// Note the x position is the top left of the font!
// draw a floating point number
float pi = 3.14159; // Value to print
int precision = 3; // Number of digits after decimal point
int xpos = 50; // x position
int ypos = 110; // y position
int font = 2; // font number only 2,4,6,7 valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 0 : a p m
xpos += img.drawFloat(pi, precision, xpos, ypos, font); // Draw rounded number and return new xpos delta for next print position
img.drawString(" is pi", xpos, ypos, font); // Continue printing from new x position
tft.pushSprite(0, 0, IWIDTH, IHEIGHT, imgPtr);
}
}

View File

@@ -0,0 +1,134 @@
/*
Sketch to show how a Sprite is created, how to draw pixels
and text within the Sprite and then split the Sprite onto
the display screen.
Example for library:
https://github.com/Bodmer/TFT_eSPI
A Sprite is notionally an invisibly 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.
The Sprite occupies (2 * width * height) bytes in RAM.
On a ESP8266 Sprite sizes up to 126 x 160 can be accomodated,
this size requires 40kBytes of RAM.
*/
// Set delay after plotting the sprite
#define DELAY 1000
// Width and height of sprite
#define WIDTH 128
#define HEIGHT 128
#include <TFT_eSPI.h> // Include the graphics library (this includes the sprite functions)
TFT_eSPI tft = TFT_eSPI(); // Declare object "tft"
TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object
void setup()
{
Serial.begin(250000);
Serial.println();
// Initialise the TFT registers
tft.init();
// Create a sprite of defined size
spr.createSprite(WIDTH, HEIGHT);
// Clear the TFT screen to blue
tft.fillScreen(TFT_BLUE);
}
void loop(void)
{
// Fill the whole sprite with black (Sprite is in memory so not visible yet)
spr.fillSprite(TFT_BLACK);
// Number of pixels to draw
uint16_t n = 100;
// Draw 100 random colour pixels at random positions in sprite
while (n--)
{
uint16_t colour = random(0x10000); // Returns colour 0 - 0xFFFF
int16_t x = random(WIDTH); // Random x coordinate
int16_t y = random(HEIGHT); // Random y coordinate
spr.drawPixel( x, y, colour); // Draw pixel in sprite
}
// Draw some lines
spr.drawLine(1, 0, WIDTH, HEIGHT-1, TFT_GREEN);
spr.drawLine(0, 0, WIDTH, HEIGHT, TFT_GREEN);
spr.drawLine(0, 1, WIDTH-1, HEIGHT, TFT_GREEN);
spr.drawLine(0, HEIGHT-1, WIDTH-1, 0, TFT_RED);
spr.drawLine(0, HEIGHT, WIDTH, 0, TFT_RED);
spr.drawLine(1, HEIGHT, WIDTH, 1, TFT_RED);
// Draw some text with Middle Centre datum
spr.setTextDatum(MC_DATUM);
spr.drawString("Sprite", WIDTH / 2, HEIGHT / 2, 4);
// Now push the sprite to the TFT at position 0,0 on screen
spr.pushSprite(-40, -40);
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2);
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
delay(DELAY);
// Fill TFT screen with blue
tft.fillScreen(TFT_BLUE);
// Draw a blue rectangle in sprite so when we move it 1 pixel it does not leave a trail
// on the blue screen background
spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_BLUE);
int x = tft.width() / 2 - WIDTH / 2;
int y = tft.height() / 2 - HEIGHT / 2;
uint32_t updateTime = 0; // time for next update
while (true)
{
// Random movement direction
int dx = 1; if (random(2)) dx = -1;
int dy = 1; if (random(2)) dy = -1;
// Pull it back onto screen if it wanders off
if (x < -WIDTH/2) dx = 1;
if (x >= tft.width()-WIDTH/2) dx = -1;
if (y < -HEIGHT/2) dy = 1;
if (y >= tft.height()-HEIGHT/2) dy = -1;
// Draw it 50 time, moving in random direct or staying still
n = 50;
int wait = random (50);
while (n)
{
if (updateTime <= millis())
{
// Use time delay so sprtie does not move fast when not all on screen
updateTime = millis() + wait;
// Push the sprite to the TFT screen
spr.pushSprite(x, y);
// Change coord for next loop
x += dx;
y += dy;
n--;
yield(); // Stop watchdog reset
}
}
} // Infinite while, will not exit!
}

View File

@@ -0,0 +1,194 @@
/*
Display "flicker free" scrolling text and updating number
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 invisibly 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.
The Sprite occupies (2 * width * height) bytes.
On a ESP8266 Sprite sizes up to 128 x 160 can be accomodated,
this size requires 128*160*2 bytes (40kBytes) of RAM, this must be
available or the processor will crash. 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 15/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 <TFT_eSPI.h> // 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)
{
// 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;
}