forked from Bodmer/TFT_eSPI
Bring back drawArc
This commit is contained in:
221
TFT_eSPI.cpp
221
TFT_eSPI.cpp
@ -53,6 +53,14 @@ void delay(uint32_t ms)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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;
|
||||
|
||||
// Clipping macro for pushImage
|
||||
#define PI_CLIP \
|
||||
if (_vpOoB) return; \
|
||||
@ -2567,6 +2575,211 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint16_t color)
|
||||
end_tft_write();
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** 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
|
||||
// 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;
|
||||
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
|
||||
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
|
||||
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
|
||||
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: pushColor
|
||||
** Description: push a single pixel
|
||||
@ -2725,14 +2938,6 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16_t
|
||||
end_tft_write();
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** 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;
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: drawPixel (aplha blended)
|
||||
** Description: Draw a pixel blended with the screen or bg pixel colour
|
||||
|
27
TFT_eSPI.h
27
TFT_eSPI.h
@ -346,6 +346,12 @@ class TFT_eSPI : public espgui::TftInterface {
|
||||
// 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);
|
||||
|
||||
|
||||
// As per "drawSmoothArc" except the ends of the arc are NOT anti-aliased, this facilitates dynamic arc length changes with
|
||||
// arc segments and ensures clean segment joints.
|
||||
// The sides of the arc are anti-aliased by default. If smoothArc is false sides will NOT be anti-aliased
|
||||
void 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 smoothArc = true);
|
||||
|
||||
// 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);
|
||||
@ -559,6 +565,9 @@ class TFT_eSPI : public espgui::TftInterface {
|
||||
// Single GPIO input/output direction control
|
||||
void gpioMode(uint8_t gpio, uint8_t mode);
|
||||
|
||||
// Smooth graphics helper
|
||||
uint8_t sqrt_fraction(uint32_t num);
|
||||
|
||||
// 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);
|
||||
|
||||
@ -646,6 +655,24 @@ class TFT_eSPI : public espgui::TftInterface {
|
||||
|
||||
}; // End of class TFT_eSPI
|
||||
|
||||
// Swap any type
|
||||
template <typename T> static inline void
|
||||
transpose(T& a, T& b) { T t = a; a = b; b = t; }
|
||||
|
||||
// Fast alphaBlend
|
||||
template <typename A, typename F, typename B> static inline uint16_t
|
||||
fastBlend(A alpha, F fgc, B bgc)
|
||||
{
|
||||
// Split out and blend 5-bit red and blue channels
|
||||
uint32_t rxb = bgc & 0xF81F;
|
||||
rxb += ((fgc & 0xF81F) - rxb) * (alpha >> 2) >> 6;
|
||||
// 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);
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Section 10: Additional extension classes
|
||||
***************************************************************************************/
|
||||
|
Reference in New Issue
Block a user