mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-07 14:44:43 +02:00
Add new anit-aliased graphics functions
Examples to follow.
This commit is contained in:
@@ -1292,7 +1292,7 @@ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
||||
** Function name: pushColor
|
||||
** Description: Send a new pixel to the set window
|
||||
***************************************************************************************/
|
||||
void TFT_eSprite::pushColor(uint32_t color)
|
||||
void TFT_eSprite::pushColor(uint16_t color)
|
||||
{
|
||||
if (!_created ) return;
|
||||
|
||||
@@ -1334,7 +1334,7 @@ void TFT_eSprite::pushColor(uint32_t color)
|
||||
** Function name: pushColor
|
||||
** Description: Send a "len" new pixels to the set window
|
||||
***************************************************************************************/
|
||||
void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
|
||||
void TFT_eSprite::pushColor(uint16_t color, uint32_t len)
|
||||
{
|
||||
if (!_created ) return;
|
||||
|
||||
|
@@ -63,9 +63,9 @@ class TFT_eSprite : public TFT_eSPI {
|
||||
// Colours are converted to the set Sprite colour bit depth
|
||||
setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1),
|
||||
// Push a color (aka singe pixel) to the screen
|
||||
pushColor(uint32_t color),
|
||||
pushColor(uint16_t color),
|
||||
// Push len colors (pixels) to the screen
|
||||
pushColor(uint32_t color, uint16_t len),
|
||||
pushColor(uint16_t color, uint32_t len),
|
||||
// Push a pixel preformatted as a 8 or 16 bit colour (avoids conversion overhead)
|
||||
writeColor(uint16_t color),
|
||||
|
||||
@@ -149,6 +149,10 @@ class TFT_eSprite : public TFT_eSPI {
|
||||
// Reserve memory for the Sprite and return a pointer
|
||||
void* callocSprite(int16_t width, int16_t height, uint8_t frames = 1);
|
||||
|
||||
// Override the non-inlined TFT_eSPI functions
|
||||
void begin_nin_write(void) { ; }
|
||||
void end_nin_write(void) { ; }
|
||||
|
||||
protected:
|
||||
|
||||
uint8_t _bpp; // bits per pixel (1, 8 or 16)
|
||||
|
@@ -426,6 +426,10 @@ SPI3_HOST = 2
|
||||
#define RD_L
|
||||
#define RD_H
|
||||
#endif
|
||||
#else
|
||||
#define TFT_RD -1
|
||||
#define RD_L
|
||||
#define RD_H
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -160,8 +160,20 @@
|
||||
// Make sure TFT_RD is defined if not used to avoid an error message
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// At the moment read is not supported for parallel mode, tie TFT signal high
|
||||
#ifndef TFT_RD
|
||||
#ifdef TFT_RD
|
||||
#if (TFT_RD >= 0)
|
||||
#define RD_L sio_hw->gpio_clr = (1ul << TFT_RD)
|
||||
//#define RD_L digitalWrite(TFT_WR, LOW)
|
||||
#define RD_H sio_hw->gpio_set = (1ul << TFT_RD)
|
||||
//#define RD_H digitalWrite(TFT_WR, HIGH)
|
||||
#else
|
||||
#define RD_L
|
||||
#define RD_H
|
||||
#endif
|
||||
#else
|
||||
#define TFT_RD -1
|
||||
#define RD_L
|
||||
#define RD_H
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
363
TFT_eSPI.cpp
363
TFT_eSPI.cpp
@@ -53,6 +53,15 @@
|
||||
\
|
||||
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
|
||||
@@ -68,6 +77,18 @@ inline void TFT_eSPI::begin_tft_write(void){
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -86,6 +107,21 @@ inline void TFT_eSPI::end_tft_write(void){
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
spi.endTransaction();
|
||||
#endif
|
||||
}
|
||||
SET_BUS_READ_MODE; // In case SPI has been configured for tx only
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: begin_tft_read (was called spi_begin_read)
|
||||
** Description: Start transaction for reads and select TFT
|
||||
@@ -108,6 +144,29 @@ inline void TFT_eSPI::begin_tft_read(void){
|
||||
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
|
||||
@@ -183,7 +242,7 @@ bool TFT_eSPI::checkViewport(int32_t x, int32_t y, int32_t w, int32_t h)
|
||||
x+= _xDatum;
|
||||
y+= _yDatum;
|
||||
|
||||
if ((x >= _vpW) || (y >= _vpH)) return false;
|
||||
if ((x >= _vpW) || (y >= _vpH)) return false;
|
||||
|
||||
int32_t dx = 0;
|
||||
int32_t dy = 0;
|
||||
@@ -290,7 +349,7 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w)
|
||||
// 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;
|
||||
@@ -320,35 +379,55 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w)
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: end_tft_read (was called spi_end_read)
|
||||
** Description: End transaction for reads and deselect TFT
|
||||
** Function name: clipAddrWindow
|
||||
** Description: Clip address window x,y,w,h to screen and viewport
|
||||
***************************************************************************************/
|
||||
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;
|
||||
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: Legacy - deprecated
|
||||
** Description: Start/end transaction
|
||||
** Function name: clipWindow
|
||||
** Description: Clip window xs,yx,xe,ye to screen and viewport
|
||||
***************************************************************************************/
|
||||
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(); }
|
||||
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
|
||||
@@ -1896,7 +1975,7 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_
|
||||
uint8_t* buf565 = data + len;
|
||||
|
||||
readRect(x0, y0, w, h, (uint16_t*)buf565);
|
||||
|
||||
|
||||
while (len--) {
|
||||
uint16_t pixel565 = (*buf565++)<<8;
|
||||
pixel565 |= *buf565++;
|
||||
@@ -1975,7 +2054,7 @@ void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
|
||||
int32_t xs = -1;
|
||||
int32_t xe = 0;
|
||||
int32_t len = 0;
|
||||
|
||||
|
||||
bool first = true;
|
||||
do {
|
||||
while (f < 0) {
|
||||
@@ -2837,7 +2916,6 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
|
||||
** 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;
|
||||
@@ -3250,7 +3328,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
x+= _xDatum;
|
||||
y+= _yDatum;
|
||||
|
||||
// Range checking
|
||||
// Range checking
|
||||
if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return;
|
||||
|
||||
#ifdef CGRAM_OFFSET
|
||||
@@ -3276,7 +3354,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
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);
|
||||
@@ -3298,9 +3376,9 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
#endif
|
||||
|
||||
// Temporary solution is to include the RP2040 optimised code here
|
||||
#elif (defined (ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined (SSD1351_DRIVER)
|
||||
#elif (defined (ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined (SSD1351_DRIVER)
|
||||
|
||||
#if defined (SSD1963_DRIVER)
|
||||
#if defined (SSD1963_DRIVER)
|
||||
if ((rotation & 0x1) == 0) { swap_coord(x, y); }
|
||||
#endif
|
||||
|
||||
@@ -3375,7 +3453,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
|
||||
#else
|
||||
|
||||
#if defined (SSD1351_DRIVER) || defined (SSD1963_DRIVER)
|
||||
#if defined (SSD1351_DRIVER) || defined (SSD1963_DRIVER)
|
||||
if ((rotation & 0x1) == 0) { swap_coord(x, y); }
|
||||
#endif
|
||||
|
||||
@@ -3412,7 +3490,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
#endif
|
||||
|
||||
DC_C; tft_Write_8(TFT_RAMWR);
|
||||
|
||||
|
||||
#if defined(TFT_PARALLEL_8_BIT) || !defined(ESP32)
|
||||
DC_D; tft_Write_16(color);
|
||||
#else
|
||||
@@ -3431,7 +3509,8 @@ void TFT_eSPI::pushColor(uint16_t color)
|
||||
{
|
||||
begin_tft_write();
|
||||
|
||||
tft_Write_16(color);
|
||||
SPI_BUSY_CHECK;
|
||||
tft_Write_16N(color);
|
||||
|
||||
end_tft_write();
|
||||
}
|
||||
@@ -3583,6 +3662,196 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Description: Constants for anti-aliased line drawing on TFT and in Sprites
|
||||
***************************************************************************************/
|
||||
constexpr float PixelAlphaGain = 255.0;
|
||||
constexpr float LoAlphaTheshold = 1.0/31.0;
|
||||
constexpr float HiAlphaTheshold = 1.0 - LoAlphaTheshold;
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: drawPixel (aplha 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);
|
||||
bg_color = alphaBlend(alpha, color, bg_color);
|
||||
drawPixel(x, y, bg_color);
|
||||
return 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)
|
||||
{
|
||||
inTransaction = true;
|
||||
int16_t xs = 0;
|
||||
int16_t cx;
|
||||
r++;
|
||||
for (int16_t cy = r; cy > 0; cy--)
|
||||
{
|
||||
for (cx = xs; cx <= xs + 1 && cx < r; cx++)
|
||||
{
|
||||
float deltaX = r - cx;
|
||||
float deltaY = r - cy;
|
||||
float weight = r - sqrtf(deltaX * deltaX + deltaY * deltaY);
|
||||
if (weight > 1.0) continue;
|
||||
xs = cx;
|
||||
if (weight < LoAlphaTheshold) continue;
|
||||
uint8_t alpha = weight * 255;
|
||||
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);
|
||||
}
|
||||
cx--;
|
||||
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: fillSmoothCircle
|
||||
** Description: Draw a filled anti-aliased circle
|
||||
***************************************************************************************/
|
||||
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;
|
||||
int16_t xs = 0;
|
||||
int16_t cx;
|
||||
|
||||
y += r;
|
||||
h -= 2*r;
|
||||
fillRect(x, y, w, h, color);
|
||||
x += r;
|
||||
w -= 2*r+1;
|
||||
r++;
|
||||
|
||||
for (int16_t cy = r; cy > 0; cy--)
|
||||
{
|
||||
for (cx = xs; cx <= xs + 1 && cx < r; cx++)
|
||||
{
|
||||
float deltaX = r - cx;
|
||||
float deltaY = r - cy;
|
||||
float weight = r - sqrtf(deltaX * deltaX + deltaY * deltaY);
|
||||
if (weight > 1.0) continue;
|
||||
xs = cx;
|
||||
if (weight < LoAlphaTheshold) continue;
|
||||
uint8_t alpha = weight * 255;
|
||||
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);
|
||||
}
|
||||
cx--;
|
||||
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
|
||||
***************************************************************************************/
|
||||
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
|
||||
** Description: draw an anti-aliased line with different width radiused ends
|
||||
***************************************************************************************/
|
||||
// For sprites and TFT screens where the background pixel colour is fixed
|
||||
void TFT_eSPI::drawWedgeLine(float ax, float ay, float bx, float by, float ar, float br, uint32_t fg_color, uint32_t bg_color)
|
||||
{
|
||||
if ( (abs(ax - bx) < 0.01f) && (abs(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 slope direction
|
||||
int32_t xs = x0, yp = y1, yinc = -1;
|
||||
if (((ax-ar)>(bx-br) && (ay>by)) || ((ax-ar)<(bx-br) && ay<by)) { yp = y0; yinc = 1; }
|
||||
|
||||
br = ar - br; // Radius delta
|
||||
float alpha = 1.0f;
|
||||
ar += 0.5;
|
||||
uint32_t ri = (uint32_t)(ar);
|
||||
uint16_t bg = bg_color;
|
||||
float xpax, ypay, bax = bx - ax, bay = by - ay;
|
||||
|
||||
begin_nin_write();
|
||||
inTransaction = true;
|
||||
|
||||
// Scan bounding box, calculate pixel intensity from distance to line
|
||||
for (int32_t y = y0; y <= y1; y++) {
|
||||
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, br);
|
||||
if (alpha <= LoAlphaTheshold ) continue;
|
||||
// Track left line segment boundary
|
||||
if (!endX) { endX = true; if ((y > (y0+ri)) && (xp > xs)) xs = xp; }
|
||||
if (alpha > HiAlphaTheshold) {
|
||||
//drawPixel(xp, yp, fg_color);
|
||||
if (swin) { setWindow(xp, yp, width()-1, yp); swin = false; }
|
||||
pushColor(fg_color); // 778960 .v. 1337554
|
||||
continue;
|
||||
}
|
||||
//Blend color with background and plot
|
||||
if (bg_color == 0x00FFFFFF) {
|
||||
bg = readPixel(xp, yp); swin = true;
|
||||
}
|
||||
//drawPixel(xp, yp, alphaBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg));
|
||||
if (swin) { setWindow(xp, yp, width()-1, yp); swin = false; }
|
||||
pushColor(alphaBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg));
|
||||
}
|
||||
yp+=yinc;
|
||||
}
|
||||
|
||||
inTransaction = lockTransaction;
|
||||
end_nin_write();
|
||||
}
|
||||
|
||||
// Calculate distance of px,py to closest part of line
|
||||
/***************************************************************************************
|
||||
** 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
|
||||
@@ -3747,7 +4016,7 @@ void TFT_eSPI::fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uin
|
||||
if ((w < 1) || (h < 1)) return;
|
||||
|
||||
begin_tft_write();
|
||||
|
||||
|
||||
float delta = -255.0/w;
|
||||
float alpha = 255.0;
|
||||
uint32_t color = color1;
|
||||
@@ -4005,7 +4274,7 @@ uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc, uint8_t
|
||||
if (alphaDither < 0) alpha = 0;
|
||||
if (alphaDither >255) alpha = 255;
|
||||
}
|
||||
|
||||
|
||||
return alphaBlend(alpha, fgc, bgc);
|
||||
}
|
||||
|
||||
@@ -4041,6 +4310,22 @@ uint32_t TFT_eSPI::alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8
|
||||
return (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: write
|
||||
** Description: draw characters piped through serial stream
|
||||
***************************************************************************************/
|
||||
size_t TFT_eSPI::write(const uint8_t *buf, size_t len)
|
||||
{
|
||||
inTransaction = true;
|
||||
|
||||
uint8_t *lbuf = (uint8_t *)buf;
|
||||
while(len--) write(*lbuf++);
|
||||
|
||||
inTransaction = lockTransaction;
|
||||
end_tft_write();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: write
|
||||
** Description: draw characters piped through serial stream
|
||||
@@ -4341,7 +4626,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
|
||||
|
||||
w *= height; // Now w is total number of pixels in the character
|
||||
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
|
||||
uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel
|
||||
|
58
TFT_eSPI.h
58
TFT_eSPI.h
@@ -16,7 +16,7 @@
|
||||
#ifndef _TFT_eSPIH_
|
||||
#define _TFT_eSPIH_
|
||||
|
||||
#define TFT_ESPI_VERSION "2.4.32"
|
||||
#define TFT_ESPI_VERSION "2.4.33"
|
||||
|
||||
// Bit level feature flags
|
||||
// Bit 0 set: viewport capability
|
||||
@@ -407,6 +407,18 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
height(void),
|
||||
width(void);
|
||||
|
||||
// Read the colour of a pixel at x,y and return value in 565 format
|
||||
virtual uint16_t readPixel(int32_t x, int32_t y);
|
||||
|
||||
virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates
|
||||
|
||||
// Push (aka write pixel) colours to the set window
|
||||
virtual void pushColor(uint16_t color);
|
||||
|
||||
// These are non-inlined to enable override
|
||||
virtual void begin_nin_write();
|
||||
virtual void end_nin_write();
|
||||
|
||||
void setRotation(uint8_t r); // Set the display image orientation to 0, 1, 2 or 3
|
||||
uint8_t getRotation(void); // Read the current rotation
|
||||
|
||||
@@ -414,8 +426,7 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
|
||||
|
||||
// The TFT_eSprite class inherits the following functions (not all are useful to Sprite class
|
||||
void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h), // Note: start coordinates + width and height
|
||||
setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates
|
||||
void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); // Note: start coordinates + width and height
|
||||
|
||||
// Viewport commands, see "Viewport_Demo" sketch
|
||||
void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true);
|
||||
@@ -428,9 +439,13 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
void frameViewport(uint16_t color, int32_t w);
|
||||
void resetViewport(void);
|
||||
|
||||
// Push (aka write pixel) colours to the TFT (use setAddrWindow() first)
|
||||
void pushColor(uint16_t color),
|
||||
pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock()
|
||||
// Clip input window to viewport bounds, return false if whole area is out of bounds
|
||||
bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h);
|
||||
// Clip input window area to viewport bounds, return false if whole area is out of bounds
|
||||
bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye);
|
||||
|
||||
// Push (aka write pixel) colours to the TFT (use setAddrWindow() first)
|
||||
void pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock()
|
||||
pushColors(uint16_t *data, uint32_t len, bool swap = true), // With byte swap option
|
||||
pushColors(uint8_t *data, uint32_t len); // Deprecated, use pushPixels()
|
||||
|
||||
@@ -440,9 +455,6 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
// Write a set of pixels stored in memory, use setSwapBytes(true/false) function to correct endianess
|
||||
void pushPixels(const void * data_in, uint32_t len);
|
||||
|
||||
// Read the colour of a pixel at x,y and return value in 565 format
|
||||
uint16_t readPixel(int32_t x, int32_t y);
|
||||
|
||||
// Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input
|
||||
#ifdef TFT_SDA_READ
|
||||
#if defined (TFT_eSPI_ENABLE_8_BIT_READ)
|
||||
@@ -461,6 +473,28 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2);
|
||||
void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2);
|
||||
|
||||
// Draw a pixel blended with the pixel colour on the TFT or sprite, return blended colour
|
||||
// If bg_color is not included the background pixel colour will be read from TFT or sprite
|
||||
uint16_t drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color = 0x00FFFFFF);
|
||||
|
||||
// Draw a small anti-aliased filled circle at ax,ay with radius r (uses drawWideLine)
|
||||
// If bg_color is not included the background pixel colour will be read from TFT or sprite
|
||||
void drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF);
|
||||
|
||||
// Draw an anti-aliased filled circle at x, y with radius r
|
||||
// If bg_color is not included the background pixel colour will be read from TFT or sprite
|
||||
void fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color = 0x00FFFFFF);
|
||||
|
||||
void fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color, uint32_t bg_color = 0x00FFFFFF);
|
||||
|
||||
// Draw an anti-aliased wide line from ax,ay to bx,by width wd with radiused ends (radius is wd/2)
|
||||
// If bg_color is not included the background pixel colour will be read from TFT or sprite
|
||||
void drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF);
|
||||
|
||||
// Draw an anti-aliased wide line from ax,ay to bx,by with different width at each end aw, bw and with radiused ends
|
||||
// If bg_color is not included the background pixel colour will be read from TFT or sprite
|
||||
void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF);
|
||||
|
||||
void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
|
||||
drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color),
|
||||
fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
|
||||
@@ -577,7 +611,8 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
|
||||
// Support function to UTF8 decode and draw characters piped through print stream
|
||||
size_t write(uint8_t);
|
||||
|
||||
size_t write(const uint8_t *buf, size_t len);
|
||||
|
||||
// Used by Smooth font class to fetch a pixel colour for the anti-aliasing
|
||||
void setCallback(getColorCallback getCol);
|
||||
|
||||
@@ -744,6 +779,9 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
// Single GPIO input/output direction control
|
||||
void gpioMode(uint8_t gpio, uint8_t mode);
|
||||
|
||||
// Helper function: calculate distance of a point from a finite length line between two points
|
||||
float wedgeLineDistance(float pax, float pay, float bax, float bay, float dr);
|
||||
|
||||
// Display variant settings
|
||||
uint8_t tabcolor, // ST7735 screen protector "tab" colour (now invalid)
|
||||
colstart = 0, rowstart = 0; // Screen display area to CGRAM area coordinate offsets
|
||||
|
@@ -27,6 +27,15 @@ getViewportHeight KEYWORD2
|
||||
getViewportDatum KEYWORD2
|
||||
frameViewport KEYWORD2
|
||||
|
||||
# Smooth (anti-aliased) graphics functions
|
||||
fillRectHGradient KEYWORD2
|
||||
fillRectVGradient KEYWORD2
|
||||
fillSmoothCircle KEYWORD2
|
||||
fillSmoothRoundRect KEYWORD2
|
||||
drawSpot KEYWORD2
|
||||
drawWideLine KEYWORD2
|
||||
drawWedgeLine KEYWORD2
|
||||
|
||||
pushColor KEYWORD2
|
||||
pushColors KEYWORD2
|
||||
pushBlock KEYWORD2
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TFT_eSPI",
|
||||
"version": "2.4.32",
|
||||
"version": "2.4.33",
|
||||
"keywords": "Arduino, tft, ePaper, display, Pico, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, RM68140, SSD1351, SSD1963, ILI9225, HX8357D",
|
||||
"description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, ESP8266, ESP32 and STM32",
|
||||
"repository":
|
||||
|
@@ -1,5 +1,5 @@
|
||||
name=TFT_eSPI
|
||||
version=2.4.32
|
||||
version=2.4.33
|
||||
author=Bodmer
|
||||
maintainer=Bodmer
|
||||
sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32
|
||||
|
Reference in New Issue
Block a user