TFT_eSPI/TFT_eSPI.cpp

6159 lines
191 KiB
C++
Raw Normal View History

/***************************************************
2023-12-07 20:35:59 +00:00
Arduino TFT graphics library targeted at 32-bit
processors such as ESP32, ESP8266 and STM32.
This is a stand-alone library that contains the
2018-02-22 22:33:49 +00:00
hardware driver, the graphics functions and the
proportional fonts.
The larger fonts are Run Length Encoded to reduce their
size.
Created by Bodmer 2/12/16
Last update by Bodmer 20/03/20
****************************************************/
#include "TFT_eSPI.h"
#if defined (ESP32)
2022-04-22 01:44:10 +00:00
#if defined(CONFIG_IDF_TARGET_ESP32S3)
2023-12-07 20:35:59 +00:00
#include "Processors/TFT_eSPI_ESP32_S3.c" // Tested with SPI and 8-bit parallel
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
2023-12-07 20:35:59 +00:00
#include "Processors/TFT_eSPI_ESP32_C3.c" // Tested with SPI (8-bit parallel will probably work too!)
2022-04-22 01:44:10 +00:00
#else
#include "Processors/TFT_eSPI_ESP32.c"
#endif
#elif defined (ARDUINO_ARCH_ESP8266)
#include "Processors/TFT_eSPI_ESP8266.c"
#elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h
#include "Processors/TFT_eSPI_STM32.c"
#elif defined (ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED) // Raspberry Pi Pico
#include "Processors/TFT_eSPI_RP2040.c"
#else
#include "Processors/TFT_eSPI_Generic.c"
#endif
#ifndef SPI_BUSY_CHECK
#define SPI_BUSY_CHECK
#endif
2020-10-11 21:36:02 +00:00
// Clipping macro for pushImage
#define PI_CLIP \
if (_vpOoB) return; \
x+= _xDatum; \
y+= _yDatum; \
\
if ((x >= _vpW) || (y >= _vpH)) return; \
\
int32_t dx = 0; \
int32_t dy = 0; \
int32_t dw = w; \
int32_t dh = h; \
\
if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } \
if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } \
\
if ((x + dw) > _vpW ) dw = _vpW - x; \
if ((y + dh) > _vpH ) dh = _vpH - y; \
\
if (dw < 1 || dh < 1) return;
/***************************************************************************************
** Function name: Legacy - deprecated
** Description: Start/end transaction
***************************************************************************************/
void TFT_eSPI::spi_begin() {begin_tft_write();}
void TFT_eSPI::spi_end() { end_tft_write();}
void TFT_eSPI::spi_begin_read() {begin_tft_read(); }
void TFT_eSPI::spi_end_read() { end_tft_read(); }
/***************************************************************************************
** Function name: begin_tft_write (was called spi_begin)
** Description: Start SPI transaction for writes and select TFT
***************************************************************************************/
inline void TFT_eSPI::begin_tft_write(void){
if (locked) {
locked = false; // Flag to show SPI access now unlocked
2022-01-08 20:01:42 +00:00
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE));
2022-01-08 20:01:42 +00:00
#endif
CS_L;
SET_BUS_WRITE_MODE; // Some processors (e.g. ESP32) allow recycling the tx buffer when rx is not used
}
}
// Non-inlined version to permit override
void TFT_eSPI::begin_nin_write(void){
if (locked) {
locked = false; // Flag to show SPI access now unlocked
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE));
#endif
CS_L;
SET_BUS_WRITE_MODE; // Some processors (e.g. ESP32) allow recycling the tx buffer when rx is not used
}
}
/***************************************************************************************
** Function name: end_tft_write (was called spi_end)
** Description: End transaction for write and deselect TFT
***************************************************************************************/
inline void TFT_eSPI::end_tft_write(void){
if(!inTransaction) { // Flag to stop ending transaction during multiple graphics calls
if (!locked) { // Locked when beginTransaction has been called
locked = true; // Flag to show SPI access now locked
SPI_BUSY_CHECK; // Check send complete and clean out unused rx data
CS_H;
2022-03-04 00:59:38 +00:00
SET_BUS_READ_MODE; // In case bus has been configured for tx only
2022-01-08 20:01:42 +00:00
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
spi.endTransaction();
2022-01-08 20:01:42 +00:00
#endif
}
}
}
// Non-inlined version to permit override
inline void TFT_eSPI::end_nin_write(void){
if(!inTransaction) { // Flag to stop ending transaction during multiple graphics calls
if (!locked) { // Locked when beginTransaction has been called
locked = true; // Flag to show SPI access now locked
SPI_BUSY_CHECK; // Check send complete and clean out unused rx data
CS_H;
2022-03-04 00:59:38 +00:00
SET_BUS_READ_MODE; // In case SPI has been configured for tx only
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
spi.endTransaction();
#endif
}
}
}
/***************************************************************************************
** Function name: begin_tft_read (was called spi_begin_read)
** Description: Start transaction for reads and select TFT
***************************************************************************************/
// Reads require a lower SPI clock rate than writes
inline void TFT_eSPI::begin_tft_read(void){
DMA_BUSY_CHECK; // Wait for any DMA transfer to complete before changing SPI settings
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
if (locked) {
locked = false;
spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE));
CS_L;
}
#else
#if !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
spi.setFrequency(SPI_READ_FREQUENCY);
#endif
CS_L;
#endif
SET_BUS_READ_MODE;
}
/***************************************************************************************
** Function name: end_tft_read (was called spi_end_read)
** Description: End transaction for reads and deselect TFT
***************************************************************************************/
inline void TFT_eSPI::end_tft_read(void){
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
if(!inTransaction) {
if (!locked) {
locked = true;
CS_H;
spi.endTransaction();
}
}
#else
#if !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
spi.setFrequency(SPI_FREQUENCY);
#endif
if(!inTransaction) {CS_H;}
#endif
SET_BUS_WRITE_MODE;
}
/***************************************************************************************
** Function name: setViewport
** Description: Set the clipping region for the TFT screen
***************************************************************************************/
void TFT_eSPI::setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum)
{
// Viewport metrics (not clipped)
2020-10-11 21:36:02 +00:00
_xDatum = x; // Datum x position in screen coordinates
_yDatum = y; // Datum y position in screen coordinates
_xWidth = w; // Viewport width
_yHeight = h; // Viewport height
// Full size default viewport
2020-10-11 21:36:02 +00:00
_vpDatum = false; // Datum is at top left corner of screen (true = top left of viewport)
_vpOoB = false; // Out of Bounds flag (true is all of viewport is off screen)
_vpX = 0; // Viewport top left corner x coordinate
_vpY = 0; // Viewport top left corner y coordinate
_vpW = width(); // Equivalent of TFT width (Nb: viewport right edge coord + 1)
_vpH = height(); // Equivalent of TFT height (Nb: viewport bottom edge coord + 1)
2020-10-11 21:36:02 +00:00
// Clip viewport to screen area
if (x<0) { w += x; x = 0; }
if (y<0) { h += y; y = 0; }
if ((x + w) > width() ) { w = width() - x; }
if ((y + h) > height() ) { h = height() - y; }
2020-10-11 21:36:02 +00:00
//Serial.print(" x=");Serial.print( x);Serial.print(", y=");Serial.print( y);
//Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h);
2020-10-11 21:36:02 +00:00
// Check if viewport is entirely out of bounds
if (w < 1 || h < 1)
{
2020-10-11 21:36:02 +00:00
// Set default values and Out of Bounds flag in case of error
_xDatum = 0;
_yDatum = 0;
_xWidth = width();
_yHeight = height();
2020-10-11 21:36:02 +00:00
_vpOoB = true; // Set Out of Bounds flag to inhibit all drawing
return;
}
2020-10-11 21:36:02 +00:00
if (!vpDatum)
{
_xDatum = 0; // Reset to top left of screen if not using a viewport datum
_yDatum = 0;
_xWidth = width();
_yHeight = height();
}
// Store the clipped screen viewport metrics and datum position
2020-10-11 21:36:02 +00:00
_vpX = x;
_vpY = y;
_vpW = x + w;
_vpH = y + h;
_vpDatum = vpDatum;
2020-10-11 21:36:02 +00:00
//Serial.print(" _xDatum=");Serial.print( _xDatum);Serial.print(", _yDatum=");Serial.print( _yDatum);
//Serial.print(", _xWidth=");Serial.print(_xWidth);Serial.print(", _yHeight=");Serial.println(_yHeight);
//Serial.print(" _vpX=");Serial.print( _vpX);Serial.print(", _vpY=");Serial.print( _vpY);
//Serial.print(", _vpW=");Serial.print(_vpW);Serial.print(", _vpH=");Serial.println(_vpH);
}
2020-10-13 12:35:03 +00:00
/***************************************************************************************
** Function name: checkViewport
** Description: Check if any part of specified area is visible in viewport
***************************************************************************************/
// Note: Setting w and h to 1 will check if coordinate x,y is in area
bool TFT_eSPI::checkViewport(int32_t x, int32_t y, int32_t w, int32_t h)
{
if (_vpOoB) return false;
x+= _xDatum;
y+= _yDatum;
if ((x >= _vpW) || (y >= _vpH)) return false;
2020-10-13 12:35:03 +00:00
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; }
if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; }
if ((x + dw) > _vpW ) dw = _vpW - x;
if ((y + dh) > _vpH ) dh = _vpH - y;
if (dw < 1 || dh < 1) return false;
return true;
}
/***************************************************************************************
** Function name: resetViewport
** Description: Reset viewport to whole TFT screen, datum at 0,0
***************************************************************************************/
void TFT_eSPI::resetViewport(void)
{
// Reset viewport to the whole screen (or sprite) area
_vpDatum = false;
_vpOoB = false;
_xDatum = 0;
_yDatum = 0;
_vpX = 0;
_vpY = 0;
_vpW = width();
_vpH = height();
_xWidth = width();
_yHeight = height();
}
2020-10-13 12:35:03 +00:00
/***************************************************************************************
** Function name: getViewportX
** Description: Get x position of the viewport datum
2020-10-13 12:35:03 +00:00
***************************************************************************************/
int32_t TFT_eSPI::getViewportX(void)
{
return _xDatum;
}
/***************************************************************************************
** Function name: getViewportY
** Description: Get y position of the viewport datum
2020-10-13 12:35:03 +00:00
***************************************************************************************/
int32_t TFT_eSPI::getViewportY(void)
{
return _yDatum;
}
/***************************************************************************************
** Function name: getViewportWidth
** Description: Get width of the viewport
***************************************************************************************/
int32_t TFT_eSPI::getViewportWidth(void)
{
return _xWidth;
}
/***************************************************************************************
** Function name: getViewportHeight
** Description: Get height of the viewport
***************************************************************************************/
int32_t TFT_eSPI::getViewportHeight(void)
{
return _yHeight;
}
2020-10-13 12:35:03 +00:00
/***************************************************************************************
** Function name: getViewportDatum
** Description: Get datum flag of the viewport (true = viewport corner)
2020-10-13 12:35:03 +00:00
***************************************************************************************/
bool TFT_eSPI::getViewportDatum(void)
{
return _vpDatum;
}
/***************************************************************************************
** Function name: frameViewport
** Description: Draw a frame inside or outside the viewport of width w
***************************************************************************************/
void TFT_eSPI::frameViewport(uint16_t color, int32_t w)
{
// Save datum position
bool _dT = _vpDatum;
// If w is positive the frame is drawn inside the viewport
// a large positive width will clear the screen inside the viewport
if (w>0)
{
// Set vpDatum true to simplify coordinate derivation
_vpDatum = true;
fillRect(0, 0, _vpW - _vpX, w, color); // Top
fillRect(0, w, w, _vpH - _vpY - w - w, color); // Left
fillRect(_xWidth - w, w, w, _yHeight - w - w, color); // Right
fillRect(0, _yHeight - w, _xWidth, w, color); // Bottom
}
else
// If w is negative the frame is drawn outside the viewport
// a large negative width will clear the screen outside the viewport
{
w = -w;
// Save old values
int32_t _xT = _vpX; _vpX = 0;
int32_t _yT = _vpY; _vpY = 0;
int32_t _wT = _vpW;
int32_t _hT = _vpH;
// Set vpDatum false so frame can be drawn outside window
_vpDatum = false; // When false the full width and height is accessed
_vpH = height();
_vpW = width();
// Draw frame
fillRect(_xT - w - _xDatum, _yT - w - _yDatum, _wT - _xT + w + w, w, color); // Top
fillRect(_xT - w - _xDatum, _yT - _yDatum, w, _hT - _yT, color); // Left
fillRect(_wT - _xDatum, _yT - _yDatum, w, _hT - _yT, color); // Right
fillRect(_xT - w - _xDatum, _hT - _yDatum, _wT - _xT + w + w, w, color); // Bottom
// Restore old values
_vpX = _xT;
_vpY = _yT;
_vpW = _wT;
_vpH = _hT;
}
// Restore vpDatum
_vpDatum = _dT;
}
/***************************************************************************************
** Function name: clipAddrWindow
** Description: Clip address window x,y,w,h to screen and viewport
***************************************************************************************/
bool TFT_eSPI::clipAddrWindow(int32_t *x, int32_t *y, int32_t *w, int32_t *h)
{
if (_vpOoB) return false; // Area is outside of viewport
*x+= _xDatum;
*y+= _yDatum;
if ((*x >= _vpW) || (*y >= _vpH)) return false; // Area is outside of viewport
// Crop drawing area bounds
if (*x < _vpX) { *w -= _vpX - *x; *x = _vpX; }
if (*y < _vpY) { *h -= _vpY - *y; *y = _vpY; }
if ((*x + *w) > _vpW ) *w = _vpW - *x;
if ((*y + *h) > _vpH ) *h = _vpH - *y;
if (*w < 1 || *h < 1) return false; // No area is inside viewport
return true; // Area is wholly or partially inside viewport
}
/***************************************************************************************
** Function name: clipWindow
** Description: Clip window xs,yx,xe,ye to screen and viewport
***************************************************************************************/
bool TFT_eSPI::clipWindow(int32_t *xs, int32_t *ys, int32_t *xe, int32_t *ye)
{
if (_vpOoB) return false; // Area is outside of viewport
*xs+= _xDatum;
*ys+= _yDatum;
*xe+= _xDatum;
*ye+= _yDatum;
if ((*xs >= _vpW) || (*ys >= _vpH)) return false; // Area is outside of viewport
if ((*xe < _vpX) || (*ye < _vpY)) return false; // Area is outside of viewport
// Crop drawing area bounds
if (*xs < _vpX) *xs = _vpX;
if (*ys < _vpY) *ys = _vpY;
if (*xe > _vpW) *xe = _vpW - 1;
if (*ye > _vpH) *ye = _vpH - 1;
return true; // Area is wholly or partially inside viewport
}
/***************************************************************************************
** Function name: TFT_eSPI
** Description: Constructor , we must use hardware SPI pins
***************************************************************************************/
TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
{
2018-02-24 19:02:20 +00:00
_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
2020-10-11 21:36:02 +00:00
// Reset the viewport to the whole screen
resetViewport();
rotation = 0;
cursor_y = cursor_x = last_cursor_x = bg_cursor_x = 0;
textfont = 1;
textsize = 1;
textcolor = bitmap_fg = 0xFFFF; // White
textbgcolor = bitmap_bg = 0x0000; // Black
padX = 0; // No padding
_fillbg = false; // Smooth font only at the moment, force text background fill
isDigits = false; // No bounding box adjustment
2018-02-24 19:02:20 +00:00
textwrapX = true; // Wrap text at end of line when using print stream
textwrapY = false; // Wrap text at bottom of screen when using print stream
textdatum = TL_DATUM; // Top Left text alignment is default
fontsloaded = 0;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
_swapBytes = false; // Do not swap colour bytes by default
locked = true; // Transaction mutex lock flag to ensure begin/endTranaction pairing
inTransaction = false; // Flag to prevent multiple sequential functions to keep bus access open
lockTransaction = false; // start/endWrite lock flag to allow sketch to keep SPI bus access open
_booted = true; // Default attributes
_cp437 = false; // Legacy GLCD font bug fix disabled by default
_utf8 = true; // UTF8 decoding enabled
#if defined (FONT_FS_AVAILABLE) && defined (SMOOTH_FONT)
fs_font = true; // Smooth font filing system or array (fs_font = false) flag
#endif
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
if (psramFound()) _psram_enable = true; // Enable the use of PSRAM (if available)
else
#endif
_psram_enable = false;
addr_row = 0xFFFF; // drawPixel command length optimiser
addr_col = 0xFFFF; // drawPixel command length optimiser
_xPivot = 0;
_yPivot = 0;
// Legacy support for bit GPIO masks
cspinmask = 0;
dcpinmask = 0;
wrpinmask = 0;
sclkpinmask = 0;
// Flags for which fonts are loaded
#ifdef LOAD_GLCD
fontsloaded = 0x0002; // Bit 1 set
#endif
#ifdef LOAD_FONT2
fontsloaded |= 0x0004; // Bit 2 set
#endif
#ifdef LOAD_FONT4
fontsloaded |= 0x0010; // Bit 4 set
#endif
#ifdef LOAD_FONT6
fontsloaded |= 0x0040; // Bit 6 set
#endif
#ifdef LOAD_FONT7
fontsloaded |= 0x0080; // Bit 7 set
#endif
#ifdef LOAD_FONT8
fontsloaded |= 0x0100; // Bit 8 set
#endif
#ifdef LOAD_FONT8N
fontsloaded |= 0x0200; // Bit 9 set
#endif
#ifdef SMOOTH_FONT
fontsloaded |= 0x8000; // Bit 15 set
#endif
}
/***************************************************************************************
** Function name: initBus
** Description: initialise the SPI or parallel bus
***************************************************************************************/
void TFT_eSPI::initBus(void) {
#ifdef TFT_CS
if (TFT_CS >= 0) {
pinMode(TFT_CS, OUTPUT);
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
}
#endif
// Configure chip select for touchscreen controller if present
#ifdef TOUCH_CS
if (TOUCH_CS >= 0) {
pinMode(TOUCH_CS, OUTPUT);
digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive)
}
#endif
// In parallel mode and with the RP2040 processor, the TFT_WR line is handled in the PIO
#if defined (TFT_WR) && !defined (ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
if (TFT_WR >= 0) {
pinMode(TFT_WR, OUTPUT);
digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive)
}
#endif
#ifdef TFT_DC
if (TFT_DC >= 0) {
pinMode(TFT_DC, OUTPUT);
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
}
#endif
#ifdef TFT_RST
if (TFT_RST >= 0) {
pinMode(TFT_RST, OUTPUT);
digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device
}
#endif
#if defined (TFT_PARALLEL_8_BIT)
// Make sure read is high before we set the bus to output
if (TFT_RD >= 0) {
pinMode(TFT_RD, OUTPUT);
digitalWrite(TFT_RD, HIGH);
}
#if !defined (ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)// PIO manages pins
// Set TFT data bus lines to output
pinMode(TFT_D0, OUTPUT); digitalWrite(TFT_D0, HIGH);
pinMode(TFT_D1, OUTPUT); digitalWrite(TFT_D1, HIGH);
pinMode(TFT_D2, OUTPUT); digitalWrite(TFT_D2, HIGH);
pinMode(TFT_D3, OUTPUT); digitalWrite(TFT_D3, HIGH);
pinMode(TFT_D4, OUTPUT); digitalWrite(TFT_D4, HIGH);
pinMode(TFT_D5, OUTPUT); digitalWrite(TFT_D5, HIGH);
pinMode(TFT_D6, OUTPUT); digitalWrite(TFT_D6, HIGH);
pinMode(TFT_D7, OUTPUT); digitalWrite(TFT_D7, HIGH);
#endif
PARALLEL_INIT_TFT_DATA_BUS;
#endif
}
/***************************************************************************************
** Function name: begin
** Description: Included for backwards compatibility
***************************************************************************************/
void TFT_eSPI::begin(uint8_t tc)
{
init(tc);
}
/***************************************************************************************
** Function name: init (tc is tab colour for ST7735 displays only)
** Description: Reset, then initialise the TFT display registers
***************************************************************************************/
void TFT_eSPI::init(uint8_t tc)
{
if (_booted)
{
initBus();
#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) && !defined(ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
// Legacy bitmasks for GPIO
#if defined (TFT_CS) && (TFT_CS >= 0)
cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS);
#endif
#if defined (TFT_DC) && (TFT_DC >= 0)
dcpinmask = (uint32_t) digitalPinToBitMask(TFT_DC);
#endif
2020-01-25 06:07:45 +00:00
#if defined (TFT_WR) && (TFT_WR >= 0)
wrpinmask = (uint32_t) digitalPinToBitMask(TFT_WR);
#endif
2020-01-25 06:07:45 +00:00
#if defined (TFT_SCLK) && (TFT_SCLK >= 0)
sclkpinmask = (uint32_t) digitalPinToBitMask(TFT_SCLK);
#endif
2020-01-25 06:07:45 +00:00
#if defined (TFT_SPI_OVERLAP) && defined (ARDUINO_ARCH_ESP8266)
// Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS
// pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss);
//spi.pins( 6, 7, 8, 0);
spi.pins(6, 7, 8, 0);
#endif
spi.begin(); // This will set HMISO to input
#else
#if !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
#if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) && !defined(ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
2022-01-26 21:30:52 +00:00
spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); // This will set MISO to input
#else
2022-01-26 21:30:52 +00:00
spi.begin(); // This will set MISO to input
#endif
#endif
#endif
lockTransaction = false;
inTransaction = false;
locked = true;
INIT_TFT_DATA_BUS;
2022-01-26 22:47:18 +00:00
#if defined (TFT_CS) && !defined(RP2040_PIO_INTERFACE)
2022-01-26 21:30:52 +00:00
// Set to output once again in case MISO is used for CS
if (TFT_CS >= 0) {
pinMode(TFT_CS, OUTPUT);
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
}
#elif defined (ARDUINO_ARCH_ESP8266) && !defined (TFT_PARALLEL_8_BIT) && !defined (RP2040_PIO_SPI)
spi.setHwCs(1); // Use hardware SS toggling
#endif
2022-01-26 21:30:52 +00:00
// Set to output once again in case MISO is used for DC
2022-01-26 22:47:18 +00:00
#if defined (TFT_DC) && !defined(RP2040_PIO_INTERFACE)
if (TFT_DC >= 0) {
pinMode(TFT_DC, OUTPUT);
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
}
#endif
_booted = false;
end_tft_write();
} // end of: if just _booted
// Toggle RST low to reset
#ifdef TFT_RST
2022-01-26 22:47:18 +00:00
#if !defined(RP2040_PIO_INTERFACE)
// Set to output once again in case MISO is used for TFT_RST
if (TFT_RST >= 0) {
pinMode(TFT_RST, OUTPUT);
}
2022-01-26 22:47:18 +00:00
#endif
if (TFT_RST >= 0) {
2022-07-19 11:29:41 +00:00
writecommand(0x00); // Put SPI bus in known state for TFT with CS tied low
digitalWrite(TFT_RST, HIGH);
delay(5);
digitalWrite(TFT_RST, LOW);
delay(20);
digitalWrite(TFT_RST, HIGH);
}
else writecommand(TFT_SWRST); // Software reset
#else
writecommand(TFT_SWRST); // Software reset
2018-02-24 19:02:20 +00:00
#endif
delay(150); // Wait for reset to complete
begin_tft_write();
2020-01-25 06:07:45 +00:00
tc = tc; // Suppress warning
// This loads the driver specific initialisation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
#if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9342_DRIVER)
#include "TFT_Drivers/ILI9341_Init.h"
#elif defined (ST7735_DRIVER)
tabcolor = tc;
#include "TFT_Drivers/ST7735_Init.h"
2017-02-26 03:03:41 +00:00
#elif defined (ILI9163_DRIVER)
#include "TFT_Drivers/ILI9163_Init.h"
2017-02-26 03:03:41 +00:00
#elif defined (S6D02A1_DRIVER)
#include "TFT_Drivers/S6D02A1_Init.h"
#elif defined (ST7796_DRIVER)
#include "TFT_Drivers/ST7796_Init.h"
#elif defined (ILI9486_DRIVER)
#include "TFT_Drivers/ILI9486_Init.h"
#elif defined (ILI9481_DRIVER)
#include "TFT_Drivers/ILI9481_Init.h"
#elif defined (ILI9488_DRIVER)
#include "TFT_Drivers/ILI9488_Init.h"
#elif defined (HX8357D_DRIVER)
#include "TFT_Drivers/HX8357D_Init.h"
#elif defined (ST7789_DRIVER)
#include "TFT_Drivers/ST7789_Init.h"
#elif defined (R61581_DRIVER)
#include "TFT_Drivers/R61581_Init.h"
#elif defined (RM68140_DRIVER)
#include "TFT_Drivers/RM68140_Init.h"
#elif defined (ST7789_2_DRIVER)
#include "TFT_Drivers/ST7789_2_Init.h"
#elif defined (SSD1351_DRIVER)
#include "TFT_Drivers/SSD1351_Init.h"
#elif defined (SSD1963_DRIVER)
#include "TFT_Drivers/SSD1963_Init.h"
#elif defined (GC9A01_DRIVER)
#include "TFT_Drivers/GC9A01_Init.h"
2020-11-25 23:18:54 +00:00
#elif defined (ILI9225_DRIVER)
#include "TFT_Drivers/ILI9225_Init.h"
#elif defined (RM68120_DRIVER)
#include "TFT_Drivers/RM68120_Init.h"
2022-04-22 01:44:10 +00:00
#elif defined (HX8357B_DRIVER)
#include "TFT_Drivers/HX8357B_Init.h"
#elif defined (HX8357C_DRIVER)
#include "TFT_Drivers/HX8357C_Init.h"
#endif
#ifdef TFT_INVERSION_ON
writecommand(TFT_INVON);
#endif
#ifdef TFT_INVERSION_OFF
writecommand(TFT_INVOFF);
#endif
end_tft_write();
setRotation(rotation);
#if defined (TFT_BL) && defined (TFT_BACKLIGHT_ON)
if (TFT_BL >= 0) {
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
}
#else
#if defined (TFT_BL) && defined (M5STACK)
// Turn on the back-light LED
if (TFT_BL >= 0) {
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
}
#endif
#endif
}
/***************************************************************************************
** Function name: setRotation
** Description: rotate the screen orientation m = 0-3 or 4-7 for BMP drawing
***************************************************************************************/
void TFT_eSPI::setRotation(uint8_t m)
{
begin_tft_write();
// This loads the driver specific rotation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
#if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9342_DRIVER)
#include "TFT_Drivers/ILI9341_Rotation.h"
#elif defined (ST7735_DRIVER)
#include "TFT_Drivers/ST7735_Rotation.h"
2017-02-26 03:03:41 +00:00
#elif defined (ILI9163_DRIVER)
#include "TFT_Drivers/ILI9163_Rotation.h"
2017-02-26 03:03:41 +00:00
#elif defined (S6D02A1_DRIVER)
#include "TFT_Drivers/S6D02A1_Rotation.h"
2017-02-26 03:03:41 +00:00
#elif defined (ST7796_DRIVER)
#include "TFT_Drivers/ST7796_Rotation.h"
#elif defined (ILI9486_DRIVER)
#include "TFT_Drivers/ILI9486_Rotation.h"
#elif defined (ILI9481_DRIVER)
#include "TFT_Drivers/ILI9481_Rotation.h"
#elif defined (ILI9488_DRIVER)
#include "TFT_Drivers/ILI9488_Rotation.h"
#elif defined (HX8357D_DRIVER)
#include "TFT_Drivers/HX8357D_Rotation.h"
#elif defined (ST7789_DRIVER)
#include "TFT_Drivers/ST7789_Rotation.h"
#elif defined (R61581_DRIVER)
#include "TFT_Drivers/R61581_Rotation.h"
#elif defined (RM68140_DRIVER)
#include "TFT_Drivers/RM68140_Rotation.h"
#elif defined (ST7789_2_DRIVER)
#include "TFT_Drivers/ST7789_2_Rotation.h"
#elif defined (SSD1351_DRIVER)
#include "TFT_Drivers/SSD1351_Rotation.h"
#elif defined (SSD1963_DRIVER)
#include "TFT_Drivers/SSD1963_Rotation.h"
#elif defined (GC9A01_DRIVER)
#include "TFT_Drivers/GC9A01_Rotation.h"
2020-11-25 23:18:54 +00:00
#elif defined (ILI9225_DRIVER)
#include "TFT_Drivers/ILI9225_Rotation.h"
#elif defined (RM68120_DRIVER)
#include "TFT_Drivers/RM68120_Rotation.h"
2022-04-22 01:44:10 +00:00
#elif defined (HX8357B_DRIVER)
#include "TFT_Drivers/HX8357B_Rotation.h"
#elif defined (HX8357C_DRIVER)
#include "TFT_Drivers/HX8357C_Rotation.h"
#endif
delayMicroseconds(10);
end_tft_write();
addr_row = 0xFFFF;
addr_col = 0xFFFF;
2020-10-11 21:36:02 +00:00
// Reset the viewport to the whole screen
resetViewport();
}
/***************************************************************************************
** Function name: getRotation
** Description: Return the rotation value (as used by setRotation())
***************************************************************************************/
uint8_t TFT_eSPI::getRotation(void)
{
return rotation;
}
/***************************************************************************************
** Function name: setOrigin
** Description: Set graphics origin to position x,y wrt to top left corner
***************************************************************************************/
//Note: setRotation, setViewport and resetViewport will revert origin to top left
void TFT_eSPI::setOrigin(int32_t x, int32_t y)
{
_xDatum = x;
_yDatum = y;
}
/***************************************************************************************
** Function name: getOriginX
** Description: Set graphics origin to position x
***************************************************************************************/
int32_t TFT_eSPI::getOriginX(void)
{
return _xDatum;
}
/***************************************************************************************
** Function name: getOriginY
** Description: Set graphics origin to position y
***************************************************************************************/
int32_t TFT_eSPI::getOriginY(void)
{
return _yDatum;
}
/***************************************************************************************
** Function name: commandList, used for FLASH based lists only (e.g. ST7735)
** Description: Get initialisation commands from FLASH and send to TFT
***************************************************************************************/
void TFT_eSPI::commandList (const uint8_t *addr)
{
uint8_t numCommands;
uint8_t numArgs;
uint8_t ms;
numCommands = pgm_read_byte(addr++); // Number of commands to follow
while (numCommands--) // For each command...
{
writecommand(pgm_read_byte(addr++)); // Read, issue command
numArgs = pgm_read_byte(addr++); // Number of args to follow
2023-12-07 20:35:59 +00:00
ms = numArgs & TFT_INIT_DELAY; // If high bit set, delay follows args
numArgs &= ~TFT_INIT_DELAY; // Mask out delay bit
while (numArgs--) // For each argument...
{
writedata(pgm_read_byte(addr++)); // Read, issue argument
}
if (ms)
{
ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
delay( (ms==255 ? 500 : ms) );
}
}
}
/***************************************************************************************
** Function name: spiwrite
** Description: Write 8 bits to SPI port (legacy support only)
***************************************************************************************/
void TFT_eSPI::spiwrite(uint8_t c)
{
2020-05-01 19:57:03 +00:00
begin_tft_write();
tft_Write_8(c);
2020-05-01 19:57:03 +00:00
end_tft_write();
}
/***************************************************************************************
** Function name: writecommand
2023-12-07 20:35:59 +00:00
** Description: Send an 8-bit command to the TFT
***************************************************************************************/
#ifndef RM68120_DRIVER
void TFT_eSPI::writecommand(uint8_t c)
{
begin_tft_write();
DC_C;
tft_Write_8(c);
DC_D;
end_tft_write();
}
#else
void TFT_eSPI::writecommand(uint16_t c)
{
begin_tft_write();
DC_C;
tft_Write_16(c);
DC_D;
end_tft_write();
}
void TFT_eSPI::writeRegister8(uint16_t c, uint8_t d)
{
begin_tft_write();
DC_C;
tft_Write_16(c);
DC_D;
tft_Write_8(d);
end_tft_write();
}
void TFT_eSPI::writeRegister16(uint16_t c, uint16_t d)
{
begin_tft_write();
DC_C;
tft_Write_16(c);
DC_D;
tft_Write_16(d);
end_tft_write();
}
#endif
/***************************************************************************************
** Function name: writedata
2023-12-07 20:35:59 +00:00
** Description: Send a 8-bit data value to the TFT
***************************************************************************************/
void TFT_eSPI::writedata(uint8_t d)
{
begin_tft_write();
DC_D; // Play safe, but should already be in data mode
tft_Write_8(d);
CS_L; // Allow more hold time for low VDI rail
end_tft_write();
}
/***************************************************************************************
** Function name: readcommand8
2023-12-07 20:35:59 +00:00
** Description: Read a 8-bit data value from an indexed command register
***************************************************************************************/
uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
{
uint8_t reg = 0;
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
2020-01-25 06:07:45 +00:00
writecommand(cmd_function); // Sets DC and CS high
busDir(GPIO_DIR_MASK, INPUT);
CS_L;
// Read nth parameter (assumes caller discards 1st parameter or points index to 2nd)
while(index--) reg = readByte();
busDir(GPIO_DIR_MASK, OUTPUT);
CS_H;
#else // SPI interface
// Tested with ILI9341 set to Interface II i.e. IM [3:0] = "1101"
begin_tft_read();
index = 0x10 + (index & 0x0F);
DC_C; tft_Write_8(0xD9);
DC_D; tft_Write_8(index);
CS_H; // Some displays seem to need CS to be pulsed here, or is just a delay needed?
CS_L;
DC_C; tft_Write_8(cmd_function);
DC_D;
reg = tft_Read_8();
end_tft_read();
#endif
return reg;
}
/***************************************************************************************
** Function name: readcommand16
2023-12-07 20:35:59 +00:00
** Description: Read a 16-bit data value from an indexed command register
***************************************************************************************/
uint16_t TFT_eSPI::readcommand16(uint8_t cmd_function, uint8_t index)
{
uint32_t reg;
reg = (readcommand8(cmd_function, index + 0) << 8);
reg |= (readcommand8(cmd_function, index + 1) << 0);
return reg;
}
/***************************************************************************************
** Function name: readcommand32
2023-12-07 20:35:59 +00:00
** Description: Read a 32-bit data value from an indexed command register
***************************************************************************************/
uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index)
{
uint32_t reg;
reg = ((uint32_t)readcommand8(cmd_function, index + 0) << 24);
reg |= ((uint32_t)readcommand8(cmd_function, index + 1) << 16);
reg |= ((uint32_t)readcommand8(cmd_function, index + 2) << 8);
reg |= ((uint32_t)readcommand8(cmd_function, index + 3) << 0);
return reg;
}
/***************************************************************************************
** Function name: read pixel (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read 565 pixel colours from a pixel
***************************************************************************************/
uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB) return 0;
x0+= _xDatum;
y0+= _yDatum;
// Range checking
if ((x0 < _vpX) || (y0 < _vpY) ||(x0 >= _vpW) || (y0 >= _vpH)) return 0;
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
2022-10-19 22:05:25 +00:00
if (!inTransaction) { CS_L; } // CS_L can be multi-statement
readAddrWindow(x0, y0, 1, 1);
// Set masked pins D0- D7 to input
busDir(GPIO_DIR_MASK, INPUT);
2022-01-27 22:15:04 +00:00
#if !defined (SSD1963_DRIVER)
// Dummy read to throw away don't care value
readByte();
2022-01-27 22:15:04 +00:00
#endif
2023-12-07 20:35:59 +00:00
// Fetch the 16-bit BRG pixel
//uint16_t rgb = (readByte() << 8) | readByte();
#if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9488_DRIVER) || defined (SSD1963_DRIVER)// Read 3 bytes
2023-12-07 20:35:59 +00:00
// Read window pixel 24-bit RGB values and fill in LS bits
uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3);
2022-10-19 22:05:25 +00:00
if (!inTransaction) { CS_H; } // CS_H can be multi-statement
// Set masked pins D0- D7 to output
busDir(GPIO_DIR_MASK, OUTPUT);
return rgb;
2023-12-07 20:35:59 +00:00
#else // ILI9481 or ILI9486 16-bit read
2023-12-07 20:35:59 +00:00
// Fetch the 16-bit BRG pixel
uint16_t bgr = (readByte() << 8) | readByte();
2022-10-19 22:05:25 +00:00
if (!inTransaction) { CS_H; } // CS_H can be multi-statement
// Set masked pins D0- D7 to output
busDir(GPIO_DIR_MASK, OUTPUT);
2023-02-25 00:51:29 +00:00
#if defined (ILI9486_DRIVER) || defined (ST7796_DRIVER)
return bgr;
#else
// Swap Red and Blue (could check MADCTL setting to see if this is needed)
return (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
#endif
#endif
#else // Not TFT_PARALLEL_8_BIT
// This function can get called during anti-aliased font rendering
// so a transaction may be in progress
bool wasInTransaction = inTransaction;
if (inTransaction) { inTransaction= false; end_tft_write();}
uint16_t color = 0;
2022-01-27 22:15:04 +00:00
begin_tft_read(); // Sets CS low
2022-01-27 22:15:04 +00:00
readAddrWindow(x0, y0, 1, 1);
#ifdef TFT_SDA_READ
begin_SDA_Read();
#endif
// Dummy read to throw away don't care value
tft_Read_8();
2020-01-25 06:07:45 +00:00
//#if !defined (ILI9488_DRIVER)
#if defined (ST7796_DRIVER)
// Read the 2 bytes
color = ((tft_Read_8()) << 8) | (tft_Read_8());
#elif defined (ST7735_DRIVER)
// Read the 3 RGB bytes, colour is in LS 6 bits of the top 7 bits of each byte
// as the TFT stores colours as 18 bits
uint8_t r = tft_Read_8()<<1;
uint8_t g = tft_Read_8()<<1;
uint8_t b = tft_Read_8()<<1;
color = color565(r, g, b);
#else
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
// as the TFT stores colours as 18 bits
uint8_t r = tft_Read_8();
uint8_t g = tft_Read_8();
uint8_t b = tft_Read_8();
color = color565(r, g, b);
#endif
/*
#else
// The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse
// so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left
uint8_t r = (tft_Read_8()&0x7E)<<1;
uint8_t g = (tft_Read_8()&0x7E)<<1;
uint8_t b = (tft_Read_8()&0x7E)<<1;
color = color565(r, g, b);
#endif
*/
CS_H;
#ifdef TFT_SDA_READ
end_SDA_Read();
#endif
end_tft_read();
// Reinstate the transaction if one was in progress
if(wasInTransaction) { begin_tft_write(); inTransaction = true; }
return color;
#endif
}
void TFT_eSPI::setCallback(getColorCallback getCol)
{
getColor = getCol;
}
/***************************************************************************************
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read 565 pixel colours from a defined area
***************************************************************************************/
void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
{
PI_CLIP ;
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
CS_L;
readAddrWindow(x, y, dw, dh);
data += dx + dy * w;
// Set masked pins D0- D7 to input
busDir(GPIO_DIR_MASK, INPUT);
#if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER) || defined (ILI9488_DRIVER) // Read 3 bytes
2020-10-11 21:36:02 +00:00
// Dummy read to throw away don't care value
readByte();
2023-12-07 20:35:59 +00:00
// Fetch the 24-bit RGB value
while (dh--) {
int32_t lw = dw;
uint16_t* line = data;
while (lw--) {
2023-12-07 20:35:59 +00:00
// Assemble the RGB 16-bit colour
uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3);
// Swapped byte order for compatibility with pushRect()
*line++ = (rgb<<8) | (rgb>>8);
}
data += w;
}
2020-10-11 21:36:02 +00:00
#elif defined (SSD1963_DRIVER)
2023-12-07 20:35:59 +00:00
// Fetch the 18-bit BRG pixels
while (dh--) {
int32_t lw = dw;
uint16_t* line = data;
while (lw--) {
uint16_t bgr = ((readByte() & 0xF8) >> 3);; // CS_L adds a small delay
bgr |= ((readByte() & 0xFC) << 3);
bgr |= (readByte() << 8);
// Swap Red and Blue (could check MADCTL setting to see if this is needed)
uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
// Swapped byte order for compatibility with pushRect()
*line++ = (rgb<<8) | (rgb>>8);
}
data += w;
2020-10-11 21:36:02 +00:00
}
#else // ILI9481 reads as 16 bits
2020-10-11 21:36:02 +00:00
// Dummy read to throw away don't care value
readByte();
2023-12-07 20:35:59 +00:00
// Fetch the 16-bit BRG pixels
while (dh--) {
int32_t lw = dw;
uint16_t* line = data;
while (lw--) {
#if defined (ILI9486_DRIVER) || defined (ST7796_DRIVER)
2023-12-07 20:35:59 +00:00
// Read the RGB 16-bit colour
*line++ = readByte() | (readByte() << 8);
#else
2023-12-07 20:35:59 +00:00
// Read the BRG 16-bit colour
uint16_t bgr = (readByte() << 8) | readByte();
// Swap Red and Blue (could check MADCTL setting to see if this is needed)
uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
// Swapped byte order for compatibility with pushRect()
*line++ = (rgb<<8) | (rgb>>8);
#endif
}
data += w;
}
#endif
CS_H;
// Set masked pins D0- D7 to output
busDir(GPIO_DIR_MASK, OUTPUT);
#else // SPI interface
// This function can get called after a begin_tft_write
// so a transaction may be in progress
bool wasInTransaction = inTransaction;
if (inTransaction) { inTransaction= false; end_tft_write();}
uint16_t color = 0;
begin_tft_read();
readAddrWindow(x, y, dw, dh);
data += dx + dy * w;
#ifdef TFT_SDA_READ
begin_SDA_Read();
#endif
// Dummy read to throw away don't care value
tft_Read_8();
2023-12-07 20:35:59 +00:00
// Read window pixel 24-bit RGB values
while (dh--) {
int32_t lw = dw;
uint16_t* line = data;
while (lw--) {
#if !defined (ILI9488_DRIVER)
#if defined (ST7796_DRIVER)
// Read the 2 bytes
color = ((tft_Read_8()) << 8) | (tft_Read_8());
#elif defined (ST7735_DRIVER)
// Read the 3 RGB bytes, colour is in LS 6 bits of the top 7 bits of each byte
// as the TFT stores colours as 18 bits
uint8_t r = tft_Read_8()<<1;
uint8_t g = tft_Read_8()<<1;
uint8_t b = tft_Read_8()<<1;
color = color565(r, g, b);
#else
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
// as the TFT stores colours as 18 bits
uint8_t r = tft_Read_8();
uint8_t g = tft_Read_8();
uint8_t b = tft_Read_8();
color = color565(r, g, b);
#endif
#else
// The 6 colour bits are in MS 6 bits of each byte but we do not include the extra clock pulse
// so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left
uint8_t r = (tft_Read_8()&0x7E)<<1;
uint8_t g = (tft_Read_8()&0x7E)<<1;
uint8_t b = (tft_Read_8()&0x7E)<<1;
color = color565(r, g, b);
#endif
// Swapped colour byte order for compatibility with pushRect()
*line++ = color << 8 | color >> 8;
}
data += w;
}
//CS_H;
#ifdef TFT_SDA_READ
end_SDA_Read();
#endif
end_tft_read();
// Reinstate the transaction if one was in progress
if(wasInTransaction) { begin_tft_write(); inTransaction = true; }
#endif
}
/***************************************************************************************
** Function name: push rectangle
** Description: push 565 pixel colours into a defined area
***************************************************************************************/
void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
{
bool swap = _swapBytes; _swapBytes = false;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
pushImage(x, y, w, h, data);
_swapBytes = swap;
}
/***************************************************************************************
** Function name: pushImage
2023-12-07 20:35:59 +00:00
** Description: plot 16-bit colour sprite or image onto TFT
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data)
{
2020-10-11 21:36:02 +00:00
PI_CLIP;
begin_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
setWindow(x, y, x + dw - 1, y + dh - 1);
data += dx + dy * w;
// Check if whole image can be pushed
if (dw == w) pushPixels(data, dw * dh);
else {
// Push line segments to crop image
while (dh--)
{
pushPixels(data, dw);
data += w;
}
}
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: pushImage
2023-12-07 20:35:59 +00:00
** Description: plot 16-bit sprite or image with 1 colour being transparent
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transp)
{
2020-10-11 21:36:02 +00:00
PI_CLIP;
begin_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
data += dx + dy * w;
2017-12-03 02:55:43 +00:00
uint16_t lineBuf[dw]; // Use buffer to minimise setWindow call count
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
// The little endian transp color must be byte swapped if the image is big endian
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
if (!_swapBytes) transp = transp >> 8 | transp << 8;
while (dh--)
{
int32_t len = dw;
uint16_t* ptr = data;
int32_t px = x, sx = x;
bool move = true;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint16_t np = 0;
while (len--)
{
if (transp != *ptr)
{
if (move) { move = false; sx = px; }
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
lineBuf[np] = *ptr;
np++;
}
else
{
move = true;
if (np)
{
setWindow(sx, y, sx + np - 1, y);
pushPixels((uint16_t*)lineBuf, np);
np = 0;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
}
px++;
ptr++;
}
if (np) { setWindow(sx, y, sx + np - 1, y); pushPixels((uint16_t*)lineBuf, np); }
y++;
data += w;
}
inTransaction = lockTransaction;
end_tft_write();
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
/***************************************************************************************
** Function name: pushImage - for FLASH (PROGMEM) stored images
2023-12-07 20:35:59 +00:00
** Description: plot 16-bit image
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data)
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
{
2023-12-07 20:35:59 +00:00
// Requires 32-bit aligned access, so use PROGMEM 16-bit word functions
2020-10-11 21:36:02 +00:00
PI_CLIP;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
begin_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
data += dx + dy * w;
uint16_t buffer[dw];
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
setWindow(x, y, x + dw - 1, y + dh - 1);
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
// Fill and send line buffers to TFT
for (int32_t i = 0; i < dh; i++) {
for (int32_t j = 0; j < dw; j++) {
buffer[j] = pgm_read_word(&data[i * w + j]);
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
pushPixels(buffer, dw);
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
inTransaction = lockTransaction;
end_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
/***************************************************************************************
** Function name: pushImage - for FLASH (PROGMEM) stored images
2023-12-07 20:35:59 +00:00
** Description: plot 16-bit image with 1 colour being transparent
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transp)
{
2023-12-07 20:35:59 +00:00
// Requires 32-bit aligned access, so use PROGMEM 16-bit word functions
2020-10-11 21:36:02 +00:00
PI_CLIP;
begin_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
data += dx + dy * w;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint16_t lineBuf[dw];
// The little endian transp color must be byte swapped if the image is big endian
if (!_swapBytes) transp = transp >> 8 | transp << 8;
while (dh--) {
int32_t len = dw;
uint16_t* ptr = (uint16_t*)data;
int32_t px = x, sx = x;
bool move = true;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint16_t np = 0;
while (len--) {
uint16_t color = pgm_read_word(ptr);
if (transp != color) {
if (move) { move = false; sx = px; }
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
lineBuf[np] = color;
np++;
}
else {
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
move = true;
if (np) {
setWindow(sx, y, sx + np - 1, y);
pushPixels(lineBuf, np);
np = 0;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
}
px++;
ptr++;
}
if (np) { setWindow(sx, y, sx + np - 1, y); pushPixels(lineBuf, np); }
y++;
data += w;
}
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: pushImage
2023-12-07 20:35:59 +00:00
** Description: plot 8-bit or 4-bit or 1 bit image or sprite using a line buffer
***************************************************************************************/
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t *data, bool bpp8, uint16_t *cmap)
{
PI_CLIP;
begin_tft_write();
inTransaction = true;
bool swap = _swapBytes;
setWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
// Line buffer makes plotting faster
uint16_t lineBuf[dw];
if (bpp8)
{
_swapBytes = false;
2023-12-07 20:35:59 +00:00
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;
data += dx + dy * w;
while (dh--) {
uint32_t len = dw;
uint8_t* ptr = (uint8_t*)data;
uint8_t* linePtr = (uint8_t*)lineBuf;
while(len--) {
uint32_t color = pgm_read_byte(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;
}
pushPixels(lineBuf, dw);
data += w;
}
_swapBytes = swap; // Restore old value
}
else if (cmap != nullptr) // Must be 4bpp
{
_swapBytes = true;
w = (w+1) & 0xFFFE; // if this is a sprite, w will already be even; this does no harm.
bool splitFirst = (dx & 0x01) != 0; // split first means we have to push a single px from the left of the sprite / image
if (splitFirst) {
data += ((dx - 1 + dy * w) >> 1);
}
else {
data += ((dx + dy * w) >> 1);
}
while (dh--) {
uint32_t len = dw;
uint8_t * ptr = (uint8_t*)data;
uint16_t *linePtr = lineBuf;
uint8_t colors; // two colors in one byte
uint16_t index;
if (splitFirst) {
colors = pgm_read_byte(ptr);
index = (colors & 0x0F);
*linePtr++ = cmap[index];
len--;
ptr++;
}
while (len--)
{
colors = pgm_read_byte(ptr);
index = ((colors & 0xF0) >> 4) & 0x0F;
*linePtr++ = cmap[index];
if (len--)
{
index = colors & 0x0F;
*linePtr++ = cmap[index];
} else {
break; // nothing to do here
}
ptr++;
}
pushPixels(lineBuf, dw);
data += (w >> 1);
}
_swapBytes = swap; // Restore old value
}
else // Must be 1bpp
{
_swapBytes = false;
uint8_t * ptr = (uint8_t*)data;
uint32_t ww = (w+7)>>3; // Width of source image line in bytes
for (int32_t yp = dy; yp < dy + dh; yp++)
{
uint8_t* linePtr = (uint8_t*)lineBuf;
for (int32_t xp = dx; xp < dx + dw; xp++)
{
uint16_t col = (pgm_read_byte(ptr + (xp>>3)) & (0x80 >> (xp & 0x7)) );
if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;}
else {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;}
}
ptr += ww;
pushPixels(lineBuf, dw);
}
}
_swapBytes = swap; // Restore old value
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: pushImage
2023-12-07 20:35:59 +00:00
** Description: plot 8-bit or 4-bit or 1 bit image or sprite using a line buffer
***************************************************************************************/
2020-01-25 06:07:45 +00:00
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8, uint16_t *cmap)
{
2020-10-11 21:36:02 +00:00
PI_CLIP;
begin_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
bool swap = _swapBytes;
setWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
// Line buffer makes plotting faster
uint16_t lineBuf[dw];
if (bpp8)
{
_swapBytes = false;
2023-12-07 20:35:59 +00:00
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;
data += dx + dy * w;
while (dh--) {
uint32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
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;
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
pushPixels(lineBuf, dw);
data += w;
}
_swapBytes = swap; // Restore old value
}
else if (cmap != nullptr) // Must be 4bpp
2020-01-25 06:07:45 +00:00
{
_swapBytes = true;
2020-01-25 06:07:45 +00:00
w = (w+1) & 0xFFFE; // if this is a sprite, w will already be even; this does no harm.
bool splitFirst = (dx & 0x01) != 0; // split first means we have to push a single px from the left of the sprite / image
if (splitFirst) {
data += ((dx - 1 + dy * w) >> 1);
}
else {
data += ((dx + dy * w) >> 1);
}
while (dh--) {
uint32_t len = dw;
uint8_t * ptr = data;
uint16_t *linePtr = lineBuf;
uint8_t colors; // two colors in one byte
uint16_t index;
if (splitFirst) {
colors = *ptr;
index = (colors & 0x0F);
*linePtr++ = cmap[index];
len--;
ptr++;
}
while (len--)
{
colors = *ptr;
index = ((colors & 0xF0) >> 4) & 0x0F;
*linePtr++ = cmap[index];
if (len--)
{
index = colors & 0x0F;
*linePtr++ = cmap[index];
} else {
break; // nothing to do here
}
ptr++;
}
pushPixels(lineBuf, dw);
data += (w >> 1);
}
_swapBytes = swap; // Restore old value
}
else // Must be 1bpp
2020-01-25 06:07:45 +00:00
{
_swapBytes = false;
uint32_t ww = (w+7)>>3; // Width of source image line in bytes
for (int32_t yp = dy; yp < dy + dh; yp++)
{
uint8_t* linePtr = (uint8_t*)lineBuf;
for (int32_t xp = dx; xp < dx + dw; xp++)
{
uint16_t col = (data[(xp>>3)] & (0x80 >> (xp & 0x7)) );
if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;}
else {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;}
}
data += ww;
pushPixels(lineBuf, dw);
}
}
_swapBytes = swap; // Restore old value
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: pushImage
2020-01-25 06:07:45 +00:00
** Description: plot 8 or 4 or 1 bit image or sprite with a transparent colour
***************************************************************************************/
2020-01-25 06:07:45 +00:00
void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transp, bool bpp8, uint16_t *cmap)
{
2020-10-11 21:36:02 +00:00
PI_CLIP;
begin_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
bool swap = _swapBytes;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
// Line buffer makes plotting faster
uint16_t lineBuf[dw];
if (bpp8) { // 8 bits per pixel
_swapBytes = false;
data += dx + dy * w;
2023-12-07 20:35:59 +00:00
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5-bit colour lookup table
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
_lastColor = -1; // Set to illegal value
// Used to store last shifted colour
uint8_t msbColor = 0;
uint8_t lsbColor = 0;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
while (dh--) {
int32_t len = dw;
uint8_t* ptr = data;
uint8_t* linePtr = (uint8_t*)lineBuf;
int32_t px = x, sx = x;
bool move = true;
uint16_t np = 0;
while (len--) {
if (transp != *ptr) {
if (move) { move = false; sx = px; }
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) {
setWindow(sx, y, sx + np - 1, y);
pushPixels(lineBuf, np);
linePtr = (uint8_t*)lineBuf;
np = 0;
}
}
px++;
ptr++;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
if (np) { setWindow(sx, y, sx + np - 1, y); pushPixels(lineBuf, np); }
y++;
data += w;
}
}
2020-01-25 06:07:45 +00:00
else if (cmap != nullptr) // 4bpp with color map
{
_swapBytes = true;
2020-01-25 06:07:45 +00:00
w = (w+1) & 0xFFFE; // here we try to recreate iwidth from dwidth.
bool splitFirst = ((dx & 0x01) != 0);
if (splitFirst) {
data += ((dx - 1 + dy * w) >> 1);
}
else {
data += ((dx + dy * w) >> 1);
}
while (dh--) {
uint32_t len = dw;
uint8_t * ptr = data;
int32_t px = x, sx = x;
2020-01-25 06:07:45 +00:00
bool move = true;
uint16_t np = 0;
uint8_t index; // index into cmap.
if (splitFirst) {
index = (*ptr & 0x0F); // odd = bits 3 .. 0
if (index != transp) {
move = false; sx = px;
2020-01-25 06:07:45 +00:00
lineBuf[np] = cmap[index];
np++;
}
px++; ptr++;
len--;
}
while (len--)
{
uint8_t color = *ptr;
// find the actual color you care about. There will be two pixels here!
// but we may only want one at the end of the row
uint16_t index = ((color & 0xF0) >> 4) & 0x0F; // high bits are the even numbers
if (index != transp) {
if (move) {
move = false; sx = px;
2020-01-25 06:07:45 +00:00
}
lineBuf[np] = cmap[index];
np++; // added a pixel
}
else {
move = true;
if (np) {
setWindow(sx, y, sx + np - 1, y);
2020-01-25 06:07:45 +00:00
pushPixels(lineBuf, np);
np = 0;
}
}
px++;
if (len--)
{
index = color & 0x0F; // the odd number is 3 .. 0
if (index != transp) {
if (move) {
move = false; sx = px;
2020-01-25 06:07:45 +00:00
}
lineBuf[np] = cmap[index];
np++;
}
else {
move = true;
if (np) {
setWindow(sx, y, sx + np - 1, y);
2020-01-25 06:07:45 +00:00
pushPixels(lineBuf, np);
np = 0;
}
}
px++;
}
else {
break; // we are done with this row.
}
ptr++; // we only increment ptr once in the loop (deliberate)
}
if (np) {
setWindow(sx, y, sx + np - 1, y);
2020-01-25 06:07:45 +00:00
pushPixels(lineBuf, np);
np = 0;
}
data += (w>>1);
y++;
}
}
else { // 1 bit per pixel
_swapBytes = false;
uint32_t ww = (w+7)>>3; // Width of source image line in bytes
uint16_t np = 0;
for (int32_t yp = dy; yp < dy + dh; yp++)
{
int32_t px = x, sx = x;
bool move = true;
for (int32_t xp = dx; xp < dx + dw; xp++)
{
if (data[(xp>>3)] & (0x80 >> (xp & 0x7))) {
if (move) {
move = false;
sx = px;
}
np++;
}
else {
move = true;
if (np) {
setWindow(sx, y, sx + np - 1, y);
pushBlock(bitmap_fg, np);
np = 0;
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
px++;
}
if (np) { setWindow(sx, y, sx + np - 1, y); pushBlock(bitmap_fg, np); np = 0; }
y++;
data += ww;
}
}
_swapBytes = swap; // Restore old value
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: pushMaskedImage
2023-12-07 20:35:59 +00:00
** Description: Render a 16-bit colour image to TFT with a 1bpp mask
***************************************************************************************/
// Can be used with a 16bpp sprite and a 1bpp sprite for the mask
void TFT_eSPI::pushMaskedImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *img, uint8_t *mask)
{
if (_vpOoB || w < 1 || h < 1) return;
// To simplify mask handling the window clipping is done by the pushImage function
// Each mask image line assumed to be padded to an integer number of bytes & padding bits are 0
begin_tft_write();
inTransaction = true;
uint8_t *mptr = mask;
uint8_t *eptr = mask + ((w + 7) >> 3);
uint16_t *iptr = img;
uint32_t setCount = 0;
// For each line in the image
while (h--) {
uint32_t xp = 0;
uint32_t clearCount = 0;
uint8_t mbyte= *mptr++;
uint32_t bits = 8;
// Scan through each byte of the bitmap and determine run lengths
do {
setCount = 0;
//Get run length for clear bits to determine x offset
while ((mbyte & 0x80) == 0x00) {
// Check if remaining bits in byte are clear (reduce shifts)
if (mbyte == 0) {
clearCount += bits; // bits not always 8 here
if (mptr >= eptr) break; // end of line
mbyte = *mptr++;
bits = 8;
continue;
}
mbyte = mbyte << 1; // 0's shifted in
clearCount ++;
if (--bits) continue;;
if (mptr >= eptr) break;
mbyte = *mptr++;
bits = 8;
}
//Get run length for set bits to determine render width
while ((mbyte & 0x80) == 0x80) {
// Check if all bits are set (reduces shifts)
if (mbyte == 0xFF) {
setCount += bits;
if (mptr >= eptr) break;
mbyte = *mptr++;
//bits = 8; // NR, bits always 8 here unless 1's shifted in
continue;
}
mbyte = mbyte << 1; //or mbyte += mbyte + 1 to shift in 1's
setCount ++;
if (--bits) continue;
if (mptr >= eptr) break;
mbyte = *mptr++;
bits = 8;
}
// A mask boundary or mask end has been found, so render the pixel line
if (setCount) {
xp += clearCount;
clearCount = 0;
pushImage(x + xp, y, setCount, 1, iptr + xp); // pushImage handles clipping
if (mptr >= eptr) break;
xp += setCount;
}
} while (setCount || mptr < eptr);
y++;
iptr += w;
eptr += ((w + 7) >> 3);
}
inTransaction = lockTransaction;
end_tft_write();
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
/***************************************************************************************
** Function name: setSwapBytes
2023-12-07 20:35:59 +00:00
** Description: Used by 16-bit pushImage() to swap byte order in colours
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
***************************************************************************************/
void TFT_eSPI::setSwapBytes(bool swap)
{
_swapBytes = swap;
}
/***************************************************************************************
** Function name: getSwapBytes
** Description: Return the swap byte order for colours
***************************************************************************************/
bool TFT_eSPI::getSwapBytes(void)
{
return _swapBytes;
}
/***************************************************************************************
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read RGB pixel colours from a defined area
***************************************************************************************/
// If w and h are 1, then 1 pixel is read, *data array size must be 3 bytes per pixel
void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data)
{
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
uint32_t len = w * h;
uint8_t* buf565 = data + len;
readRect(x0, y0, w, h, (uint16_t*)buf565);
while (len--) {
uint16_t pixel565 = (*buf565++)<<8;
pixel565 |= *buf565++;
uint8_t red = (pixel565 & 0xF800) >> 8; red |= red >> 5;
uint8_t green = (pixel565 & 0x07E0) >> 3; green |= green >> 6;
uint8_t blue = (pixel565 & 0x001F) << 3; blue |= blue >> 5;
*data++ = red;
*data++ = green;
*data++ = blue;
}
#else // Not TFT_PARALLEL_8_BIT
begin_tft_read();
readAddrWindow(x0, y0, w, h); // Sets CS low
#ifdef TFT_SDA_READ
begin_SDA_Read();
#endif
// Dummy read to throw away don't care value
tft_Read_8();
2023-12-07 20:35:59 +00:00
// Read window pixel 24-bit RGB values, buffer must be set in sketch to 3 * w * h
uint32_t len = w * h;
while (len--) {
#if !defined (ILI9488_DRIVER)
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
// as the TFT stores colours as 18 bits
*data++ = tft_Read_8();
*data++ = tft_Read_8();
*data++ = tft_Read_8();
#else
// The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse
// so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left
*data++ = (tft_Read_8()&0x7E)<<1;
*data++ = (tft_Read_8()&0x7E)<<1;
*data++ = (tft_Read_8()&0x7E)<<1;
#endif
}
CS_H;
#ifdef TFT_SDA_READ
end_SDA_Read();
#endif
end_tft_read();
#endif
}
/***************************************************************************************
** Function name: drawCircle
** Description: Draw a circle outline
***************************************************************************************/
// Optimised midpoint circle algorithm
void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
{
if ( r <= 0 ) return;
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
int32_t f = 1 - r;
int32_t ddF_y = -2 * r;
int32_t ddF_x = 1;
int32_t xs = -1;
int32_t xe = 0;
int32_t len = 0;
bool first = true;
do {
while (f < 0) {
++xe;
f += (ddF_x += 2);
}
f += (ddF_y += 2);
if (xe-xs>1) {
if (first) {
len = 2*(xe - xs)-1;
drawFastHLine(x0 - xe, y0 + r, len, color);
drawFastHLine(x0 - xe, y0 - r, len, color);
drawFastVLine(x0 + r, y0 - xe, len, color);
drawFastVLine(x0 - r, y0 - xe, len, color);
first = false;
}
else {
len = xe - xs++;
drawFastHLine(x0 - xe, y0 + r, len, color);
drawFastHLine(x0 - xe, y0 - r, len, color);
drawFastHLine(x0 + xs, y0 - r, len, color);
drawFastHLine(x0 + xs, y0 + r, len, color);
drawFastVLine(x0 + r, y0 + xs, len, color);
drawFastVLine(x0 + r, y0 - xe, len, color);
drawFastVLine(x0 - r, y0 - xe, len, color);
drawFastVLine(x0 - r, y0 + xs, len, color);
}
}
else {
++xs;
drawPixel(x0 - xe, y0 + r, color);
drawPixel(x0 - xe, y0 - r, color);
drawPixel(x0 + xs, y0 - r, color);
drawPixel(x0 + xs, y0 + r, color);
drawPixel(x0 + r, y0 + xs, color);
drawPixel(x0 + r, y0 - xe, color);
drawPixel(x0 - r, y0 - xe, color);
drawPixel(x0 - r, y0 + xs, color);
}
xs = xe;
} while (xe < --r);
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawCircleHelper
** Description: Support function for drawRoundRect()
***************************************************************************************/
void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t rr, uint8_t cornername, uint32_t color)
{
if (rr <= 0) return;
int32_t f = 1 - rr;
int32_t ddF_x = 1;
int32_t ddF_y = -2 * rr;
int32_t xe = 0;
int32_t xs = 0;
int32_t len = 0;
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
2023-12-06 13:51:53 +00:00
do
{
while (f < 0) {
++xe;
f += (ddF_x += 2);
}
f += (ddF_y += 2);
if (xe-xs==1) {
if (cornername & 0x1) { // left top
drawPixel(x0 - xe, y0 - rr, color);
drawPixel(x0 - rr, y0 - xe, color);
}
if (cornername & 0x2) { // right top
drawPixel(x0 + rr , y0 - xe, color);
drawPixel(x0 + xs + 1, y0 - rr, color);
}
if (cornername & 0x4) { // right bottom
drawPixel(x0 + xs + 1, y0 + rr , color);
drawPixel(x0 + rr, y0 + xs + 1, color);
}
if (cornername & 0x8) { // left bottom
drawPixel(x0 - rr, y0 + xs + 1, color);
drawPixel(x0 - xe, y0 + rr , color);
}
}
else {
len = xe - xs++;
if (cornername & 0x1) { // left top
drawFastHLine(x0 - xe, y0 - rr, len, color);
drawFastVLine(x0 - rr, y0 - xe, len, color);
}
if (cornername & 0x2) { // right top
drawFastVLine(x0 + rr, y0 - xe, len, color);
drawFastHLine(x0 + xs, y0 - rr, len, color);
}
if (cornername & 0x4) { // right bottom
drawFastHLine(x0 + xs, y0 + rr, len, color);
drawFastVLine(x0 + rr, y0 + xs, len, color);
}
if (cornername & 0x8) { // left bottom
drawFastVLine(x0 - rr, y0 + xs, len, color);
drawFastHLine(x0 - xe, y0 + rr, len, color);
}
}
xs = xe;
2023-12-06 13:51:53 +00:00
} while (xe < rr--);
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: fillCircle
** Description: draw a filled circle
***************************************************************************************/
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
// Optimised midpoint circle algorithm, changed to horizontal lines (faster in sprites)
// Improved algorithm avoids repetition of lines
void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
{
int32_t x = 0;
int32_t dx = 1;
int32_t dy = r+r;
int32_t p = -(r>>1);
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
drawFastHLine(x0 - r, y0, dy+1, color);
while(x<r){
if(p>=0) {
2020-10-19 15:21:00 +00:00
drawFastHLine(x0 - x, y0 + r, dx, color);
drawFastHLine(x0 - x, y0 - r, dx, color);
dy-=2;
p-=dy;
r--;
}
dx+=2;
p+=dx;
x++;
drawFastHLine(x0 - r, y0 + x, dy+1, color);
drawFastHLine(x0 - r, y0 - x, dy+1, color);
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: fillCircleHelper
** Description: Support function for fillRoundRect()
***************************************************************************************/
// Support drawing roundrects, changed to horizontal lines (faster in sprites)
void TFT_eSPI::fillCircleHelper(int32_t x0, int32_t y0, int32_t r, uint8_t cornername, int32_t delta, uint32_t color)
{
int32_t f = 1 - r;
int32_t ddF_x = 1;
int32_t ddF_y = -r - r;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
int32_t y = 0;
delta++;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
while (y < r) {
if (f >= 0) {
if (cornername & 0x1) drawFastHLine(x0 - y, y0 + r, y + y + delta, color);
if (cornername & 0x2) drawFastHLine(x0 - y, y0 - r, y + y + delta, color);
r--;
ddF_y += 2;
f += ddF_y;
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
y++;
ddF_x += 2;
f += ddF_x;
if (cornername & 0x1) drawFastHLine(x0 - r, y0 + y, r + r + delta, color);
if (cornername & 0x2) drawFastHLine(x0 - r, y0 - y, r + r + delta, color);
}
}
/***************************************************************************************
** Function name: drawEllipse
** Description: Draw a ellipse outline
***************************************************************************************/
void TFT_eSPI::drawEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint16_t color)
{
if (rx<2) return;
if (ry<2) return;
int32_t x, y;
int32_t rx2 = rx * rx;
int32_t ry2 = ry * ry;
int32_t fx2 = 4 * rx2;
int32_t fy2 = 4 * ry2;
int32_t s;
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++) {
// These are ordered to minimise coordinate changes in x or y
// drawPixel can then send fewer bounding box commands
drawPixel(x0 + x, y0 + y, color);
drawPixel(x0 - x, y0 + y, color);
drawPixel(x0 - x, y0 - y, color);
drawPixel(x0 + x, y0 - y, color);
if (s >= 0) {
s += fx2 * (1 - y);
y--;
}
s += ry2 * ((4 * x) + 6);
}
for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++) {
// These are ordered to minimise coordinate changes in x or y
// drawPixel can then send fewer bounding box commands
drawPixel(x0 + x, y0 + y, color);
drawPixel(x0 - x, y0 + y, color);
drawPixel(x0 - x, y0 - y, color);
drawPixel(x0 + x, y0 - y, color);
if (s >= 0)
{
s += fy2 * (1 - x);
x--;
}
s += rx2 * ((4 * y) + 6);
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: fillEllipse
** Description: draw a filled ellipse
***************************************************************************************/
void TFT_eSPI::fillEllipse(int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint16_t color)
{
if (rx<2) return;
if (ry<2) return;
int32_t x, y;
int32_t rx2 = rx * rx;
int32_t ry2 = ry * ry;
int32_t fx2 = 4 * rx2;
int32_t fy2 = 4 * ry2;
int32_t s;
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++) {
drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
if (s >= 0) {
s += fx2 * (1 - y);
y--;
}
s += ry2 * ((4 * x) + 6);
}
for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++) {
drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
if (s >= 0) {
s += fy2 * (1 - x);
x--;
}
s += rx2 * ((4 * y) + 6);
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: fillScreen
** Description: Clear the screen to defined colour
***************************************************************************************/
void TFT_eSPI::fillScreen(uint32_t color)
{
fillRect(0, 0, _width, _height, color);
}
/***************************************************************************************
** Function name: drawRect
** Description: Draw a rectangle outline
***************************************************************************************/
// Draw a rectangle
void TFT_eSPI::drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
drawFastHLine(x, y, w, color);
drawFastHLine(x, y + h - 1, w, color);
// Avoid drawing corner pixels twice
drawFastVLine(x, y+1, h-2, color);
drawFastVLine(x + w - 1, y+1, h-2, color);
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawRoundRect
** Description: Draw a rounded corner rectangle outline
***************************************************************************************/
// Draw a rounded rectangle
void TFT_eSPI::drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
// smarter version
drawFastHLine(x + r , y , w - r - r, color); // Top
drawFastHLine(x + r , y + h - 1, w - r - r, color); // Bottom
drawFastVLine(x , y + r , h - r - r, color); // Left
drawFastVLine(x + w - 1, y + r , h - r - r, color); // Right
// draw four corners
drawCircleHelper(x + r , y + r , r, 1, color);
drawCircleHelper(x + w - r - 1, y + r , r, 2, color);
drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
drawCircleHelper(x + r , y + h - r - 1, r, 8, color);
2020-01-25 06:07:45 +00:00
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: fillRoundRect
** Description: Draw a rounded corner filled rectangle
***************************************************************************************/
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
// Fill a rounded rectangle, changed to horizontal lines (faster in sprites)
void TFT_eSPI::fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
// smarter version
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
fillRect(x, y + r, w, h - r - r, color);
// draw four corners
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
fillCircleHelper(x + r, y + h - r - 1, r, 1, w - r - r - 1, color);
fillCircleHelper(x + r , y + r, r, 2, w - r - r - 1, color);
2020-01-25 06:07:45 +00:00
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawTriangle
** Description: Draw a triangle outline using 3 arbitrary points
***************************************************************************************/
// Draw a triangle
void TFT_eSPI::drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
drawLine(x0, y0, x1, y1, color);
drawLine(x1, y1, x2, y2, color);
drawLine(x2, y2, x0, y0, color);
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: fillTriangle
** Description: Draw a filled triangle using 3 arbitrary points
***************************************************************************************/
// Fill a triangle - original Adafruit function works well and code footprint is small
void TFT_eSPI::fillTriangle ( int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color)
{
int32_t a, b, y, last;
// Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1) {
transpose(y0, y1); transpose(x0, x1);
}
if (y1 > y2) {
transpose(y2, y1); transpose(x2, x1);
}
if (y0 > y1) {
transpose(y0, y1); transpose(x0, x1);
}
if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
a = b = x0;
if (x1 < a) a = x1;
else if (x1 > b) b = x1;
if (x2 < a) a = x2;
else if (x2 > b) b = x2;
drawFastHLine(a, y0, b - a + 1, color);
return;
}
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
int32_t
dx01 = x1 - x0,
dy01 = y1 - y0,
dx02 = x2 - x0,
dy02 = y2 - y0,
dx12 = x2 - x1,
dy12 = y2 - y1,
sa = 0,
sb = 0;
// For upper part of triangle, find scanline crossings for segments
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
// is included here (and second loop will be skipped, avoiding a /0
// error there), otherwise scanline y1 is skipped here and handled
// in the second loop...which also avoids a /0 error here if y0=y1
// (flat-topped triangle).
if (y1 == y2) last = y1; // Include y1 scanline
else last = y1 - 1; // Skip it
for (y = y0; y <= last; y++) {
a = x0 + sa / dy01;
b = x0 + sb / dy02;
sa += dx01;
sb += dx02;
if (a > b) transpose(a, b);
drawFastHLine(a, y, b - a + 1, color);
}
// For lower part of triangle, find scanline crossings for segments
// 0-2 and 1-2. This loop is skipped if y1=y2.
sa = dx12 * (y - y1);
sb = dx02 * (y - y0);
for (; y <= y2; y++) {
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
if (a > b) transpose(a, b);
drawFastHLine(a, y, b - a + 1, color);
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawBitmap
** Description: Draw an image stored in an array on the TFT
***************************************************************************************/
void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
int32_t i, j, byteWidth = (w + 7) / 8;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++ ) {
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
drawPixel(x + i, y + j, color);
}
}
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawBitmap
** Description: Draw an image stored in an array on the TFT
***************************************************************************************/
void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
int32_t i, j, byteWidth = (w + 7) / 8;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++ ) {
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7)))
drawPixel(x + i, y + j, fgcolor);
else drawPixel(x + i, y + j, bgcolor);
}
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawXBitmap
** Description: Draw an image stored in an XBM array onto the TFT
***************************************************************************************/
void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
int32_t i, j, byteWidth = (w + 7) / 8;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++ ) {
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i & 7))) {
drawPixel(x + i, y + j, color);
}
}
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: drawXBitmap
** Description: Draw an XBM image with foreground and background colors
***************************************************************************************/
void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bgcolor)
{
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
int32_t i, j, byteWidth = (w + 7) / 8;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++ ) {
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i & 7)))
drawPixel(x + i, y + j, color);
else drawPixel(x + i, y + j, bgcolor);
}
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
/***************************************************************************************
** Function name: setCursor
** Description: Set the text cursor x,y position
***************************************************************************************/
void TFT_eSPI::setCursor(int16_t x, int16_t y)
{
cursor_x = x;
cursor_y = y;
}
/***************************************************************************************
** Function name: setCursor
** Description: Set the text cursor x,y position and font
***************************************************************************************/
void TFT_eSPI::setCursor(int16_t x, int16_t y, uint8_t font)
{
setTextFont(font);
cursor_x = x;
cursor_y = y;
}
/***************************************************************************************
** Function name: getCursorX
** Description: Get the text cursor x position
***************************************************************************************/
int16_t TFT_eSPI::getCursorX(void)
{
return cursor_x;
}
/***************************************************************************************
** Function name: getCursorY
** Description: Get the text cursor y position
***************************************************************************************/
int16_t TFT_eSPI::getCursorY(void)
{
return cursor_y;
}
/***************************************************************************************
** Function name: setTextSize
** Description: Set the text size multiplier
***************************************************************************************/
void TFT_eSPI::setTextSize(uint8_t s)
{
if (s>7) s = 7; // Limit the maximum size multiplier so byte variables can be used for rendering
textsize = (s > 0) ? s : 1; // Don't allow font size 0
}
/***************************************************************************************
** Function name: setTextColor
** Description: Set the font foreground colour (background is transparent)
***************************************************************************************/
void TFT_eSPI::setTextColor(uint16_t c)
{
// For 'transparent' background, we'll set the bg
// to the same as fg instead of using a flag
textcolor = textbgcolor = c;
}
/***************************************************************************************
** Function name: setTextColor
** Description: Set the font foreground and background colour
***************************************************************************************/
// Smooth fonts use the background colour for anti-aliasing and by default the
// background is not filled. If bgfill = true, then a smooth font background fill will
// be used.
void TFT_eSPI::setTextColor(uint16_t c, uint16_t b, bool bgfill)
{
textcolor = c;
textbgcolor = b;
_fillbg = bgfill;
}
/***************************************************************************************
** Function name: setPivot
** Description: Set the pivot point on the TFT
*************************************************************************************x*/
void TFT_eSPI::setPivot(int16_t x, int16_t y)
{
_xPivot = x;
_yPivot = y;
}
/***************************************************************************************
** Function name: getPivotX
** Description: Get the x pivot position
***************************************************************************************/
int16_t TFT_eSPI::getPivotX(void)
{
return _xPivot;
}
/***************************************************************************************
** Function name: getPivotY
** Description: Get the y pivot position
***************************************************************************************/
int16_t TFT_eSPI::getPivotY(void)
{
return _yPivot;
}
/***************************************************************************************
** 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
***************************************************************************************/
void TFT_eSPI::setTextWrap(bool wrapX, bool wrapY)
{
2018-02-24 19:02:20 +00:00
textwrapX = wrapX;
textwrapY = wrapY;
}
/***************************************************************************************
** Function name: setTextDatum
** Description: Set the text position reference datum
***************************************************************************************/
void TFT_eSPI::setTextDatum(uint8_t d)
{
textdatum = d;
}
/***************************************************************************************
** Function name: setTextPadding
** Description: Define padding width (aids erasing old text and numbers)
***************************************************************************************/
void TFT_eSPI::setTextPadding(uint16_t x_width)
{
padX = x_width;
}
/***************************************************************************************
** Function name: setTextPadding
** Description: Define padding width (aids erasing old text and numbers)
***************************************************************************************/
uint16_t TFT_eSPI::getTextPadding(void)
{
return padX;
}
/***************************************************************************************
** Function name: getTextDatum
** Description: Return the text datum value (as used by setTextDatum())
***************************************************************************************/
uint8_t TFT_eSPI::getTextDatum(void)
{
return textdatum;
}
/***************************************************************************************
** Function name: width
** Description: Return the pixel width of display (per current rotation)
***************************************************************************************/
// Return the size of the display (per current rotation)
int16_t TFT_eSPI::width(void)
{
if (_vpDatum) return _xWidth;
return _width;
}
/***************************************************************************************
** Function name: height
** Description: Return the pixel height of display (per current rotation)
***************************************************************************************/
int16_t TFT_eSPI::height(void)
{
if (_vpDatum) return _yHeight;
return _height;
}
/***************************************************************************************
** Function name: textWidth
** Description: Return the width in pixels of a string in a given font
***************************************************************************************/
int16_t TFT_eSPI::textWidth(const String& string)
{
int16_t len = string.length() + 2;
char buffer[len];
string.toCharArray(buffer, len);
return textWidth(buffer, textfont);
}
int16_t TFT_eSPI::textWidth(const String& string, uint8_t font)
{
int16_t len = string.length() + 2;
char buffer[len];
string.toCharArray(buffer, len);
return textWidth(buffer, font);
}
int16_t TFT_eSPI::textWidth(const char *string)
{
return textWidth(string, textfont);
}
int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
{
int32_t str_width = 0;
uint16_t uniCode = 0;
2018-02-24 19:02:20 +00:00
#ifdef SMOOTH_FONT
if(fontLoaded) {
while (*string) {
uniCode = decodeUTF8(*string++);
if (uniCode) {
if (uniCode == 0x20) str_width += gFont.spaceWidth;
else {
2018-02-24 19:02:20 +00:00
uint16_t gNum = 0;
bool found = getUnicodeIndex(uniCode, &gNum);
if (found) {
2018-02-24 19:02:20 +00:00
if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum];
if (*string || isDigits) str_width += gxAdvance[gNum];
2018-02-24 19:02:20 +00:00
else str_width += (gdX[gNum] + gWidth[gNum]);
}
else str_width += gFont.spaceWidth + 1;
}
}
}
isDigits = false;
2018-02-24 19:02:20 +00:00
return str_width;
}
#endif
if (font>1 && font<9) {
char *widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop
while (*string) {
uniCode = *(string++);
if (uniCode > 31 && uniCode < 128)
str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subtract 32 from uniCode
else str_width += pgm_read_byte( widthtable + 32); // Set illegal character = space width
}
}
else {
#ifdef LOAD_GFXFF
if(gfxFont) { // New font
while (*string) {
uniCode = decodeUTF8(*string++);
if ((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last ))) {
uniCode -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[uniCode]);
// If this is not the last character or is a digit then use xAdvance
if (*string || isDigits) str_width += pgm_read_byte(&glyph->xAdvance);
// Else use the offset plus width since this can be bigger than xAdvance
else str_width += ((int8_t)pgm_read_byte(&glyph->xOffset) + pgm_read_byte(&glyph->width));
}
}
}
else
#endif
{
#ifdef LOAD_GLCD
while (*string++) str_width += 6;
#endif
}
}
isDigits = false;
return str_width * textsize;
}
/***************************************************************************************
** Function name: fontsLoaded
2023-12-07 20:35:59 +00:00
** Description: return an encoded 16-bit value showing the fonts loaded
***************************************************************************************/
// Returns a value showing which fonts are loaded (bit N set = Font N loaded)
uint16_t TFT_eSPI::fontsLoaded(void)
{
return fontsloaded;
}
/***************************************************************************************
** Function name: fontHeight
** Description: return the height of a font (yAdvance for free fonts)
***************************************************************************************/
2024-01-16 22:49:43 +00:00
int16_t TFT_eSPI::fontHeight(uint8_t font)
{
2024-01-16 22:49:43 +00:00
if (font > 8) return 0;
2018-02-24 19:02:20 +00:00
#ifdef SMOOTH_FONT
if(fontLoaded) return gFont.yAdvance;
#endif
#ifdef LOAD_GFXFF
if (font==1) {
if(gfxFont) { // New font
return pgm_read_byte(&gfxFont->yAdvance) * textsize;
}
}
#endif
return pgm_read_byte( &fontdata[font].height ) * textsize;
}
int16_t TFT_eSPI::fontHeight(void)
{
return fontHeight(textfont);
}
/***************************************************************************************
** Function name: drawChar
** Description: draw a single character in the GLCD or GFXFF font
***************************************************************************************/
void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB) return;
#ifdef LOAD_GLCD
//>>>>>>>>>>>>>>>>>>
2020-10-11 21:36:02 +00:00
#ifdef LOAD_GFXFF
2023-02-15 16:57:55 +00:00
if(!gfxFont) { // 'Classic' built-in GLCD font
2020-10-11 21:36:02 +00:00
#endif
//>>>>>>>>>>>>>>>>>>
int32_t xd = x + _xDatum;
int32_t yd = y + _yDatum;
2020-10-11 21:36:02 +00:00
if ((xd >= _vpW) || // Clip right
( yd >= _vpH) || // Clip bottom
((xd + 6 * size - 1) < _vpX) || // Clip left
((yd + 8 * size - 1) < _vpY)) // Clip top
return;
if (c > 255) return;
if (!_cp437 && c > 175) c++;
bool fillbg = (bg != color);
2020-10-11 21:36:02 +00:00
bool clip = xd < _vpX || xd + 6 * textsize >= _vpW || yd < _vpY || yd + 8 * textsize >= _vpH;
2020-10-11 21:36:02 +00:00
if ((size==1) && fillbg && !clip) {
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t column[6];
uint8_t mask = 0x1;
begin_tft_write();
setWindow(xd, yd, xd+5, yd+7);
2024-01-16 22:49:43 +00:00
for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(&font[0] + (c * 5) + i);
column[5] = 0;
for (int8_t j = 0; j < 8; j++) {
for (int8_t k = 0; k < 5; k++ ) {
if (column[k] & mask) {tft_Write_16(color);}
else {tft_Write_16(bg);}
}
mask <<= 1;
tft_Write_16(bg);
}
end_tft_write();
}
else {
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
2020-10-11 21:36:02 +00:00
for (int8_t i = 0; i < 6; i++ ) {
uint8_t line;
if (i == 5)
line = 0x0;
else
2024-01-16 22:49:43 +00:00
line = pgm_read_byte(&font[0] + (c * 5) + i);
if (size == 1 && !fillbg) { // default size
for (int8_t j = 0; j < 8; j++) {
if (line & 0x1) drawPixel(x + i, y + j, color);
line >>= 1;
}
}
else { // big size or clipped
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;
}
}
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
2020-10-11 21:36:02 +00:00
#ifdef LOAD_GFXFF
} else { // Custom font
2020-10-11 21:36:02 +00:00
#endif
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
#endif // LOAD_GLCD
#ifdef LOAD_GFXFF
// Filter out bad characters not present in font
if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last ))) {
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
c -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap);
uint32_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=0, bit=0;
int16_t xo16 = 0, yo16 = 0;
2020-01-25 06:07:45 +00:00
if(size > 1) {
xo16 = xo;
yo16 = yo;
}
// GFXFF rendering speed up
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;
}
}
inTransaction = lockTransaction;
end_tft_write(); // Does nothing if Sprite class uses this function
}
#endif
#ifdef LOAD_GLCD
#ifdef LOAD_GFXFF
} // End classic vs custom font
#endif
#else
#ifndef LOAD_GFXFF
// Avoid warnings if fonts are disabled
x = x;
y = y;
color = color;
bg = bg;
size = size;
#endif
#endif
}
/***************************************************************************************
** Function name: setAddrWindow
** Description: define an area to receive a stream of pixels
***************************************************************************************/
// Chip select is high at the end of this function
void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t w, int32_t h)
{
begin_tft_write();
setWindow(x0, y0, x0 + w - 1, y0 + h - 1);
end_tft_write();
}
/***************************************************************************************
** Function name: setWindow
** Description: define an area to receive a stream of pixels
***************************************************************************************/
// Chip select stays low, call begin_tft_write first. Use setAddrWindow() from sketches
void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
{
//begin_tft_write(); // Must be called before setWindow
addr_row = 0xFFFF;
addr_col = 0xFFFF;
#if defined (ILI9225_DRIVER)
if (rotation & 0x01) { transpose(x0, y0); transpose(x1, y1); }
SPI_BUSY_CHECK;
DC_C; tft_Write_8(TFT_CASET1);
DC_D; tft_Write_16(x0);
DC_C; tft_Write_8(TFT_CASET2);
DC_D; tft_Write_16(x1);
DC_C; tft_Write_8(TFT_PASET1);
DC_D; tft_Write_16(y0);
DC_C; tft_Write_8(TFT_PASET2);
DC_D; tft_Write_16(y1);
DC_C; tft_Write_8(TFT_RAM_ADDR1);
DC_D; tft_Write_16(x0);
DC_C; tft_Write_8(TFT_RAM_ADDR2);
DC_D; tft_Write_16(y0);
// write to RAM
DC_C; tft_Write_8(TFT_RAMWR);
DC_D;
// Temporary solution is to include the RP2040 code here
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined(RP2040_PIO_INTERFACE)
2023-12-07 20:35:59 +00:00
// For ILI9225 and RP2040 the slower Arduino SPI transfer calls were used, so need to swap back to 16-bit mode
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
#endif
#elif defined (SSD1351_DRIVER)
if (rotation & 1) {
transpose(x0, y0);
transpose(x1, y1);
}
SPI_BUSY_CHECK;
DC_C; tft_Write_8(TFT_CASET);
DC_D; tft_Write_16(x1 | (x0 << 8));
DC_C; tft_Write_8(TFT_PASET);
DC_D; tft_Write_16(y1 | (y0 << 8));
DC_C; tft_Write_8(TFT_RAMWR);
DC_D;
#else
#if defined (SSD1963_DRIVER)
if ((rotation & 0x1) == 0) { transpose(x0, y0); transpose(x1, y1); }
#endif
#ifdef CGRAM_OFFSET
x0+=colstart;
x1+=colstart;
y0+=rowstart;
y1+=rowstart;
#endif
// Temporary solution is to include the RP2040 optimised code here
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED))
#if !defined(RP2040_PIO_INTERFACE)
2023-12-07 20:35:59 +00:00
// Use hardware SPI port, this code does not swap from 8 to 16-bit
// to avoid the spi_set_format() call overhead
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_C;
#if !defined (SPI_18BIT_DRIVER)
2023-12-07 20:35:59 +00:00
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16-bit transfers
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
#else
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
#endif
#endif
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
spi_get_hw(SPI_X)->dr = (uint32_t)x0>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)x0;
spi_get_hw(SPI_X)->dr = (uint32_t)x1>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)x1;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
spi_get_hw(SPI_X)->dr = (uint32_t)y0>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)y0;
spi_get_hw(SPI_X)->dr = (uint32_t)y1>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)y1;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMWR;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
#if !defined (SPI_18BIT_DRIVER)
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
#endif
DC_D;
#elif defined (RM68120_DRIVER)
DC_C; tft_Write_16(TFT_CASET+0); DC_D; tft_Write_16(x0 >> 8);
DC_C; tft_Write_16(TFT_CASET+1); DC_D; tft_Write_16(x0 & 0xFF);
DC_C; tft_Write_16(TFT_CASET+2); DC_D; tft_Write_16(x1 >> 8);
DC_C; tft_Write_16(TFT_CASET+3); DC_D; tft_Write_16(x1 & 0xFF);
DC_C; tft_Write_16(TFT_PASET+0); DC_D; tft_Write_16(y0 >> 8);
DC_C; tft_Write_16(TFT_PASET+1); DC_D; tft_Write_16(y0 & 0xFF);
DC_C; tft_Write_16(TFT_PASET+2); DC_D; tft_Write_16(y1 >> 8);
DC_C; tft_Write_16(TFT_PASET+3); DC_D; tft_Write_16(y1 & 0xFF);
DC_C; tft_Write_16(TFT_RAMWR);
DC_D;
#else
// This is for the RP2040 and PIO interface (SPI or parallel)
WAIT_FOR_STALL;
tft_pio->sm[pio_sm].instr = pio_instr_addr;
TX_FIFO = TFT_CASET;
TX_FIFO = (x0<<16) | x1;
TX_FIFO = TFT_PASET;
TX_FIFO = (y0<<16) | y1;
TX_FIFO = TFT_RAMWR;
#endif
#else
SPI_BUSY_CHECK;
DC_C; tft_Write_8(TFT_CASET);
DC_D; tft_Write_32C(x0, x1);
DC_C; tft_Write_8(TFT_PASET);
DC_D; tft_Write_32C(y0, y1);
DC_C; tft_Write_8(TFT_RAMWR);
DC_D;
#endif // RP2040 SPI
#endif
//end_tft_write(); // Must be called after setWindow
}
/***************************************************************************************
** Function name: readAddrWindow
** Description: define an area to read a stream of pixels
***************************************************************************************/
void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h)
{
//begin_tft_write(); // Must be called before readAddrWindow or CS set low
int32_t xe = xs + w - 1;
int32_t ye = ys + h - 1;
addr_col = 0xFFFF;
addr_row = 0xFFFF;
2022-01-27 22:15:04 +00:00
#if defined (SSD1963_DRIVER)
if ((rotation & 0x1) == 0) { transpose(xs, ys); transpose(xe, ye); }
2022-01-27 22:15:04 +00:00
#endif
#ifdef CGRAM_OFFSET
2019-01-25 13:03:28 +00:00
xs += colstart;
xe += colstart;
ys += rowstart;
ye += rowstart;
#endif
// Temporary solution is to include the RP2040 optimised code here
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined(RP2040_PIO_INTERFACE)
2023-12-07 20:35:59 +00:00
// Use hardware SPI port, this code does not swap from 8 to 16-bit
2022-01-27 22:15:04 +00:00
// to avoid the spi_set_format() call overhead
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_C;
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
spi_get_hw(SPI_X)->dr = (uint32_t)xs>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)xs;
spi_get_hw(SPI_X)->dr = (uint32_t)xe>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)xe;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
spi_get_hw(SPI_X)->dr = (uint32_t)ys>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)ys;
spi_get_hw(SPI_X)->dr = (uint32_t)ye>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)ye;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMRD;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
// Flush the rx buffer and reset overflow flag
while (spi_is_readable(SPI_X)) (void)spi_get_hw(SPI_X)->dr;
spi_get_hw(SPI_X)->icr = SPI_SSPICR_RORIC_BITS;
#else
// Column addr set
DC_C; tft_Write_8(TFT_CASET);
DC_D; tft_Write_32C(xs, xe);
// Row addr set
DC_C; tft_Write_8(TFT_PASET);
DC_D; tft_Write_32C(ys, ye);
// Read CGRAM command
DC_C; tft_Write_8(TFT_RAMRD);
DC_D;
#endif // RP2040 SPI
//end_tft_write(); // Must be called after readAddrWindow or CS set high
}
/***************************************************************************************
** Function name: drawPixel
** Description: push a single pixel at an arbitrary position
***************************************************************************************/
void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB) return;
x+= _xDatum;
y+= _yDatum;
// Range checking
if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return;
#ifdef CGRAM_OFFSET
x+=colstart;
y+=rowstart;
#endif
#if (defined (MULTI_TFT_SUPPORT) || defined (GC9A01_DRIVER)) && !defined (ILI9225_DRIVER)
addr_row = 0xFFFF;
addr_col = 0xFFFF;
#endif
begin_tft_write();
#if defined (ILI9225_DRIVER)
if (rotation & 0x01) { transpose(x, y); }
SPI_BUSY_CHECK;
// Set window to full screen to optimise sequential pixel rendering
if (addr_row != 0x9225) {
addr_row = 0x9225; // addr_row used for flag
DC_C; tft_Write_8(TFT_CASET1);
DC_D; tft_Write_16(0);
DC_C; tft_Write_8(TFT_CASET2);
DC_D; tft_Write_16(175);
DC_C; tft_Write_8(TFT_PASET1);
DC_D; tft_Write_16(0);
DC_C; tft_Write_8(TFT_PASET2);
DC_D; tft_Write_16(219);
}
// Define pixel coordinate
DC_C; tft_Write_8(TFT_RAM_ADDR1);
DC_D; tft_Write_16(x);
DC_C; tft_Write_8(TFT_RAM_ADDR2);
DC_D; tft_Write_16(y);
// write to RAM
DC_C; tft_Write_8(TFT_RAMWR);
2022-04-22 01:44:10 +00:00
#if defined(TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) || !defined(ESP32)
DC_D; tft_Write_16(color);
#else
DC_D; tft_Write_16N(color);
#endif
// Temporary solution is to include the RP2040 optimised code here
#elif (defined (ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined (SSD1351_DRIVER)
#if defined (SSD1963_DRIVER)
if ((rotation & 0x1) == 0) { transpose(x, y); }
#endif
#if !defined(RP2040_PIO_INTERFACE)
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
2023-12-07 20:35:59 +00:00
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16-bit transfers
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
#else
hw_write_masked(&spi_get_hw(SPI_X)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS);
#endif
if (addr_col != x) {
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS){};
DC_D;
spi_get_hw(SPI_X)->dr = (uint32_t)x>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)x;
spi_get_hw(SPI_X)->dr = (uint32_t)x>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)x;
addr_col = x;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
}
if (addr_row != y) {
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
spi_get_hw(SPI_X)->dr = (uint32_t)y>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)y;
spi_get_hw(SPI_X)->dr = (uint32_t)y>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)y;
addr_row = y;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
}
DC_C;
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMWR;
2023-12-07 20:35:59 +00:00
#if defined (SPI_18BIT_DRIVER) // SPI 18-bit colour
uint8_t r = (color & 0xF800)>>8;
uint8_t g = (color & 0x07E0)>>3;
uint8_t b = (color & 0x001F)<<3;
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
tft_Write_8N(r); tft_Write_8N(g); tft_Write_8N(b);
#else
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
DC_D;
2023-12-07 20:35:59 +00:00
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16-bit transfers
spi_get_hw(SPI_X)->dr = (uint32_t)color;
#else
spi_get_hw(SPI_X)->dr = (uint32_t)color>>8;
spi_get_hw(SPI_X)->dr = (uint32_t)color;
#endif
#endif
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
#elif defined (RM68120_DRIVER)
if (addr_col != x) {
DC_C; tft_Write_16(TFT_CASET+0); DC_D; tft_Write_16(x >> 8);
DC_C; tft_Write_16(TFT_CASET+1); DC_D; tft_Write_16(x & 0xFF);
DC_C; tft_Write_16(TFT_CASET+2); DC_D; tft_Write_16(x >> 8);
DC_C; tft_Write_16(TFT_CASET+3); DC_D; tft_Write_16(x & 0xFF);
addr_col = x;
}
if (addr_row != y) {
DC_C; tft_Write_16(TFT_PASET+0); DC_D; tft_Write_16(y >> 8);
DC_C; tft_Write_16(TFT_PASET+1); DC_D; tft_Write_16(y & 0xFF);
DC_C; tft_Write_16(TFT_PASET+2); DC_D; tft_Write_16(y >> 8);
DC_C; tft_Write_16(TFT_PASET+3); DC_D; tft_Write_16(y & 0xFF);
addr_row = y;
}
DC_C; tft_Write_16(TFT_RAMWR); DC_D;
TX_FIFO = color;
#else
// This is for the RP2040 and PIO interface (SPI or parallel)
WAIT_FOR_STALL;
tft_pio->sm[pio_sm].instr = pio_instr_addr;
TX_FIFO = TFT_CASET;
TX_FIFO = (x<<16) | x;
TX_FIFO = TFT_PASET;
TX_FIFO = (y<<16) | y;
TX_FIFO = TFT_RAMWR;
//DC set high by PIO
#if defined (SPI_18BIT_DRIVER) || (defined (SSD1963_DRIVER) && defined (TFT_PARALLEL_8_BIT))
TX_FIFO = ((color & 0xF800)<<8) | ((color & 0x07E0)<<5) | ((color & 0x001F)<<3);
#else
TX_FIFO = color;
#endif
#endif
#else
2022-02-21 14:32:02 +00:00
#if defined (SSD1963_DRIVER)
if ((rotation & 0x1) == 0) { transpose(x, y); }
#endif
SPI_BUSY_CHECK;
#if defined (SSD1351_DRIVER)
if (rotation & 0x1) { transpose(x, y); }
// No need to send x if it has not changed (speeds things up)
if (addr_col != x) {
DC_C; tft_Write_8(TFT_CASET);
DC_D; tft_Write_16(x | (x << 8));
addr_col = x;
}
// No need to send y if it has not changed (speeds things up)
if (addr_row != y) {
DC_C; tft_Write_8(TFT_PASET);
DC_D; tft_Write_16(y | (y << 8));
addr_row = y;
}
#else
// No need to send x if it has not changed (speeds things up)
if (addr_col != x) {
DC_C; tft_Write_8(TFT_CASET);
DC_D; tft_Write_32D(x);
addr_col = x;
}
// No need to send y if it has not changed (speeds things up)
if (addr_row != y) {
DC_C; tft_Write_8(TFT_PASET);
DC_D; tft_Write_32D(y);
addr_row = y;
}
#endif
DC_C; tft_Write_8(TFT_RAMWR);
2022-04-22 01:44:10 +00:00
#if defined(TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT) || !defined(ESP32)
DC_D; tft_Write_16(color);
#else
DC_D; tft_Write_16N(color);
#endif
#endif
end_tft_write();
}
/***************************************************************************************
** Function name: pushColor
** Description: push a single pixel
***************************************************************************************/
void TFT_eSPI::pushColor(uint16_t color)
{
begin_tft_write();
SPI_BUSY_CHECK;
tft_Write_16N(color);
end_tft_write();
}
/***************************************************************************************
** Function name: pushColor
** Description: push a single colour to "len" pixels
***************************************************************************************/
void TFT_eSPI::pushColor(uint16_t color, uint32_t len)
{
begin_tft_write();
pushBlock(color, len);
end_tft_write();
}
/***************************************************************************************
** Function name: startWrite
** Description: begin transaction with CS low, MUST later call endWrite
***************************************************************************************/
void TFT_eSPI::startWrite(void)
{
begin_tft_write();
lockTransaction = true; // Lock transaction for all sequentially run sketch functions
inTransaction = true;
}
/***************************************************************************************
** Function name: endWrite
** Description: end transaction with CS high
***************************************************************************************/
void TFT_eSPI::endWrite(void)
{
lockTransaction = false; // Release sketch induced transaction lock
inTransaction = false;
DMA_BUSY_CHECK; // Safety check - user code should have checked this!
end_tft_write(); // Release SPI bus
}
/***************************************************************************************
** Function name: writeColor (use startWrite() and endWrite() before & after)
** Description: raw write of "len" pixels avoiding transaction check
***************************************************************************************/
void TFT_eSPI::writeColor(uint16_t color, uint32_t len)
{
pushBlock(color, len);
}
/***************************************************************************************
** Function name: pushColors
2023-12-07 20:35:59 +00:00
** Description: push an array of pixels for 16-bit raw image drawing
***************************************************************************************/
// Assumed that setAddrWindow() has previously been called
// len is number of bytes, not pixels
void TFT_eSPI::pushColors(uint8_t *data, uint32_t len)
{
begin_tft_write();
pushPixels(data, len>>1);
end_tft_write();
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
/***************************************************************************************
** Function name: pushColors
** Description: push an array of pixels, for image drawing
***************************************************************************************/
void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
{
begin_tft_write();
if (swap) {swap = _swapBytes; _swapBytes = true; }
2020-01-25 06:07:45 +00:00
pushPixels(data, len);
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
_swapBytes = swap; // Restore old value
end_tft_write();
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
}
/***************************************************************************************
** Function name: drawLine
** Description: draw a line between 2 arbitrary points
***************************************************************************************/
2023-12-07 20:35:59 +00:00
// Bresenham's algorithm - thx Wikipedia - speed enhanced by Bodmer to use
2018-02-22 22:33:49 +00:00
// an efficient FastH/V Line draw routine for line segments of 2 pixels or more
void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
{
if (_vpOoB) return;
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
inTransaction = true;
//x+= _xDatum; // Not added here, added by drawPixel & drawFastXLine
//y+= _yDatum;
bool steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
transpose(x0, y0);
transpose(x1, y1);
}
if (x0 > x1) {
transpose(x0, x1);
transpose(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) {
if (dlen == 1) drawPixel(y0, xs, color);
else drawFastVLine(y0, xs, dlen, color);
dlen = 0;
y0 += ystep; xs = x0 + 1;
err += dx;
}
}
if (dlen) drawFastVLine(y0, xs, dlen, color);
}
else
{
for (; x0 <= x1; x0++) {
dlen++;
err -= dy;
if (err < 0) {
if (dlen == 1) drawPixel(xs, y0, color);
else drawFastHLine(xs, y0, dlen, color);
dlen = 0;
y0 += ystep; xs = x0 + 1;
err += dx;
}
}
if (dlen) drawFastHLine(xs, y0, dlen, color);
}
inTransaction = lockTransaction;
end_tft_write();
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
/***************************************************************************************
** Description: Constants for anti-aliased line drawing on TFT and in Sprites
***************************************************************************************/
constexpr float PixelAlphaGain = 255.0;
constexpr float LoAlphaTheshold = 1.0/32.0;
constexpr float HiAlphaTheshold = 1.0 - LoAlphaTheshold;
constexpr float deg2rad = 3.14159265359/180.0;
/***************************************************************************************
** Function name: drawPixel (alpha blended)
** Description: Draw a pixel blended with the screen or bg pixel colour
***************************************************************************************/
uint16_t TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color)
{
if (bg_color == 0x00FFFFFF) bg_color = readPixel(x, y);
color = fastBlend(alpha, color, bg_color);
drawPixel(x, y, color);
return color;
}
/***************************************************************************************
** Function name: drawSmoothArc
** Description: Draw a smooth arc clockwise from 6 o'clock
***************************************************************************************/
void TFT_eSPI::drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, uint32_t startAngle, uint32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool roundEnds)
// Centre at x,y
// r = arc outer radius, ir = arc inner radius. Inclusive so arc thickness = r - ir + 1
// Angles in range 0-360
// Arc foreground colour anti-aliased with background colour at edges
// anti-aliased roundEnd is optional, default is anti-aliased straight end
// Note: rounded ends extend the arc angle so can overlap, user sketch to manage this.
{
inTransaction = true;
2023-01-14 22:40:17 +00:00
if (endAngle != startAngle && (startAngle != 0 || endAngle != 360))
{
float sx = -sinf(startAngle * deg2rad);
float sy = +cosf(startAngle * deg2rad);
float ex = -sinf( endAngle * deg2rad);
float ey = +cosf( endAngle * deg2rad);
if (roundEnds)
{ // Round ends
sx = sx * (r + ir)/2.0 + x;
sy = sy * (r + ir)/2.0 + y;
drawSpot(sx, sy, (r - ir)/2.0, fg_color, bg_color);
ex = ex * (r + ir)/2.0 + x;
ey = ey * (r + ir)/2.0 + y;
drawSpot(ex, ey, (r - ir)/2.0, fg_color, bg_color);
}
else
{ // Square ends
float asx = sx * ir + x;
float asy = sy * ir + y;
float aex = sx * r + x;
float aey = sy * r + y;
drawWedgeLine(asx, asy, aex, aey, 0.3, 0.3, fg_color, bg_color);
asx = ex * ir + x;
asy = ey * ir + y;
aex = ex * r + x;
aey = ey * r + y;
drawWedgeLine(asx, asy, aex, aey, 0.3, 0.3, fg_color, bg_color);
}
2023-01-14 22:40:17 +00:00
// Draw arc
drawArc(x, y, r, ir, startAngle, endAngle, fg_color, bg_color);
}
else // Draw full 360
{
drawArc(x, y, r, ir, 0, 360, fg_color, bg_color);
}
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
2023-01-14 22:40:17 +00:00
** Function name: sqrt_fraction (private function)
** Description: Smooth graphics support function for alpha derivation
***************************************************************************************/
// Compute the fixed point square root of an integer and
// return the 8 MS bits of fractional part.
// Quicker than sqrt() for processors that do not have an FPU (e.g. RP2040)
inline uint8_t TFT_eSPI::sqrt_fraction(uint32_t num) {
if (num > (0x40000000)) return 0;
uint32_t bsh = 0x00004000;
uint32_t fpr = 0;
uint32_t osh = 0;
// Auto adjust from U8:8 up to U15:16
while (num>bsh) {bsh <<= 2; osh++;}
do {
uint32_t bod = bsh + fpr;
if(num >= bod)
{
num -= bod;
fpr = bsh + bod;
}
num <<= 1;
} while(bsh >>= 1);
return fpr>>osh;
}
/***************************************************************************************
** Function name: drawArc
** Description: Draw an arc clockwise from 6 o'clock position
***************************************************************************************/
// Centre at x,y
// r = arc outer radius, ir = arc inner radius. Inclusive, so arc thickness = r-ir+1
2023-01-14 22:40:17 +00:00
// Angles MUST be in range 0-360
// Arc foreground fg_color anti-aliased with background colour along sides
// smooth is optional, default is true, smooth=false means no antialiasing
// Note: Arc ends are not anti-aliased (use drawSmoothArc instead for that)
void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir,
uint32_t startAngle, uint32_t endAngle,
uint32_t fg_color, uint32_t bg_color,
bool smooth)
{
if (endAngle > 360) endAngle = 360;
if (startAngle > 360) startAngle = 360;
2023-01-14 22:40:17 +00:00
if (_vpOoB || startAngle == endAngle) return;
if (r < ir) transpose(r, ir); // Required that r > ir
if (r <= 0 || ir < 0) return; // Invalid r, ir can be zero (circle sector)
if (endAngle < startAngle) {
// Arc sweeps through 6 o'clock so draw in two parts
if (startAngle < 360) drawArc(x, y, r, ir, startAngle, 360, fg_color, bg_color, smooth);
if (endAngle == 0) return;
startAngle = 0;
}
inTransaction = true;
int32_t xs = 0; // x start position for quadrant scan
uint8_t alpha = 0; // alpha value for blending pixels
uint32_t r2 = r * r; // Outer arc radius^2
if (smooth) r++; // Outer AA zone radius
uint32_t r1 = r * r; // Outer AA radius^2
int16_t w = r - ir; // Width of arc (r - ir + 1)
uint32_t r3 = ir * ir; // Inner arc radius^2
if (smooth) ir--; // Inner AA zone radius
uint32_t r4 = ir * ir; // Inner AA radius^2
// 1 | 2
// ---¦--- Arc quadrant index
// 0 | 3
// Fixed point U16.16 slope table for arc start/end in each quadrant
2023-01-14 22:40:17 +00:00
uint32_t startSlope[4] = {0, 0, 0xFFFFFFFF, 0};
uint32_t endSlope[4] = {0, 0xFFFFFFFF, 0, 0};
// Ensure maximum U16.16 slope of arc ends is ~ 0x8000 0000
constexpr float minDivisor = 1.0f/0x8000;
// Fill in start slope table and empty quadrants
float fabscos = fabsf(cosf(startAngle * deg2rad));
float fabssin = fabsf(sinf(startAngle * deg2rad));
// U16.16 slope of arc start
2023-12-07 20:35:59 +00:00
uint32_t slope = (fabscos/(fabssin + minDivisor)) * (float)(1UL<<16);
// Update slope table, add slope for arc start
if (startAngle <= 90) {
startSlope[0] = slope;
}
else if (startAngle <= 180) {
startSlope[1] = slope;
}
else if (startAngle <= 270) {
startSlope[1] = 0xFFFFFFFF;
startSlope[2] = slope;
}
else {
startSlope[1] = 0xFFFFFFFF;
startSlope[2] = 0;
startSlope[3] = slope;
}
// Fill in end slope table and empty quadrants
fabscos = fabsf(cosf(endAngle * deg2rad));
fabssin = fabsf(sinf(endAngle * deg2rad));
// U16.16 slope of arc end
2023-12-07 20:35:59 +00:00
slope = (uint32_t)((fabscos/(fabssin + minDivisor)) * (float)(1UL<<16));
// Work out which quadrants will need to be drawn and add slope for arc end
if (endAngle <= 90) {
endSlope[0] = slope;
endSlope[1] = 0;
startSlope[2] = 0;
}
else if (endAngle <= 180) {
endSlope[1] = slope;
startSlope[2] = 0;
}
else if (endAngle <= 270) {
endSlope[2] = slope;
}
else {
endSlope[3] = slope;
}
// Scan quadrant
for (int32_t cy = r - 1; cy > 0; cy--)
{
uint32_t len[4] = { 0, 0, 0, 0}; // Pixel run length
int32_t xst[4] = {-1, -1, -1, -1}; // Pixel run x start
uint32_t dy2 = (r - cy) * (r - cy);
// Find and track arc zone start point
while ((r - xs) * (r - xs) + dy2 >= r1) xs++;
for (int32_t cx = xs; cx < r; cx++)
{
// Calculate radius^2
uint32_t hyp = (r - cx) * (r - cx) + dy2;
// If in outer zone calculate alpha
if (hyp > r2) {
alpha = ~sqrt_fraction(hyp); // Outer AA zone
}
// If within arc fill zone, get line start and lengths for each quadrant
else if (hyp >= r3) {
// Calculate U16.16 slope
slope = ((r - cy) << 16)/(r - cx);
if (slope <= startSlope[0] && slope >= endSlope[0]) { // slope hi -> lo
xst[0] = cx; // Bottom left line end
len[0]++;
}
if (slope >= startSlope[1] && slope <= endSlope[1]) { // slope lo -> hi
xst[1] = cx; // Top left line end
len[1]++;
}
if (slope <= startSlope[2] && slope >= endSlope[2]) { // slope hi -> lo
xst[2] = cx; // Bottom right line start
len[2]++;
}
if (slope <= endSlope[3] && slope >= startSlope[3]) { // slope lo -> hi
xst[3] = cx; // Top right line start
len[3]++;
}
continue; // Next x
}
else {
if (hyp <= r4) break; // Skip inner pixels
alpha = sqrt_fraction(hyp); // Inner AA zone
}
if (alpha < 16) continue; // Skip low alpha pixels
// If background is read it must be done in each quadrant
uint16_t pcol = fastBlend(alpha, fg_color, bg_color);
// Check if an AA pixels need to be drawn
slope = ((r - cy)<<16)/(r - cx);
if (slope <= startSlope[0] && slope >= endSlope[0]) // BL
drawPixel(x + cx - r, y - cy + r, pcol);
if (slope >= startSlope[1] && slope <= endSlope[1]) // TL
drawPixel(x + cx - r, y + cy - r, pcol);
if (slope <= startSlope[2] && slope >= endSlope[2]) // TR
drawPixel(x - cx + r, y + cy - r, pcol);
if (slope <= endSlope[3] && slope >= startSlope[3]) // BR
drawPixel(x - cx + r, y - cy + r, pcol);
}
// Add line in inner zone
if (len[0]) drawFastHLine(x + xst[0] - len[0] + 1 - r, y - cy + r, len[0], fg_color); // BL
if (len[1]) drawFastHLine(x + xst[1] - len[1] + 1 - r, y + cy - r, len[1], fg_color); // TL
if (len[2]) drawFastHLine(x - xst[2] + r, y + cy - r, len[2], fg_color); // TR
if (len[3]) drawFastHLine(x - xst[3] + r, y - cy + r, len[3], fg_color); // BR
}
// Fill in centre lines
if (startAngle == 0 || endAngle == 360) drawFastVLine(x, y + r - w, w, fg_color); // Bottom
if (startAngle <= 90 && endAngle >= 90) drawFastHLine(x - r + 1, y, w, fg_color); // Left
if (startAngle <= 180 && endAngle >= 180) drawFastVLine(x, y - r + 1, w, fg_color); // Top
if (startAngle <= 270 && endAngle >= 270) drawFastHLine(x + r - w, y, w, fg_color); // Right
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: drawSmoothCircle
** Description: Draw a smooth circle
***************************************************************************************/
// To have effective anti-aliasing the circle will be 3 pixels thick
void TFT_eSPI::drawSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t fg_color, uint32_t bg_color)
{
drawSmoothRoundRect(x-r, y-r, r, r-1, 0, 0, fg_color, bg_color);
}
/***************************************************************************************
** Function name: fillSmoothCircle
** Description: Draw a filled anti-aliased circle
***************************************************************************************/
void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color)
{
if (r <= 0) return;
inTransaction = true;
drawFastHLine(x - r, y, 2 * r + 1, color);
int32_t xs = 1;
int32_t cx = 0;
int32_t r1 = r * r;
r++;
int32_t r2 = r * r;
for (int32_t cy = r - 1; cy > 0; cy--)
{
int32_t dy2 = (r - cy) * (r - cy);
for (cx = xs; cx < r; cx++)
{
int32_t hyp2 = (r - cx) * (r - cx) + dy2;
if (hyp2 <= r1) break;
if (hyp2 >= r2) continue;
uint8_t alpha = ~sqrt_fraction(hyp2);
if (alpha > 246) break;
xs = cx;
if (alpha < 9) continue;
if (bg_color == 0x00FFFFFF) {
drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
drawPixel(x - cx + r, y + cy - r, color, alpha, bg_color);
drawPixel(x - cx + r, y - cy + r, color, alpha, bg_color);
drawPixel(x + cx - r, y - cy + r, color, alpha, bg_color);
}
else {
uint16_t pcol = drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
drawPixel(x - cx + r, y + cy - r, pcol);
drawPixel(x - cx + r, y - cy + r, pcol);
drawPixel(x + cx - r, y - cy + r, pcol);
}
}
drawFastHLine(x + cx - r, y + cy - r, 2 * (r - cx) + 1, color);
drawFastHLine(x + cx - r, y - cy + r, 2 * (r - cx) + 1, color);
}
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: drawSmoothRoundRect
** Description: Draw a rounded rectangle
***************************************************************************************/
// x,y is top left corner of bounding box for a complete rounded rectangle
// r = arc outer corner radius, ir = arc inner radius. Arc thickness = r-ir+1
// w and h are width and height of the bounding rectangle
// If w and h are < radius (e.g. 0,0) a circle will be drawn with centre at x+r,y+r
// Arc foreground fg_color anti-aliased with background colour at edges
// A subset of corners can be drawn by specifying a quadrants mask. A bit set in the
// mask means draw that quadrant (all are drawn if parameter missing):
// 0x1 | 0x2
// ---¦--- Arc quadrant mask select bits (as in drawCircleHelper fn)
// 0x8 | 0x4
void TFT_eSPI::drawSmoothRoundRect(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t w, int32_t h, uint32_t fg_color, uint32_t bg_color, uint8_t quadrants)
{
if (_vpOoB) return;
if (r < ir) transpose(r, ir); // Required that r > ir
if (r <= 0 || ir < 0) return; // Invalid
w -= 2*r;
h -= 2*r;
if (w < 0) w = 0;
if (h < 0) h = 0;
inTransaction = true;
x += r;
y += r;
uint16_t t = r - ir + 1;
int32_t xs = 0;
int32_t cx = 0;
int32_t r2 = r * r; // Outer arc radius^2
r++;
int32_t r1 = r * r; // Outer AA zone radius^2
int32_t r3 = ir * ir; // Inner arc radius^2
ir--;
int32_t r4 = ir * ir; // Inner AA zone radius^2
uint8_t alpha = 0;
// Scan top left quadrant x y r ir fg_color bg_color
for (int32_t cy = r - 1; cy > 0; cy--)
{
int32_t len = 0; // Pixel run length
int32_t lxst = 0; // Left side run x start
int32_t rxst = 0; // Right side run x start
int32_t dy2 = (r - cy) * (r - cy);
// Find and track arc zone start point
while ((r - xs) * (r - xs) + dy2 >= r1) xs++;
for (cx = xs; cx < r; cx++)
{
// Calculate radius^2
int32_t hyp = (r - cx) * (r - cx) + dy2;
// If in outer zone calculate alpha
if (hyp > r2) {
alpha = ~sqrt_fraction(hyp); // Outer AA zone
}
// If within arc fill zone, get line lengths for each quadrant
else if (hyp >= r3) {
rxst = cx; // Right side start
len++; // Line segment length
continue; // Next x
}
else {
if (hyp <= r4) break; // Skip inner pixels
alpha = sqrt_fraction(hyp); // Inner AA zone
}
if (alpha < 16) continue; // Skip low alpha pixels
// If background is read it must be done in each quadrant - TODO
uint16_t pcol = fastBlend(alpha, fg_color, bg_color);
if (quadrants & 0x8) drawPixel(x + cx - r, y - cy + r + h, pcol); // BL
if (quadrants & 0x1) drawPixel(x + cx - r, y + cy - r, pcol); // TL
if (quadrants & 0x2) drawPixel(x - cx + r + w, y + cy - r, pcol); // TR
if (quadrants & 0x4) drawPixel(x - cx + r + w, y - cy + r + h, pcol); // BR
}
// Fill arc inner zone in each quadrant
lxst = rxst - len + 1; // Calculate line segment start for left side
if (quadrants & 0x8) drawFastHLine(x + lxst - r, y - cy + r + h, len, fg_color); // BL
if (quadrants & 0x1) drawFastHLine(x + lxst - r, y + cy - r, len, fg_color); // TL
if (quadrants & 0x2) drawFastHLine(x - rxst + r + w, y + cy - r, len, fg_color); // TR
if (quadrants & 0x4) drawFastHLine(x - rxst + r + w, y - cy + r + h, len, fg_color); // BR
}
// Draw sides
if ((quadrants & 0xC) == 0xC) fillRect(x, y + r - t + h, w + 1, t, fg_color); // Bottom
if ((quadrants & 0x9) == 0x9) fillRect(x - r + 1, y, t, h + 1, fg_color); // Left
if ((quadrants & 0x3) == 0x3) fillRect(x, y - r + 1, w + 1, t, fg_color); // Top
if ((quadrants & 0x6) == 0x6) fillRect(x + r - t + w, y, t, h + 1, fg_color); // Right
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: fillSmoothRoundRect
** Description: Draw a filled anti-aliased rounded corner rectangle
***************************************************************************************/
void TFT_eSPI::fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color, uint32_t bg_color)
{
inTransaction = true;
int32_t xs = 0;
int32_t cx = 0;
// Limit radius to half width or height
if (r < 0) r = 0;
if (r > w/2) r = w/2;
if (r > h/2) r = h/2;
y += r;
h -= 2*r;
fillRect(x, y, w, h, color);
h--;
x += r;
w -= 2*r+1;
int32_t r1 = r * r;
r++;
int32_t r2 = r * r;
for (int32_t cy = r - 1; cy > 0; cy--)
{
int32_t dy2 = (r - cy) * (r - cy);
for (cx = xs; cx < r; cx++)
{
int32_t hyp2 = (r - cx) * (r - cx) + dy2;
if (hyp2 <= r1) break;
if (hyp2 >= r2) continue;
uint8_t alpha = ~sqrt_fraction(hyp2);
if (alpha > 246) break;
xs = cx;
if (alpha < 9) continue;
drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
drawPixel(x - cx + r + w, y + cy - r, color, alpha, bg_color);
drawPixel(x - cx + r + w, y - cy + r + h, color, alpha, bg_color);
drawPixel(x + cx - r, y - cy + r + h, color, alpha, bg_color);
}
drawFastHLine(x + cx - r, y + cy - r, 2 * (r - cx) + 1 + w, color);
drawFastHLine(x + cx - r, y - cy + r + h, 2 * (r - cx) + 1 + w, color);
}
inTransaction = lockTransaction;
end_tft_write();
}
/***************************************************************************************
** Function name: drawSpot - maths intensive, so for small filled circles
** Description: Draw an anti-aliased filled circle at ax,ay with radius r
***************************************************************************************/
// Coordinates are floating point to achieve sub-pixel positioning
void TFT_eSPI::drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color)
{
// Filled circle can be created by the wide line function with zero line length
drawWedgeLine( ax, ay, ax, ay, r, r, fg_color, bg_color);
}
/***************************************************************************************
** Function name: drawWideLine - background colour specified or pixel read
** Description: draw an anti-aliased line with rounded ends, width wd
***************************************************************************************/
void TFT_eSPI::drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color)
{
drawWedgeLine( ax, ay, bx, by, wd/2.0, wd/2.0, fg_color, bg_color);
}
/***************************************************************************************
** Function name: drawWedgeLine - background colour specified or pixel read
** Description: draw an anti-aliased line with different width radiused ends
***************************************************************************************/
void TFT_eSPI::drawWedgeLine(float ax, float ay, float bx, float by, float ar, float br, uint32_t fg_color, uint32_t bg_color)
{
2022-10-10 18:02:05 +00:00
if ( (ar < 0.0) || (br < 0.0) )return;
if ( (fabsf(ax - bx) < 0.01f) && (fabsf(ay - by) < 0.01f) ) bx += 0.01f; // Avoid divide by zero
// Find line bounding box
int32_t x0 = (int32_t)floorf(fminf(ax-ar, bx-br));
int32_t x1 = (int32_t) ceilf(fmaxf(ax+ar, bx+br));
int32_t y0 = (int32_t)floorf(fminf(ay-ar, by-br));
int32_t y1 = (int32_t) ceilf(fmaxf(ay+ar, by+br));
if (!clipWindow(&x0, &y0, &x1, &y1)) return;
// Establish x start and y start
int32_t ys = ay;
if ((ax-ar)>(bx-br)) ys = by;
float rdt = ar - br; // Radius delta
float alpha = 1.0f;
ar += 0.5;
uint16_t bg = bg_color;
float xpax, ypay, bax = bx - ax, bay = by - ay;
begin_nin_write();
inTransaction = true;
int32_t xs = x0;
// Scan bounding box from ys down, calculate pixel intensity from distance to line
for (int32_t yp = ys; yp <= y1; yp++) {
bool swin = true; // Flag to start new window area
bool endX = false; // Flag to skip pixels
ypay = yp - ay;
for (int32_t xp = xs; xp <= x1; xp++) {
if (endX) if (alpha <= LoAlphaTheshold) break; // Skip right side
xpax = xp - ax;
alpha = ar - wedgeLineDistance(xpax, ypay, bax, bay, rdt);
if (alpha <= LoAlphaTheshold ) continue;
// Track edge to minimise calculations
if (!endX) { endX = true; xs = xp; }
if (alpha > HiAlphaTheshold) {
#ifdef GC9A01_DRIVER
drawPixel(xp, yp, fg_color);
#else
if (swin) { setWindow(xp, yp, x1, yp); swin = false; }
pushColor(fg_color);
#endif
continue;
}
//Blend color with background and plot
if (bg_color == 0x00FFFFFF) {
bg = readPixel(xp, yp); swin = true;
}
#ifdef GC9A01_DRIVER
uint16_t pcol = fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg);
2023-02-13 01:39:33 +00:00
drawPixel(xp, yp, pcol);
2023-07-03 11:36:27 +00:00
swin = swin;
#else
if (swin) { setWindow(xp, yp, x1, yp); swin = false; }
pushColor(fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg));
#endif
}
}
// Reset x start to left side of box
xs = x0;
// Scan bounding box from ys-1 up, calculate pixel intensity from distance to line
for (int32_t yp = ys-1; yp >= y0; yp--) {
bool swin = true; // Flag to start new window area
bool endX = false; // Flag to skip pixels
ypay = yp - ay;
for (int32_t xp = xs; xp <= x1; xp++) {
if (endX) if (alpha <= LoAlphaTheshold) break; // Skip right side of drawn line
xpax = xp - ax;
alpha = ar - wedgeLineDistance(xpax, ypay, bax, bay, rdt);
if (alpha <= LoAlphaTheshold ) continue;
// Track line boundary
if (!endX) { endX = true; xs = xp; }
if (alpha > HiAlphaTheshold) {
#ifdef GC9A01_DRIVER
drawPixel(xp, yp, fg_color);
#else
if (swin) { setWindow(xp, yp, x1, yp); swin = false; }
pushColor(fg_color);
#endif
continue;
}
//Blend colour with background and plot
if (bg_color == 0x00FFFFFF) {
bg = readPixel(xp, yp); swin = true;
}
#ifdef GC9A01_DRIVER
uint16_t pcol = fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg);
2023-02-13 01:39:33 +00:00
drawPixel(xp, yp, pcol);
2023-07-03 11:36:27 +00:00
swin = swin;
#else
if (swin) { setWindow(xp, yp, x1, yp); swin = false; }
pushColor(fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg));
#endif
}
}
inTransaction = lockTransaction;
end_nin_write();
}
/***************************************************************************************
** Function name: lineDistance - private helper function for drawWedgeLine
** Description: returns distance of px,py to closest part of a to b wedge
***************************************************************************************/
inline float TFT_eSPI::wedgeLineDistance(float xpax, float ypay, float bax, float bay, float dr)
{
float h = fmaxf(fminf((xpax * bax + ypay * bay) / (bax * bax + bay * bay), 1.0f), 0.0f);
float dx = xpax - bax * h, dy = ypay - bay * h;
return sqrtf(dx * dx + dy * dy) + h * dr;
}
/***************************************************************************************
** Function name: drawFastVLine
** Description: draw a vertical line
***************************************************************************************/
void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB) return;
x+= _xDatum;
y+= _yDatum;
// Clipping
if ((x < _vpX) || (x >= _vpW) || (y >= _vpH)) return;
if (y < _vpY) { h += y - _vpY; y = _vpY; }
if ((y + h) > _vpH) h = _vpH - y;
if (h < 1) return;
begin_tft_write();
setWindow(x, y, x, y + h - 1);
pushBlock(color, h);
2020-01-25 06:07:45 +00:00
end_tft_write();
}
/***************************************************************************************
** Function name: drawFastHLine
** Description: draw a horizontal line
***************************************************************************************/
void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB) return;
x+= _xDatum;
y+= _yDatum;
// Clipping
if ((y < _vpY) || (x >= _vpW) || (y >= _vpH)) return;
if (x < _vpX) { w += x - _vpX; x = _vpX; }
if ((x + w) > _vpW) w = _vpW - x;
if (w < 1) return;
begin_tft_write();
setWindow(x, y, x + w - 1, y);
pushBlock(color, w);
2020-01-25 06:07:45 +00:00
end_tft_write();
}
/***************************************************************************************
** Function name: fillRect
** Description: draw a filled rectangle
***************************************************************************************/
2018-01-27 02:35:25 +00:00
void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB) return;
x+= _xDatum;
y+= _yDatum;
// Clipping
if ((x >= _vpW) || (y >= _vpH)) return;
2020-01-25 06:07:45 +00:00
if (x < _vpX) { w += x - _vpX; x = _vpX; }
if (y < _vpY) { h += y - _vpY; y = _vpY; }
if ((x + w) > _vpW) w = _vpW - x;
if ((y + h) > _vpH) h = _vpH - y;
if ((w < 1) || (h < 1)) return;
2020-10-11 21:36:02 +00:00
//Serial.print(" _xDatum=");Serial.print( _xDatum);Serial.print(", _yDatum=");Serial.print( _yDatum);
//Serial.print(", _xWidth=");Serial.print(_xWidth);Serial.print(", _yHeight=");Serial.println(_yHeight);
//Serial.print(" _vpX=");Serial.print( _vpX);Serial.print(", _vpY=");Serial.print( _vpY);
//Serial.print(", _vpW=");Serial.print(_vpW);Serial.print(", _vpH=");Serial.println(_vpH);
//Serial.print(" x=");Serial.print( y);Serial.print(", y=");Serial.print( y);
//Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h);
begin_tft_write();
setWindow(x, y, x + w - 1, y + h - 1);
pushBlock(color, w * h);
end_tft_write();
}
2022-01-08 20:01:42 +00:00
/***************************************************************************************
** Function name: fillRectVGradient
** Description: draw a filled rectangle with a vertical colour gradient
***************************************************************************************/
void TFT_eSPI::fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2)
{
if (_vpOoB) return;
x+= _xDatum;
y+= _yDatum;
// Clipping
if ((x >= _vpW) || (y >= _vpH)) return;
if (x < _vpX) { w += x - _vpX; x = _vpX; }
if (y < _vpY) { h += y - _vpY; y = _vpY; }
if ((x + w) > _vpW) w = _vpW - x;
if ((y + h) > _vpH) h = _vpH - y;
if ((w < 1) || (h < 1)) return;
begin_nin_write();
2022-01-08 20:01:42 +00:00
float delta = -255.0/h;
float alpha = 255.0;
uint32_t color = color1;
while (h--) {
drawFastHLine(x, y++, w, color);
2022-01-08 20:01:42 +00:00
alpha += delta;
color = fastBlend((uint8_t)alpha, color1, color2);
2022-01-08 20:01:42 +00:00
}
end_nin_write();
2022-01-08 20:01:42 +00:00
}
/***************************************************************************************
** Function name: fillRectHGradient
** Description: draw a filled rectangle with a horizontal colour gradient
***************************************************************************************/
void TFT_eSPI::fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2)
{
if (_vpOoB) return;
x+= _xDatum;
y+= _yDatum;
// Clipping
if ((x >= _vpW) || (y >= _vpH)) return;
if (x < _vpX) { w += x - _vpX; x = _vpX; }
if (y < _vpY) { h += y - _vpY; y = _vpY; }
if ((x + w) > _vpW) w = _vpW - x;
if ((y + h) > _vpH) h = _vpH - y;
if ((w < 1) || (h < 1)) return;
begin_nin_write();
2022-01-08 20:01:42 +00:00
float delta = -255.0/w;
float alpha = 255.0;
uint32_t color = color1;
while (w--) {
drawFastVLine(x++, y, h, color);
alpha += delta;
color = fastBlend((uint8_t)alpha, color1, color2);
2022-01-08 20:01:42 +00:00
}
end_nin_write();
2022-01-08 20:01:42 +00:00
}
/***************************************************************************************
** Function name: color565
2023-12-07 20:35:59 +00:00
** Description: convert three 8-bit RGB levels to a 16-bit colour value
***************************************************************************************/
uint16_t TFT_eSPI::color565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
/***************************************************************************************
2018-02-24 19:02:20 +00:00
** Function name: color16to8
2023-12-07 20:35:59 +00:00
** Description: convert 16-bit colour to an 8-bit 332 RGB colour value
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
***************************************************************************************/
2018-02-24 19:02:20 +00:00
uint8_t TFT_eSPI::color16to8(uint16_t c)
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
{
return ((c & 0xE000)>>8) | ((c & 0x0700)>>6) | ((c & 0x0018)>>3);
}
2018-02-24 19:02:20 +00:00
/***************************************************************************************
** Function name: color8to16
2023-12-07 20:35:59 +00:00
** Description: convert 8-bit colour to a 16-bit 565 colour value
2018-02-24 19:02:20 +00:00
***************************************************************************************/
uint16_t TFT_eSPI::color8to16(uint8_t color)
{
2023-12-07 20:35:59 +00:00
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5-bit colour lookup table
2018-02-24 19:02:20 +00:00
uint16_t color16 = 0;
// =====Green===== ===============Red==============
color16 = (color & 0x1C)<<6 | (color & 0xC0)<<5 | (color & 0xE0)<<8;
// =====Green===== =======Blue======
color16 |= (color & 0x1C)<<3 | blue[color & 0x03];
return color16;
}
/***************************************************************************************
** Function name: color16to24
2023-12-07 20:35:59 +00:00
** Description: convert 16-bit colour to a 24-bit 888 colour value
***************************************************************************************/
uint32_t TFT_eSPI::color16to24(uint16_t color565)
{
uint8_t r = (color565 >> 8) & 0xF8; r |= (r >> 5);
uint8_t g = (color565 >> 3) & 0xFC; g |= (g >> 6);
uint8_t b = (color565 << 3) & 0xF8; b |= (b >> 5);
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b << 0);
}
/***************************************************************************************
** Function name: color24to16
2023-12-07 20:35:59 +00:00
** Description: convert 24-bit colour to a 16-bit 565 colour value
***************************************************************************************/
uint32_t TFT_eSPI::color24to16(uint32_t color888)
{
uint16_t r = (color888 >> 8) & 0xF800;
uint16_t g = (color888 >> 5) & 0x07E0;
uint16_t b = (color888 >> 3) & 0x001F;
return (r | g | b);
}
2018-02-24 19:02:20 +00:00
/***************************************************************************************
** Function name: invertDisplay
** Description: invert the display colours i = 1 invert, i = 0 normal
***************************************************************************************/
void TFT_eSPI::invertDisplay(bool i)
{
begin_tft_write();
// Send the command twice as otherwise it does not always work!
writecommand(i ? TFT_INVON : TFT_INVOFF);
writecommand(i ? TFT_INVON : TFT_INVOFF);
end_tft_write();
}
/**************************************************************************
** Function name: setAttribute
** Description: Sets a control parameter of an attribute
**************************************************************************/
void TFT_eSPI::setAttribute(uint8_t attr_id, uint8_t param) {
switch (attr_id) {
break;
case CP437_SWITCH:
_cp437 = param;
break;
case UTF8_SWITCH:
_utf8 = param;
decoderState = 0;
break;
case PSRAM_ENABLE:
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
if (psramFound()) _psram_enable = param; // Enable the use of PSRAM (if available)
else
#endif
_psram_enable = false;
break;
//case 4: // TBD future feature control
// _tbd = param;
// break;
}
}
/**************************************************************************
** Function name: getAttribute
** Description: Get value of an attribute (control parameter)
**************************************************************************/
uint8_t TFT_eSPI::getAttribute(uint8_t attr_id) {
switch (attr_id) {
case CP437_SWITCH: // ON/OFF control of full CP437 character set
return _cp437;
case UTF8_SWITCH: // ON/OFF control of UTF-8 decoding
return _utf8;
case PSRAM_ENABLE:
return _psram_enable;
//case 3: // TBD future feature control
// return _tbd;
// break;
}
return false;
}
/***************************************************************************************
** Function name: decodeUTF8
** Description: Serial UTF-8 decoder with fall-back to extended ASCII
*************************************************************************************x*/
uint16_t TFT_eSPI::decodeUTF8(uint8_t c)
{
2021-04-23 15:51:18 +00:00
if (!_utf8) return c;
2023-12-07 20:35:59 +00:00
// 7-bit Unicode Code Point
if ((c & 0x80) == 0x00) {
decoderState = 0;
2021-04-23 15:51:18 +00:00
return c;
}
if (decoderState == 0) {
2023-12-07 20:35:59 +00:00
// 11-bit Unicode Code Point
if ((c & 0xE0) == 0xC0) {
decoderBuffer = ((c & 0x1F)<<6);
decoderState = 1;
return 0;
}
2023-12-07 20:35:59 +00:00
// 16-bit Unicode Code Point
if ((c & 0xF0) == 0xE0) {
decoderBuffer = ((c & 0x0F)<<12);
decoderState = 2;
return 0;
}
2023-12-07 20:35:59 +00:00
// 21-bit Unicode Code Point not supported so fall-back to extended ASCII
2021-04-23 15:51:18 +00:00
// if ((c & 0xF8) == 0xF0) return c;
}
else {
if (decoderState == 2) {
decoderBuffer |= ((c & 0x3F)<<6);
decoderState--;
return 0;
}
else {
decoderBuffer |= (c & 0x3F);
decoderState = 0;
return decoderBuffer;
}
}
decoderState = 0;
2021-04-23 15:51:18 +00:00
return c; // fall-back to extended ASCII
}
/***************************************************************************************
** Function name: decodeUTF8
** Description: Line buffer UTF-8 decoder with fall-back to extended ASCII
*************************************************************************************x*/
uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining)
{
2019-02-22 00:13:40 +00:00
uint16_t c = buf[(*index)++];
//Serial.print("Byte from string = 0x"); Serial.println(c, HEX);
2021-04-23 15:51:18 +00:00
if (!_utf8) return c;
2023-12-07 20:35:59 +00:00
// 7-bit Unicode
if ((c & 0x80) == 0x00) return c;
2023-12-07 20:35:59 +00:00
// 11-bit Unicode
if (((c & 0xE0) == 0xC0) && (remaining > 1))
return ((c & 0x1F)<<6) | (buf[(*index)++]&0x3F);
2023-12-07 20:35:59 +00:00
// 16-bit Unicode
if (((c & 0xF0) == 0xE0) && (remaining > 2)) {
c = ((c & 0x0F)<<12) | ((buf[(*index)++]&0x3F)<<6);
return c | ((buf[(*index)++]&0x3F));
}
2023-12-07 20:35:59 +00:00
// 21-bit Unicode not supported so fall-back to extended ASCII
// if (((c & 0xF8) == 0xF0) && (remaining > 3)) {
// c = ((c & 0x07) << 18) | ((buf[(*index)++] & 0x03F) << 12);
// c |= ((buf[(*index)++] & 0x3F) << 6);
// return c | ((buf[(*index)++] & 0x3F));
return c; // fall-back to extended ASCII
}
/***************************************************************************************
** Function name: alphaBlend
** Description: Blend 16bit foreground and background
*************************************************************************************x*/
2023-06-30 13:15:05 +00:00
uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc)
{
2023-12-07 20:35:59 +00:00
// Split out and blend 5-bit red and blue channels
uint32_t rxb = bgc & 0xF81F;
rxb += ((fgc & 0xF81F) - rxb) * (alpha >> 2) >> 6;
2023-12-07 20:35:59 +00:00
// Split out and blend 6-bit green channel
uint32_t xgx = bgc & 0x07E0;
xgx += ((fgc & 0x07E0) - xgx) * alpha >> 8;
// Recombine channels
return (rxb & 0xF81F) | (xgx & 0x07E0);
}
/***************************************************************************************
** Function name: alphaBlend
** Description: Blend 16bit foreground and background with dither
*************************************************************************************x*/
uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc, uint8_t dither)
{
if (dither) {
int16_t alphaDither = (int16_t)alpha - dither + random(2*dither+1); // +/-4 randomised
alpha = (uint8_t)alphaDither;
if (alphaDither < 0) alpha = 0;
if (alphaDither >255) alpha = 255;
}
return alphaBlend(alpha, fgc, bgc);
}
/***************************************************************************************
** Function name: alphaBlend
** Description: Blend 24bit foreground and background with optional dither
*************************************************************************************x*/
uint32_t TFT_eSPI::alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8_t dither)
{
if (dither) {
int16_t alphaDither = (int16_t)alpha - dither + random(2*dither+1); // +/-dither randomised
alpha = (uint8_t)alphaDither;
if (alphaDither < 0) alpha = 0;
if (alphaDither >255) alpha = 255;
}
uint32_t rxx = bgc & 0xFF0000;
rxx += ((fgc & 0xFF0000) - rxx) * alpha >> 8;
uint32_t xgx = bgc & 0x00FF00;
2023-09-01 01:02:01 +00:00
xgx += ((fgc & 0x00FF00) - xgx) * alpha >> 8;
uint32_t xxb = bgc & 0x0000FF;
2023-09-01 01:02:01 +00:00
xxb += ((fgc & 0x0000FF) - xxb) * alpha >> 8;
return (rxx & 0xFF0000) | (xgx & 0x00FF00) | (xxb & 0x0000FF);
}
/***************************************************************************************
** Function name: write
** Description: draw characters piped through serial stream
***************************************************************************************/
/* // Not all processors support buffered write
#ifndef ARDUINO_ARCH_ESP8266 // Avoid ESP8266 board package bug
size_t TFT_eSPI::write(const uint8_t *buf, size_t len)
{
inTransaction = true;
uint8_t *lbuf = (uint8_t *)buf;
while(*lbuf !=0 && len--) write(*lbuf++);
inTransaction = lockTransaction;
end_tft_write();
return 1;
}
#endif
*/
/***************************************************************************************
** Function name: write
** Description: draw characters piped through serial stream
***************************************************************************************/
size_t TFT_eSPI::write(uint8_t utf8)
{
if (_vpOoB) return 1;
uint16_t uniCode = decodeUTF8(utf8);
if (!uniCode) return 1;
if (utf8 == '\r') return 1;
2018-02-24 19:02:20 +00:00
#ifdef SMOOTH_FONT
if(fontLoaded) {
if (uniCode < 32 && utf8 != '\n') return 1;
2018-02-24 19:02:20 +00:00
drawGlyph(uniCode);
2018-02-24 19:02:20 +00:00
return 1;
}
#endif
if (uniCode == '\n') uniCode+=22; // Make it a valid space character to stop errors
uint16_t cwidth = 0;
uint16_t cheight = 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) {
2023-02-15 16:57:55 +00:00
if (uniCode < 32 || uniCode > 127) return 1;
cwidth = pgm_read_byte(widtbl_f16 + uniCode-32);
cheight = chr_hgt_f16;
// Font 2 is rendered in whole byte widths so we must allow for this
cwidth = (cwidth + 6) / 8; // Width in whole bytes for font 2, should be + 7 but must allow for font width change
cwidth = cwidth * 8; // Width converted back to pixels
}
#ifdef LOAD_RLE
else
#endif
#endif
#ifdef LOAD_RLE
{
if ((textfont>2) && (textfont<9)) {
2023-02-15 16:57:55 +00:00
if (uniCode < 32 || uniCode > 127) return 1;
// Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
cwidth = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
cheight= pgm_read_byte( &fontdata[textfont].height );
}
}
#endif
#ifdef LOAD_GLCD
if (textfont==1) {
cwidth = 6;
cheight = 8;
}
#else
if (textfont==1) return 1;
#endif
cheight = cheight * textsize;
if (utf8 == '\n') {
cursor_y += cheight;
cursor_x = 0;
}
else {
if (textwrapX && (cursor_x + cwidth * textsize > width())) {
cursor_y += cheight;
cursor_x = 0;
}
if (textwrapY && (cursor_y >= (int32_t) height())) cursor_y = 0;
cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont);
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#ifdef LOAD_GFXFF
} // Custom GFX font
else {
if(utf8 == '\n') {
cursor_x = 0;
cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else {
if (uniCode > pgm_read_word(&gfxFont->last )) return 1;
if (uniCode < pgm_read_word(&gfxFont->first)) return 1;
uint16_t c2 = uniCode - pgm_read_word(&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(textwrapX && ((cursor_x + textsize * (xo + w)) > width())) {
// Drawing character would go off right edge; wrap to new line
cursor_x = 0;
cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
if (textwrapY && (cursor_y >= (int32_t) height())) cursor_y = 0;
drawChar(cursor_x, cursor_y, uniCode, textcolor, textbgcolor, textsize);
}
cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
}
}
#endif // LOAD_GFXFF
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return 1;
}
/***************************************************************************************
** Function name: drawChar
** Description: draw a Unicode glyph onto the screen
***************************************************************************************/
// TODO: Rationalise with TFT_eSprite
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y)
{
return drawChar(uniCode, x, y, textfont);
}
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
{
2020-10-11 21:36:02 +00:00
if (_vpOoB || !uniCode) return 0;
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_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last) )) {
uint16_t c2 = uniCode - pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
return pgm_read_byte(&glyph->xAdvance) * textsize;
}
else {
return 0;
}
}
#endif
}
if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0;
int32_t width = 0;
int32_t height = 0;
uint32_t flash_address = 0;
uniCode -= 32;
#ifdef LOAD_FONT2
if (font == 2) {
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)) {
flash_address = pgm_read_dword( (const void*)(pgm_read_dword( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *)) );
2017-05-01 22:42:17 +00:00
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[font].widthtbl ) ) + uniCode );
height= pgm_read_byte( &fontdata[font].height );
}
}
#endif
2020-10-11 21:36:02 +00:00
int32_t xd = x + _xDatum;
int32_t yd = y + _yDatum;
if ((xd + width * textsize < _vpX || xd >= _vpW) && (yd + height * textsize < _vpY || yd >= _vpH)) return width * textsize ;
int32_t w = width;
int32_t pX = 0;
int32_t pY = y;
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t line = 0;
2020-10-11 21:36:02 +00:00
bool clip = xd < _vpX || xd + width * textsize >= _vpW || yd < _vpY || yd + height * textsize >= _vpH;
#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;
2020-10-11 21:36:02 +00:00
if (textcolor == textbgcolor || textsize != 1 || clip) {
//begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write()
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = true;
for (int32_t i = 0; i < height; i++) {
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize, textbgcolor);
for (int32_t k = 0; k < w; k++) {
2017-05-01 22:42:17 +00:00
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;
}
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
inTransaction = lockTransaction;
end_tft_write();
}
else { // Faster drawing of characters and background using block write
2020-10-11 21:36:02 +00:00
begin_tft_write();
2020-10-11 21:36:02 +00:00
setWindow(xd, yd, xd + width - 1, yd + height - 1);
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t mask;
for (int32_t i = 0; i < height; i++) {
pX = width;
for (int32_t k = 0; k < w; k++) {
line = pgm_read_byte((uint8_t *) (flash_address + w * i + k) );
mask = 0x80;
while (mask && pX) {
if (line & mask) {tft_Write_16(textcolor);}
else {tft_Write_16(textbgcolor);}
pX--;
mask = mask >> 1;
}
}
if (pX) {tft_Write_16(textbgcolor);}
}
end_tft_write();
}
}
#ifdef LOAD_RLE
else
#endif
#endif //FONT2
#ifdef LOAD_RLE //674 bytes of code
// Font is not 2 and hence is RLE encoded
{
begin_tft_write();
inTransaction = true;
w *= height; // Now w is total number of pixels in the character
2020-10-11 21:36:02 +00:00
if (textcolor == textbgcolor && !clip) {
int32_t px = 0, py = pY; // To hold character block start and end column and row values
int32_t pc = 0; // Pixel count
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t tnp = 0; // Temporary copy of np for while loop
uint8_t ts = textsize - 1; // Temporary copy of textsize
2023-12-07 20:35:59 +00:00
// 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) {
2017-05-01 22:42:17 +00:00
line = pgm_read_byte((uint8_t *)flash_address);
2018-02-24 19:02:20 +00:00
flash_address++;
if (line & 0x80) {
line &= 0x7F;
line++;
if (ts) {
2020-10-11 21:36:02 +00:00
px = xd + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow
py = yd + textsize * (pc / width);
}
else {
2020-10-11 21:36:02 +00:00
px = xd + pc % width; // Keep these px and py calculations outside the loop as they are slow
py = yd + pc / width;
}
while (line--) { // In this case the while(line--) is faster
pc++; // This is faster than putting pc+=line before while()?
setWindow(px, py, px + ts, py + ts);
if (ts) {
tnp = np;
while (tnp--) {tft_Write_16(textcolor);}
}
else {tft_Write_16(textcolor);}
px += textsize;
2020-10-11 21:36:02 +00:00
if (px >= (xd + width * textsize)) {
px = xd;
py += textsize;
}
}
}
else {
line++;
pc += line;
}
}
}
2020-06-11 21:34:22 +00:00
else {
2020-10-11 21:36:02 +00:00
// Text colour != background and textsize = 1 and character is within viewport area
2020-06-11 21:34:22 +00:00
// so use faster drawing of characters and background using block write
2020-10-11 21:36:02 +00:00
if (textcolor != textbgcolor && textsize == 1 && !clip)
2020-06-11 21:34:22 +00:00
{
2020-10-11 21:36:02 +00:00
setWindow(xd, yd, xd + width - 1, yd + height - 1);
2020-06-11 21:34:22 +00:00
// Maximum font size is equivalent to 180x180 pixels in area
while (w > 0) {
line = pgm_read_byte((uint8_t *)flash_address++); // 8 bytes smaller when incrementing here
if (line & 0x80) {
line &= 0x7F;
line++; w -= line;
pushBlock(textcolor,line);
}
else {
line++; w -= line;
pushBlock(textbgcolor,line);
}
}
2020-06-11 21:34:22 +00:00
}
else
{
2020-10-02 21:00:03 +00:00
int32_t px = 0, py = 0; // To hold character pixel coords
int32_t tx = 0, ty = 0; // To hold character TFT pixel coords
2020-06-11 21:34:22 +00:00
int32_t pc = 0; // Pixel count
int32_t pl = 0; // Pixel line length
uint16_t pcol = 0; // Pixel color
bool pf = true; // Flag for plotting
2020-06-11 21:34:22 +00:00
while (pc < w) {
line = pgm_read_byte((uint8_t *)flash_address);
flash_address++;
if (line & 0x80) { pcol = textcolor; line &= 0x7F; pf = true;}
else { pcol = textbgcolor; if (textcolor == textbgcolor) pf = false;}
2020-06-11 21:34:22 +00:00
line++;
2020-10-02 21:00:03 +00:00
px = pc % width;
tx = x + textsize * px;
py = pc / width;
ty = y + textsize * py;
2020-06-11 21:34:22 +00:00
pl = 0;
pc += line;
2020-10-02 21:00:03 +00:00
while (line--) {
2020-06-11 21:34:22 +00:00
pl++;
2020-10-02 21:00:03 +00:00
if ((px+pl) >= width) {
if (pf) fillRect(tx, ty, pl * textsize, textsize, pcol);
2020-06-11 21:34:22 +00:00
pl = 0;
2020-10-02 21:00:03 +00:00
px = 0;
tx = x;
2020-06-11 21:34:22 +00:00
py ++;
2020-10-02 21:00:03 +00:00
ty += textsize;
2020-06-11 21:34:22 +00:00
}
}
if (pl && pf) fillRect(tx, ty, pl * textsize, textsize, pcol);
}
}
}
inTransaction = lockTransaction;
end_tft_write();
}
// End of RLE font rendering
#endif
#if !defined (LOAD_FONT2) && !defined (LOAD_RLE)
// Stop warnings
flash_address = flash_address;
w = w;
pX = pX;
pY = pY;
line = line;
clip = clip;
#endif
return width * textsize; // x +
}
/***************************************************************************************
** Function name: drawString (with or without user defined font)
** Description : draw string with padding if it is defined
***************************************************************************************/
// Without font number, uses font set by setTextFont()
int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY)
{
int16_t len = string.length() + 2;
char buffer[len];
string.toCharArray(buffer, len);
return drawString(buffer, poX, poY, textfont);
}
// With font number
int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY, uint8_t font)
{
int16_t len = string.length() + 2;
char buffer[len];
string.toCharArray(buffer, len);
return drawString(buffer, poX, poY, font);
}
// Without font number, uses font set by setTextFont()
int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY)
{
return drawString(string, poX, poY, textfont);
}
// With font number. Note: font number is over-ridden if a smooth font is loaded
int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8_t font)
{
2024-01-16 22:49:43 +00:00
if (font > 8) return 0;
int16_t sumX = 0;
uint8_t padding = 1, baseline = 0;
uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font
uint16_t cheight = 8 * textsize;
#ifdef LOAD_GFXFF
2018-10-24 09:00:33 +00:00
#ifdef SMOOTH_FONT
bool freeFont = (font == 1 && gfxFont && !fontLoaded);
#else
bool freeFont = (font == 1 && gfxFont);
#endif
2018-10-11 22:46:19 +00:00
if (freeFont) {
cheight = glyph_ab * textsize;
poY += cheight; // Adjust for baseline datum of free fonts
baseline = cheight;
padding =101; // Different padding method used for Free Fonts
// We need to make an adjustment for the bottom of the string (eg 'y' character)
if ((textdatum == BL_DATUM) || (textdatum == BC_DATUM) || (textdatum == BR_DATUM)) {
cheight += glyph_bb * textsize;
}
}
#endif
// If it is not font 1 (GLCD or free font) get the baseline and pixel height of the font
2018-02-24 19:02:20 +00:00
#ifdef SMOOTH_FONT
if(fontLoaded) {
baseline = gFont.maxAscent;
cheight = fontHeight();
}
else
2018-02-24 19:02:20 +00:00
#endif
if (font!=1) {
baseline = pgm_read_byte( &fontdata[font].baseline ) * textsize;
cheight = fontHeight(font);
}
if (textdatum || padX) {
switch(textdatum) {
case TC_DATUM:
poX -= cwidth/2;
padding += 1;
break;
case TR_DATUM:
poX -= cwidth;
padding += 2;
break;
case ML_DATUM:
poY -= cheight/2;
//padding += 0;
break;
case MC_DATUM:
poX -= cwidth/2;
poY -= cheight/2;
padding += 1;
break;
case MR_DATUM:
poX -= cwidth;
poY -= cheight/2;
padding += 2;
break;
case BL_DATUM:
poY -= cheight;
//padding += 0;
break;
case BC_DATUM:
poX -= cwidth/2;
poY -= cheight;
padding += 1;
break;
case BR_DATUM:
poX -= cwidth;
poY -= cheight;
padding += 2;
break;
case L_BASELINE:
poY -= baseline;
//padding += 0;
break;
case C_BASELINE:
poX -= cwidth/2;
poY -= baseline;
padding += 1;
break;
case R_BASELINE:
poX -= cwidth;
poY -= baseline;
padding += 2;
break;
}
}
int8_t xo = 0;
#ifdef LOAD_GFXFF
if (freeFont && (textcolor!=textbgcolor)) {
cheight = (glyph_ab + glyph_bb) * textsize;
// Get the offset for the first character only to allow for negative offsets
uint16_t c2 = 0;
uint16_t len = strlen(string);
uint16_t n = 0;
while (n < len && c2 == 0) c2 = decodeUTF8((uint8_t*)string, &n, len - n);
if((c2 >= pgm_read_word(&gfxFont->first)) && (c2 <= pgm_read_word(&gfxFont->last) )) {
c2 -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
xo = pgm_read_byte(&glyph->xOffset) * textsize;
// Adjust for negative xOffset
if (xo > 0) xo = 0;
else cwidth -= xo;
// Add 1 pixel of padding all round
//cheight +=2;
//fillRect(poX+xo-1, poY - 1 - glyph_ab * textsize, cwidth+2, cheight, textbgcolor);
fillRect(poX+xo, poY - glyph_ab * textsize, cwidth, cheight, textbgcolor);
}
padding -=100;
}
#endif
uint16_t len = strlen(string);
uint16_t n = 0;
2018-02-24 19:02:20 +00:00
#ifdef SMOOTH_FONT
if(fontLoaded) {
2018-02-24 19:02:20 +00:00
setCursor(poX, poY);
bool fillbg = _fillbg;
// If padding is requested then fill the text background
if (padX && !_fillbg) _fillbg = true;
while (n < len) {
uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n);
drawGlyph(uniCode);
2018-02-24 19:02:20 +00:00
}
_fillbg = fillbg; // restore state
2018-02-24 19:02:20 +00:00
sumX += cwidth;
//fontFile.close();
}
else
#endif
{
while (n < len) {
uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n);
sumX += drawChar(uniCode, poX+sumX, poY, font);
}
}
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Switch on debugging for the padding areas
//#define PADDING_DEBUG
#ifndef PADDING_DEBUG
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if((padX>cwidth) && (textcolor!=textbgcolor)) {
int16_t padXc = poX+cwidth+xo;
#ifdef LOAD_GFXFF
if (freeFont) {
poX +=xo; // Adjust for negative offset start character
poY -= glyph_ab * textsize;
sumX += poX;
}
#endif
switch(padding) {
case 1:
fillRect(padXc,poY,padX-cwidth,cheight, textbgcolor);
break;
case 2:
fillRect(padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor);
padXc = poX - ((padX-cwidth)>>1);
fillRect(padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor);
break;
case 3:
if (padXc>padX) padXc = padX;
fillRect(poX + cwidth - padXc,poY,padXc-cwidth,cheight, textbgcolor);
break;
}
}
#else
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// This is debug code to show text (green box) and blanked (white box) areas
// It shows that the padding areas are being correctly sized and positioned
if((padX>sumX) && (textcolor!=textbgcolor)) {
int16_t padXc = poX+sumX; // Maximum left side padding
#ifdef LOAD_GFXFF
if ((font == 1) && (gfxFont)) poY -= glyph_ab;
#endif
drawRect(poX,poY,sumX,cheight, TFT_GREEN);
switch(padding) {
case 1:
drawRect(padXc,poY,padX-sumX,cheight, TFT_WHITE);
break;
case 2:
drawRect(padXc,poY,(padX-sumX)>>1, cheight, TFT_WHITE);
padXc = (padX-sumX)>>1;
drawRect(poX - padXc,poY,(padX-sumX)>>1,cheight, TFT_WHITE);
break;
case 3:
if (padXc>padX) padXc = padX;
drawRect(poX + sumX - padXc,poY,padXc-sumX,cheight, TFT_WHITE);
break;
}
}
#endif
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return sumX;
}
/***************************************************************************************
** Function name: drawCentreString (deprecated, use setTextDatum())
** Descriptions: draw string centred on dX
***************************************************************************************/
int16_t TFT_eSPI::drawCentreString(const String& string, int32_t dX, int32_t poY, uint8_t font)
{
int16_t len = string.length() + 2;
char buffer[len];
string.toCharArray(buffer, len);
return drawCentreString(buffer, dX, poY, font);
}
int16_t TFT_eSPI::drawCentreString(const char *string, int32_t dX, int32_t poY, uint8_t font)
{
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t tempdatum = textdatum;
int32_t sumX = 0;
textdatum = TC_DATUM;
sumX = drawString(string, dX, poY, font);
textdatum = tempdatum;
return sumX;
}
/***************************************************************************************
** Function name: drawRightString (deprecated, use setTextDatum())
** Descriptions: draw string right justified to dX
***************************************************************************************/
int16_t TFT_eSPI::drawRightString(const String& string, int32_t dX, int32_t poY, uint8_t font)
{
int16_t len = string.length() + 2;
char buffer[len];
string.toCharArray(buffer, len);
return drawRightString(buffer, dX, poY, font);
}
int16_t TFT_eSPI::drawRightString(const char *string, int32_t dX, int32_t poY, uint8_t font)
{
Performance enhancements, new functions, bug fixes 1. Ability to swap bytes in pushColors() and pushImage() 2. pushImage() will handle FLASH stroed images 3. pushImage() will accept a transparent color 4. pushRect() deprecated but still works 5. setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 6. getSwapBytes() returns swap bytes parameter 7. fillCircle() and fillCircleHelper() changed to use horizontal lines to speed up plotting in a sprite 8. fillTriangle bug fix by moving spi_begin() 9 Small performance improvement to setAddrWindow() 10. pushColor() bug fix for swapped bytes 11. pushColors() performance improvement for ESP8266 and add optional byte swap parameter, accepts higher pixel count 12. move spi_begin() later in drawLine() incase fn returns early 13. add spi_end() in drawLine incdae return occurs early 14. Add color332() fn to convert 16 bit to 8 bit colour 15. Sprite: createSprite() checks if sprite already created and returns pointer if it does 16. Sprite: one extra "off-screen pixel added to a sprite to point out-of-bounds setWindow coords to this avoids extra bounds checks in push/write color 17. Sprite: setColorDepth allows changing of depthe for existing sprtie and returns a new pointer to the new sprite 18. Sprite: pushImage() accepts a swapped byte parameter 19. Sprite: setSwapBytes() to set swapping bytes in color for pushImage() and pushColors() true or false 20. Sprite: getSwapBytes() returns swap bytes parameter 21. Sprite: setWindow deals with duff out of sprite coords. 22. Sprite: bug in draw char corrected which could draw too many over-writing pixels
2018-01-08 23:19:42 +00:00
uint8_t tempdatum = textdatum;
int16_t sumX = 0;
textdatum = TR_DATUM;
sumX = drawString(string, dX, poY, font);
textdatum = tempdatum;
return sumX;
}
/***************************************************************************************
** Function name: drawNumber
** Description: draw a long integer
***************************************************************************************/
int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY)
{
isDigits = true; // Eliminate jiggle in monospaced fonts
char str[12];
ltoa(long_num, str, 10);
return drawString(str, poX, poY, textfont);
}
int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY, uint8_t font)
{
isDigits = true; // Eliminate jiggle in monospaced fonts
char str[12];
ltoa(long_num, str, 10);
return drawString(str, poX, poY, font);
}
/***************************************************************************************
** Function name: drawFloat
** Descriptions: drawFloat, prints 7 non zero digits maximum
***************************************************************************************/
// Assemble and print a string, this permits alignment relative to a datum
// looks complicated but much more compact and actually faster than using print class
int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t poY)
{
return drawFloat(floatNumber, dp, poX, poY, textfont);
}
int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t poY, uint8_t font)
{
isDigits = true;
char str[14]; // Array to contain decimal string
uint8_t ptr = 0; // Initialise pointer for array
int8_t digits = 1; // Count the digits to avoid array overflow
float rounding = 0.5; // Round up down delta
bool negative = false;
if (dp > 7) dp = 7; // Limit the size of decimal portion
// Adjust the rounding value
for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0;
if (floatNumber < -rounding) { // add sign, avoid adding - sign to 0.0!
str[ptr++] = '-'; // Negative number
str[ptr] = 0; // Put a null in the array as a precaution
digits = 0; // Set digits to 0 to compensate so pointer value can be used later
floatNumber = -floatNumber; // Make positive
negative = true;
}
floatNumber += rounding; // Round up or down
if (dp == 0) {
if (negative) floatNumber = -floatNumber;
return drawNumber((long)floatNumber, poX, poY, font);
}
// For error put ... in string and return (all TFT_eSPI library fonts contain . character)
if (floatNumber >= 2147483647) {
strcpy(str, "...");
return drawString(str, poX, poY, font);
}
// No chance of overflow from here on
// Get integer part
uint32_t temp = (uint32_t)floatNumber;
// Put integer part into array
ltoa(temp, str + ptr, 10);
// Find out where the null is to get the digit count loaded
while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along
digits += ptr; // Count the digits
str[ptr++] = '.'; // Add decimal point
str[ptr] = '0'; // Add a dummy zero
str[ptr + 1] = 0; // Add a null but don't increment pointer so it can be overwritten
// Get the decimal portion
floatNumber = floatNumber - temp;
// Get decimal digits one by one and put in array
// Limit digit count so we don't get a false sense of resolution
uint8_t i = 0;
while ((i < dp) && (digits < 9)) { // while (i < dp) for no limit but array size must be increased
i++;
floatNumber *= 10; // for the next decimal
temp = floatNumber; // get the decimal
ltoa(temp, str + ptr, 10);
ptr++; digits++; // Increment pointer and digits count
floatNumber -= temp; // Remove that digit
}
// Finally we can plot the string and return pixel length
return drawString(str, poX, poY, font);
}
/***************************************************************************************
** Function name: setFreeFont
** Descriptions: Sets the GFX free font to use
***************************************************************************************/
#ifdef LOAD_GFXFF
void TFT_eSPI::setFreeFont(const GFXfont *f)
{
if (f == nullptr) { // Fix issue #400 (ESP32 crash)
setTextFont(1); // Use GLCD font
return;
}
textfont = 1;
gfxFont = (GFXfont *)f;
glyph_ab = 0;
glyph_bb = 0;
uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first);
2020-01-25 06:07:45 +00:00
// Find the biggest above and below baseline offsets
2022-02-21 20:10:05 +00:00
for (uint16_t c = 0; c < numChars; c++) {
GFXglyph *glyph1 = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
int8_t ab = -pgm_read_byte(&glyph1->yOffset);
if (ab > glyph_ab) glyph_ab = ab;
int8_t bb = pgm_read_byte(&glyph1->height) - ab;
if (bb > glyph_bb) glyph_bb = bb;
}
}
/***************************************************************************************
** Function name: setTextFont
** Description: Set the font for the print stream
***************************************************************************************/
void TFT_eSPI::setTextFont(uint8_t f)
{
textfont = (f > 0) ? f : 1; // Don't allow font 0
2024-01-16 22:49:43 +00:00
textfont = (f > 8) ? 1 : f; // Don't allow font > 8
gfxFont = NULL;
}
#else
2020-01-25 06:07:45 +00:00
/***************************************************************************************
** Function name: setFreeFont
** Descriptions: Sets the GFX free font to use
***************************************************************************************/
// Alternative to setTextFont() so we don't need two different named functions
void TFT_eSPI::setFreeFont(uint8_t font)
{
setTextFont(font);
}
/***************************************************************************************
** Function name: setTextFont
** Description: Set the font for the print stream
***************************************************************************************/
void TFT_eSPI::setTextFont(uint8_t f)
{
textfont = (f > 0) ? f : 1; // Don't allow font 0
2024-01-16 22:49:43 +00:00
textfont = (f > 8) ? 1 : f; // Don't allow font > 8
}
#endif
/***************************************************************************************
** Function name: getSPIinstance
** Description: Get the instance of the SPI class
***************************************************************************************/
#if !defined (TFT_PARALLEL_8_BIT) && !defined (RP2040_PIO_INTERFACE)
SPIClass& TFT_eSPI::getSPIinstance(void)
{
return spi;
}
#endif
/***************************************************************************************
** Function name: verifySetupID
** Description: Compare the ID if USER_SETUP_ID defined in user setup file
***************************************************************************************/
bool TFT_eSPI::verifySetupID(uint32_t id)
{
#if defined (USER_SETUP_ID)
if (USER_SETUP_ID == id) return true;
#else
id = id; // Avoid warning
#endif
return false;
}
/***************************************************************************************
** Function name: getSetup
** Description: Get the setup details for diagnostic and sketch access
***************************************************************************************/
void TFT_eSPI::getSetup(setup_t &tft_settings)
{
2019-01-23 20:55:04 +00:00
// tft_settings.version is set in header file
#if defined (USER_SETUP_INFO)
tft_settings.setup_info = USER_SETUP_INFO;
#else
tft_settings.setup_info = "NA";
#endif
#if defined (USER_SETUP_ID)
tft_settings.setup_id = USER_SETUP_ID;
#else
tft_settings.setup_id = 0;
#endif
#if defined (PROCESSOR_ID)
tft_settings.esp = PROCESSOR_ID;
#else
tft_settings.esp = -1;
#endif
#if defined (SUPPORT_TRANSACTIONS)
tft_settings.trans = true;
#else
tft_settings.trans = false;
#endif
2022-04-22 01:44:10 +00:00
#if defined (TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT)
tft_settings.serial = false;
tft_settings.tft_spi_freq = 0;
#else
tft_settings.serial = true;
tft_settings.tft_spi_freq = SPI_FREQUENCY/100000;
2019-01-23 20:55:04 +00:00
#ifdef SPI_READ_FREQUENCY
tft_settings.tft_rd_freq = SPI_READ_FREQUENCY/100000;
#endif
2023-02-20 17:25:58 +00:00
#ifndef GENERIC_PROCESSOR
#ifdef TFT_SPI_PORT
tft_settings.port = TFT_SPI_PORT;
#else
tft_settings.port = 255;
#endif
#endif
#ifdef RP2040_PIO_SPI
tft_settings.interface = 0x10;
#else
tft_settings.interface = 0x0;
#endif
#endif
#if defined(TFT_SPI_OVERLAP)
tft_settings.overlap = true;
#else
tft_settings.overlap = false;
#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
2022-04-22 01:44:10 +00:00
#if defined (TFT_PARALLEL_8_BIT) || defined(TFT_PARALLEL_16_BIT)
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 (TFT_BL)
tft_settings.pin_tft_led = TFT_BL;
#endif
#if defined (TFT_BACKLIGHT_ON)
tft_settings.pin_tft_led_on = TFT_BACKLIGHT_ON;
#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
}
2018-02-24 19:02:20 +00:00
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TOUCH_CS
#include "Extensions/Touch.cpp"
#endif
2022-03-13 00:12:27 +00:00
#include "Extensions/Button.cpp"
2018-02-24 19:02:20 +00:00
#include "Extensions/Sprite.cpp"
2018-02-24 19:02:20 +00:00
#ifdef SMOOTH_FONT
#include "Extensions/Smooth_font.cpp"
#endif
#ifdef AA_GRAPHICS
#include "Extensions/AA_graphics.cpp" // Loaded if SMOOTH_FONT is defined by user
#endif
2018-02-24 19:02:20 +00:00
////////////////////////////////////////////////////////////////////////////////////////