Files
iot-objets-connectes/T-Display-S3-main/lib/Arduino_GFX/src/Arduino_GFX.cpp
2026-03-31 13:17:21 +02:00

2670 lines
80 KiB
C++

/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*
* Arc function come from:
* https://github.com/lovyan03/LovyanGFX.git
*/
#include "Arduino_DataBus.h"
#include "Arduino_GFX.h"
#include "font/glcdfont.h"
#include "float.h"
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#endif
/**************************************************************************/
/*!
@brief Instatiate a GFX context for graphics! Can only be done by a superclass
@param w Display width, in pixels
@param h Display height, in pixels
*/
/**************************************************************************/
#if defined(LITTLE_FOOT_PRINT)
Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h)
#else
Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : Arduino_G(w, h)
#endif // !defined(LITTLE_FOOT_PRINT)
{
_width = WIDTH;
_height = HEIGHT;
_max_x = _width - 1; ///< x zero base bound
_max_y = _height - 1; ///< y zero base bound
_rotation = 0;
cursor_y = cursor_x = 0;
textsize_x = textsize_y = 1;
text_pixel_margin = 0;
textcolor = textbgcolor = 0xFFFF;
wrap = true;
#if !defined(ATTINY_CORE)
gfxFont = NULL;
#if defined(U8G2_FONT_SUPPORT)
u8g2Font = NULL;
#endif // defined(U8G2_FONT_SUPPORT)
#endif // !defined(ATTINY_CORE)
}
/**************************************************************************/
/*!
@brief Write a line. Check straight or slash line and call corresponding function
@param x0 Start point x coordinate
@param y0 Start point y coordinate
@param x1 End point x coordinate
@param y1 End point y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color)
{
if (x0 == x1)
{
if (y0 > y1)
{
_swap_int16_t(y0, y1);
}
writeFastVLine(x0, y0, y1 - y0 + 1, color);
}
else if (y0 == y1)
{
if (x0 > x1)
{
_swap_int16_t(x0, x1);
}
writeFastHLine(x0, y0, x1 - x0 + 1, color);
}
else
{
writeSlashLine(x0, y0, x1, y1, color);
}
}
/**************************************************************************/
/*!
@brief Write a line. Bresenham's algorithm - thx wikpedia
@param x0 Start point x coordinate
@param y0 Start point y coordinate
@param x1 End point x coordinate
@param y1 End point y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color)
{
bool steep = _diff(y1, y0) > _diff(x1, x0);
if (steep)
{
_swap_int16_t(x0, y0);
_swap_int16_t(x1, y1);
}
if (x0 > x1)
{
_swap_int16_t(x0, x1);
_swap_int16_t(y0, y1);
}
int16_t dx = x1 - x0;
int16_t dy = _diff(y1, y0);
int16_t err = dx >> 1;
int16_t step = (y0 < y1) ? 1 : -1;
for (; x0 <= x1; x0++)
{
if (steep)
{
writePixel(y0, x0, color);
}
else
{
writePixel(x0, y0, color);
}
err -= dy;
if (err < 0)
{
err += dx;
y0 += step;
}
}
}
/**************************************************************************/
/*!
@brief Start a display-writing routine, overwrite in subclasses.
*/
/**************************************************************************/
INLINE void Arduino_GFX::startWrite()
{
}
void Arduino_GFX::writePixel(int16_t x, int16_t y, uint16_t color)
{
if (_ordered_in_range(x, 0, _max_x) && _ordered_in_range(y, 0, _max_y))
{
writePixelPreclipped(x, y, color);
}
}
/**************************************************************************/
/*!
@brief Write a pixel, overwrite in subclasses if startWrite is defined!
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::drawPixel(int16_t x, int16_t y, uint16_t color)
{
startWrite();
writePixel(x, y, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Write a perfectly vertical line, overwrite in subclasses if startWrite is defined!
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::writeFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
for (int16_t i = y; i < y + h; i++)
{
writePixel(x, i, color);
}
}
/**************************************************************************/
/*!
@brief Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined!
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::writeFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
for (int16_t i = x; i < x + w; i++)
{
writePixel(i, y, color);
}
}
/**************************************************************************/
/*!
@brief Draw a filled rectangle to the display. Not self-contained;
should follow startWrite(). Typically used by higher-level
graphics primitives; user code shouldn't need to call this and
is likely to use the self-contained fillRect() instead.
writeFillRect() performs its own edge clipping and rejection;
see writeFillRectPreclipped() for a more 'raw' implementation.
@param x Horizontal position of first corner.
@param y Vertical position of first corner.
@param w Rectangle width in pixels (positive = right of first
corner, negative = left of first corner).
@param h Rectangle height in pixels (positive = below first
corner, negative = above first corner).
@param color 16-bit fill color in '565' RGB format.
@note Written in this deep-nested way because C by definition will
optimize for the 'if' case, not the 'else' -- avoids branches
and rejects clipped rectangles at the least-work possibility.
*/
/**************************************************************************/
void Arduino_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color)
{
if (w && h)
{ // Nonzero width and height?
if (w < 0)
{ // If negative width...
x += w + 1; // Move X to left edge
w = -w; // Use positive width
}
if (x <= _max_x)
{ // Not off right
if (h < 0)
{ // If negative height...
y += h + 1; // Move Y to top edge
h = -h; // Use positive height
}
if (y <= _max_y)
{ // Not off bottom
int16_t x2 = x + w - 1;
if (x2 >= 0)
{ // Not off left
int16_t y2 = y + h - 1;
if (y2 >= 0)
{ // Not off top
// Rectangle partly or fully overlaps screen
if (x < 0)
{
x = 0;
w = x2 + 1;
} // Clip left
if (y < 0)
{
y = 0;
h = y2 + 1;
} // Clip top
if (x2 > _max_x)
{
w = _max_x - x + 1;
} // Clip right
if (y2 > _max_y)
{
h = _max_y - y + 1;
} // Clip bottom
writeFillRectPreclipped(x, y, w, h, color);
}
}
}
}
}
}
/**************************************************************************/
/*!
@brief Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined!
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color)
{
// Overwrite in subclasses if desired!
for (int16_t i = y; i < y + h; i++)
{
writeFastHLine(x, i, w, color);
}
}
/**************************************************************************/
/*!
@brief End a display-writing routine, overwrite in subclasses if startWrite is defined!
*/
/**************************************************************************/
INLINE void Arduino_GFX::endWrite()
{
}
/**************************************************************************/
/*!
@brief Draw a perfectly vertical line (this is often optimized in a subclass!)
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::drawFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
startWrite();
writeFastVLine(x, y, h, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a perfectly horizontal line (this is often optimized in a subclass!)
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::drawFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
startWrite();
writeFastHLine(x, y, w, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Fill a rectangle completely with one color. Update in subclasses if desired!
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color)
{
startWrite();
writeFillRect(x, y, w, h, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Fill the screen completely with one color. Update in subclasses if desired!
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillScreen(uint16_t color)
{
fillRect(0, 0, _width, _height, color);
}
/**************************************************************************/
/*!
@brief Draw a line
@param x0 Start point x coordinate
@param y0 Start point y coordinate
@param x1 End point x coordinate
@param y1 End point y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color)
{
// Update in subclasses if desired!
startWrite();
writeLine(x0, y0, x1, y1, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a circle outline
@param x Center-point x coordinate
@param y Center-point y coordinate
@param r Radius of circle
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawCircle(int16_t x, int16_t y,
int16_t r, uint16_t color)
{
startWrite();
drawEllipseHelper(x, y, r, r, 0xf, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Quarter-ellipse drawer, used to do circles and roundrects
@param x Center-point x coordinate
@param y Center-point y coordinate
@param rx radius of x coordinate
@param ry radius of y coordinate
@param cornername Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawEllipseHelper(int32_t x, int32_t y,
int32_t rx, int32_t ry,
uint8_t cornername, uint16_t color)
{
if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0)))
{
return;
}
if (ry == 0)
{
drawFastHLine(x - rx, y, (ry << 2) + 1, color);
return;
}
if (rx == 0)
{
drawFastVLine(x, y - ry, (rx << 2) + 1, color);
return;
}
int32_t xt, yt, s, i;
int32_t rx2 = rx * rx;
int32_t ry2 = ry * ry;
i = -1;
xt = 0;
yt = ry;
s = (ry2 << 1) + rx2 * (1 - (ry << 1));
do
{
while (s < 0)
s += ry2 * ((++xt << 2) + 2);
if (cornername & 0x1)
{
writeFastHLine(x - xt, y - yt, xt - i, color);
}
if (cornername & 0x2)
{
writeFastHLine(x + i + 1, y - yt, xt - i, color);
}
if (cornername & 0x4)
{
writeFastHLine(x + i + 1, y + yt, xt - i, color);
}
if (cornername & 0x8)
{
writeFastHLine(x - xt, y + yt, xt - i, color);
}
i = xt;
s -= (--yt) * rx2 << 2;
} while (ry2 * xt <= rx2 * yt);
i = -1;
yt = 0;
xt = rx;
s = (rx2 << 1) + ry2 * (1 - (rx << 1));
do
{
while (s < 0)
s += rx2 * ((++yt << 2) + 2);
if (cornername & 0x1)
{
writeFastVLine(x - xt, y - yt, yt - i, color);
}
if (cornername & 0x2)
{
writeFastVLine(x + xt, y - yt, yt - i, color);
}
if (cornername & 0x4)
{
writeFastVLine(x + xt, y + i + 1, yt - i, color);
}
if (cornername & 0x8)
{
writeFastVLine(x - xt, y + i + 1, yt - i, color);
}
i = yt;
s -= (--xt) * ry2 << 2;
} while (rx2 * yt <= ry2 * xt);
}
/**************************************************************************/
/*!
@brief Draw a circle with filled color
@param x Center-point x coordinate
@param y Center-point y coordinate
@param r Radius of circle
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillCircle(int16_t x, int16_t y,
int16_t r, uint16_t color)
{
startWrite();
fillEllipseHelper(x, y, r, r, 3, 0, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Quarter-circle drawer with fill, used for circles and roundrects
@param x Center-point x coordinate
@param y Center-point y coordinate
@param rx Radius of x coordinate
@param ry Radius of y coordinate
@param corners Mask bits indicating which quarters we're doing
@param delta Offset from center-point, used for round-rects
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillEllipseHelper(int32_t x, int32_t y,
int32_t rx, int32_t ry,
uint8_t corners, int16_t delta, uint16_t color)
{
if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0)))
{
return;
}
if (ry == 0)
{
drawFastHLine(x - rx, y, (ry << 2) + 1, color);
return;
}
if (rx == 0)
{
drawFastVLine(x, y - ry, (rx << 2) + 1, color);
return;
}
int32_t xt, yt, i;
int32_t rx2 = (int32_t)rx * rx;
int32_t ry2 = (int32_t)ry * ry;
int32_t s;
writeFastHLine(x - rx, y, (rx << 1) + 1, color);
i = 0;
yt = 0;
xt = rx;
s = (rx2 << 1) + ry2 * (1 - (rx << 1));
do
{
while (s < 0)
{
s += rx2 * ((++yt << 2) + 2);
}
if (corners & 1)
{
writeFillRect(x - xt, y - yt, (xt << 1) + 1 + delta, yt - i, color);
}
if (corners & 2)
{
writeFillRect(x - xt, y + i + 1, (xt << 1) + 1 + delta, yt - i, color);
}
i = yt;
s -= (--xt) * ry2 << 2;
} while (rx2 * yt <= ry2 * xt);
xt = 0;
yt = ry;
s = (ry2 << 1) + rx2 * (1 - (ry << 1));
do
{
while (s < 0)
{
s += ry2 * ((++xt << 2) + 2);
}
if (corners & 1)
{
writeFastHLine(x - xt, y - yt, (xt << 1) + 1 + delta, color);
}
if (corners & 2)
{
writeFastHLine(x - xt, y + yt, (xt << 1) + 1 + delta, color);
}
s -= (--yt) * rx2 << 2;
} while (ry2 * xt <= rx2 * yt);
}
/**************************************************************************/
/*!
@brief Draw an ellipse outline
@param x Center-point x coordinate
@param y Center-point y coordinate
@param rx radius of x coordinate
@param ry radius of y coordinate
@param start degree of ellipse start
@param end degree of ellipse end
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color)
{
startWrite();
drawEllipseHelper(x, y, rx, ry, 0xf, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw an ellipse with filled color
@param x Center-point x coordinate
@param y Center-point y coordinate
@param rx radius of x coordinate
@param ry radius of y coordinate
@param start degree of ellipse start
@param end degree of ellipse end
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color)
{
startWrite();
fillEllipseHelper(x, y, rx, ry, 3, 0, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw an arc outline
@param x Center-point x coordinate
@param y Center-point y coordinate
@param r1 Outer radius of arc
@param r2 Inner radius of arc
@param start degree of arc start
@param end degree of arc end
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color)
{
if (r1 < r2)
{
_swap_int16_t(r1, r2);
}
if (r1 < 1)
{
r1 = 1;
}
if (r2 < 1)
{
r2 = 1;
}
bool equal = fabsf(start - end) < FLT_EPSILON;
start = fmodf(start, 360);
end = fmodf(end, 360);
if (start < 0)
start += 360.0;
if (end < 0)
end += 360.0;
startWrite();
fillArcHelper(x, y, r1, r2, start, start, color);
fillArcHelper(x, y, r1, r2, end, end, color);
if (!equal && (fabsf(start - end) <= 0.0001))
{
start = .0;
end = 360.0;
}
fillArcHelper(x, y, r1, r1, start, end, color);
fillArcHelper(x, y, r2, r2, start, end, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw an arc with filled color
@param x Center-point x coordinate
@param y Center-point y coordinate
@param r1 Outer radius of arc
@param r2 Inner radius of arc
@param start degree of arc start
@param end degree of arc end
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color)
{
if (r1 < r2)
{
_swap_int16_t(r1, r2);
}
if (r1 < 1)
{
r1 = 1;
}
if (r2 < 1)
{
r2 = 1;
}
bool equal = fabsf(start - end) < FLT_EPSILON;
start = fmodf(start, 360);
end = fmodf(end, 360);
if (start < 0)
start += 360.0;
if (end < 0)
end += 360.0;
if (!equal && (fabsf(start - end) <= 0.0001))
{
start = .0;
end = 360.0;
}
startWrite();
fillArcHelper(x, y, r1, r2, start, end, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Arc drawer with fill
@param cx Center-point x coordinate
@param cy Center-point y coordinate
@param oradius Outer radius of arc
@param iradius Inner radius of arc
@param start degree of arc start
@param end degree of arc end
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Arduino_GFX::fillArcHelper(int16_t cx, int16_t cy, int16_t oradius, int16_t iradius, float start, float end, uint16_t color)
{
if ((start == 90.0) || (start == 180.0) || (start == 270.0) || (start == 360.0))
{
start -= 0.1;
}
if ((end == 90.0) || (end == 180.0) || (end == 270.0) || (end == 360.0))
{
end -= 0.1;
}
float s_cos = (cos(start * DEGTORAD));
float e_cos = (cos(end * DEGTORAD));
float sslope = s_cos / (sin(start * DEGTORAD));
float eslope = e_cos / (sin(end * DEGTORAD));
float swidth = 0.5 / s_cos;
float ewidth = -0.5 / e_cos;
--iradius;
int32_t ir2 = iradius * iradius + iradius;
int32_t or2 = oradius * oradius + oradius;
bool start180 = !(start < 180.0);
bool end180 = end < 180.0;
bool reversed = start + 180.0 < end || (end < start && start < end + 180.0);
int32_t xs = -oradius;
int32_t y = -oradius;
int32_t ye = oradius;
int32_t xe = oradius + 1;
if (!reversed)
{
if ((end >= 270 || end < 90) && (start >= 270 || start < 90))
{
xs = 0;
}
else if (end < 270 && end >= 90 && start < 270 && start >= 90)
{
xe = 1;
}
if (end >= 180 && start >= 180)
{
ye = 0;
}
else if (end < 180 && start < 180)
{
y = 0;
}
}
do
{
int32_t y2 = y * y;
int32_t x = xs;
if (x < 0)
{
while (x * x + y2 >= or2)
{
++x;
}
if (xe != 1)
{
xe = 1 - x;
}
}
float ysslope = (y + swidth) * sslope;
float yeslope = (y + ewidth) * eslope;
int32_t len = 0;
do
{
bool flg1 = start180 != (x <= ysslope);
bool flg2 = end180 != (x <= yeslope);
int32_t distance = x * x + y2;
if (distance >= ir2 && ((flg1 && flg2) || (reversed && (flg1 || flg2))) && x != xe && distance < or2)
{
++len;
}
else
{
if (len)
{
writeFastHLine(cx + x - len, cy + y, len, color);
len = 0;
}
if (distance >= or2)
break;
if (x < 0 && distance < ir2)
{
x = -x;
}
}
} while (++x <= xe);
} while (++y <= ye);
}
/**************************************************************************/
/*!
@brief Draw a rectangle with no fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color)
{
startWrite();
writeFastHLine(x, y, w, color);
writeFastHLine(x, y + h - 1, w, color);
writeFastVLine(x, y, h, color);
writeFastVLine(x + w - 1, y, h, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a rounded rectangle with no fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param r Radius of corner rounding
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
int16_t h, int16_t r, uint16_t color)
{
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
if (r > max_radius)
r = max_radius;
// smarter version
startWrite();
writeFastHLine(x + r, y, w - 2 * r, color); // Top
writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
writeFastVLine(x, y + r, h - 2 * r, color); // Left
writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
// draw four corners
drawEllipseHelper(x + r, y + r, r, r, 1, color);
drawEllipseHelper(x + w - r - 1, y + r, r, r, 2, color);
drawEllipseHelper(x + w - r - 1, y + h - r - 1, r, r, 4, color);
drawEllipseHelper(x + r, y + h - r - 1, r, r, 8, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a rounded rectangle with fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param r Radius of corner rounding
@param color 16-bit 5-6-5 Color to draw/fill with
*/
/**************************************************************************/
void Arduino_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
int16_t h, int16_t r, uint16_t color)
{
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
if (r > max_radius)
r = max_radius;
// smarter version
startWrite();
writeFillRect(x, y + r, w, h - (r << 1), color);
// draw four corners
fillEllipseHelper(x + r, y + r, r, r, 1, w - 2 * r - 1, color);
fillEllipseHelper(x + r, y + h - r - 1, r, r, 2, w - 2 * r - 1, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a triangle with no fill color
@param x0 Vertex #0 x coordinate
@param y0 Vertex #0 y coordinate
@param x1 Vertex #1 x coordinate
@param y1 Vertex #1 y coordinate
@param x2 Vertex #2 x coordinate
@param y2 Vertex #2 y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawTriangle(int16_t x0, int16_t y0,
int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
{
startWrite();
writeLine(x0, y0, x1, y1, color);
writeLine(x1, y1, x2, y2, color);
writeLine(x2, y2, x0, y0, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a triangle with color-fill
@param x0 Vertex #0 x coordinate
@param y0 Vertex #0 y coordinate
@param x1 Vertex #1 x coordinate
@param y1 Vertex #1 y coordinate
@param x2 Vertex #2 x coordinate
@param y2 Vertex #2 y coordinate
@param color 16-bit 5-6-5 Color to fill/draw with
*/
/**************************************************************************/
void Arduino_GFX::fillTriangle(int16_t x0, int16_t y0,
int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
{
int16_t a, b, y, last;
// Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1)
{
_swap_int16_t(y0, y1);
_swap_int16_t(x0, x1);
}
if (y1 > y2)
{
_swap_int16_t(y2, y1);
_swap_int16_t(x2, x1);
}
if (y0 > y1)
{
_swap_int16_t(y0, y1);
_swap_int16_t(x0, x1);
}
startWrite();
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;
writeFastHLine(a, y0, b - a + 1, color);
endWrite();
return;
}
int16_t
dx01 = x1 - x0,
dy01 = y1 - y0,
dx02 = x2 - x0,
dy02 = y2 - y0,
dx12 = x2 - x1,
dy12 = y2 - y1;
int32_t
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;
/* longhand:
a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if (a > b)
{
_swap_int16_t(a, b);
}
writeFastHLine(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 = (int32_t)dx12 * (y - y1);
sb = (int32_t)dx02 * (y - y0);
for (; y <= y2; y++)
{
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
/* longhand:
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if (a > b)
{
_swap_int16_t(a, b);
}
writeFastHLine(a, y, b - a + 1, color);
}
endWrite();
}
// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with monochrome bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
{
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
}
if (byte & 0x80)
{
writePixel(x + i, y, color);
}
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with monochrome bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
@param color 16-bit 5-6-5 Color to draw pixels with
@param bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], int16_t w, int16_t h,
uint16_t color, uint16_t bg)
{
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
}
writePixel(x + i, y, (byte & 0x80) ? color : bg);
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with monochrome bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
{
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = bitmap[j * byteWidth + i / 8];
}
if (byte & 0x80)
{
writePixel(x + i, y, color);
}
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with monochrome bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
@param color 16-bit 5-6-5 Color to draw pixels with
@param bg 16-bit 5-6-5 Color to draw background with
*/
/**************************************************************************/
void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
{
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = bitmap[j * byteWidth + i / 8];
}
writePixel(x + i, y, (byte & 0x80) ? color : bg);
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP.
Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
C Array can be directly used with this function.
There is no RAM-resident version of this function; if generating bitmaps
in RAM, use the format defined by drawBitmap() and call that instead.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with monochrome bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
@param color 16-bit 5-6-5 Color to draw pixels with
*/
/**************************************************************************/
void Arduino_GFX::drawXBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
{
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte >>= 1;
}
else
{
byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
}
// Nearly identical to drawBitmap(), only the bit order
// is reversed here (left-to-right = LSB to MSB):
if (byte & 0x01)
{
writePixel(x + i, y, color);
}
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with grayscale bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], int16_t w, int16_t h)
{
uint8_t v;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]);
writePixel(x + i, y, color565(v, v, v));
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with grayscale bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
uint8_t *bitmap, int16_t w, int16_t h)
{
uint8_t v;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
v = bitmap[j * w + i];
writePixel(x + i, y, color565(v, v, v));
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask
(set bits = opaque, unset bits = clear) at the specified (x,y) position.
BOTH buffers (grayscale and mask) must be PROGMEM-resident.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with grayscale bitmap
@param mask byte array with mask bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], const uint8_t mask[],
int16_t w, int16_t h)
{
int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
uint8_t byte = 0;
uint8_t v;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = pgm_read_byte(&mask[j * bw + i / 8]);
}
if (byte & 0x80)
{
v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]);
writePixel(x + i, y, color565(v, v, v));
}
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask
(set bits = opaque, unset bits = clear) at the specified (x,y) position.
BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with grayscale bitmap
@param mask byte array with mask bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
{
int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
uint8_t byte = 0;
uint8_t v;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = mask[j * bw + i / 8];
}
if (byte & 0x80)
{
v = bitmap[j * w + i];
writePixel(x + i, y, color565(v, v, v));
}
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array of Indexed color bitmap
@param color_index byte array of 16-bit color index
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::drawIndexedBitmap(int16_t x, int16_t y,
uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h)
{
int32_t offset = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
writePixel(x + i, y, color_index[bitmap[offset++]]);
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 3-bit image (RGB 1/1/1) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 3-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw3bitRGBBitmap(int16_t x, int16_t y,
uint8_t *bitmap, int16_t w, int16_t h)
{
int32_t offset = 0, idx = 0;
uint8_t c = 0;
uint16_t d;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (offset & 1)
{
d = (((c & 0b100) ? RED : 0) |
((c & 0b010) ? GREEN : 0) |
((c & 0b001) ? BLUE : 0));
}
else
{
c = bitmap[idx++];
d = (((c & 0b100000) ? RED : 0) |
((c & 0b010000) ? GREEN : 0) |
((c & 0b001000) ? BLUE : 0));
}
writePixel(x + i, y, d);
offset++;
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
const uint16_t bitmap[], int16_t w, int16_t h)
{
int32_t offset = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
writePixel(x + i, y, pgm_read_word(&bitmap[offset++]));
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, int16_t w, int16_t h)
{
int32_t offset = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
writePixel(x + i, y, bitmap[offset++]);
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 16-bit Big Endian image (RGB 5/6/5) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw16bitBeRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, int16_t w, int16_t h)
{
int32_t offset = 0;
uint16_t p;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
p = bitmap[offset++];
MSB_16_SET(p, p);
writePixel(x + i, y, p);
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask
(set bits = opaque, unset bits = clear) at the specified (x,y) position.
BOTH buffers (color and mask) must be PROGMEM-resident.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param mask byte array with monochrome mask bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
const uint16_t bitmap[], const uint8_t mask[],
int16_t w, int16_t h)
{
int32_t offset = 0;
int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = pgm_read_byte(&mask[j * bw + i / 8]);
}
if (byte & 0x80)
{
writePixel(x + i, y, pgm_read_word(&bitmap[offset]));
}
offset++;
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask
(set bits = opaque, unset bits = clear) at the specified (x,y) position.
BOTH buffers (color and mask) must be RAM-resident.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param mask byte array with monochrome mask bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
{
int32_t offset = 0, maskIdx = 0;
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = mask[maskIdx++];
}
if (byte & 0x80)
{
writePixel(x + i, y, bitmap[offset]);
}
offset++;
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], int16_t w, int16_t h)
{
int32_t offset = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2])));
offset += 3;
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
uint8_t *bitmap, int16_t w, int16_t h)
{
int32_t offset = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2]));
offset += 3;
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask
(set bits = opaque, unset bits = clear) at the specified (x,y) position.
BOTH buffers (color and mask) must be PROGMEM-resident.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param mask byte array with monochrome mask bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], const uint8_t mask[],
int16_t w, int16_t h)
{
int32_t offset = 0;
int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = pgm_read_byte(&mask[j * bw + i / 8]);
}
if (byte & 0x80)
{
writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2])));
}
offset += 3;
}
}
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask
(set bits = opaque, unset bits = clear) at the specified (x,y) position.
BOTH buffers (color and mask) must be RAM-resident.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with 16-bit color bitmap
@param mask byte array with monochrome mask bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
{
int32_t offset = 0;
int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
{
byte <<= 1;
}
else
{
byte = mask[j * bw + i / 8];
}
if (byte & 0x80)
{
writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2]));
}
offset += 3;
}
}
endWrite();
}
#if defined(U8G2_FONT_SUPPORT)
uint16_t Arduino_GFX::u8g2_font_get_word(const uint8_t *font, uint8_t offset)
{
uint16_t pos;
font += offset;
pos = pgm_read_byte(font);
font++;
pos <<= 8;
pos += pgm_read_byte(font);
return pos;
}
uint8_t Arduino_GFX::u8g2_font_decode_get_unsigned_bits(uint8_t cnt)
{
uint8_t val;
uint8_t bit_pos = _u8g2_decode_bit_pos;
uint8_t bit_pos_plus_cnt;
val = pgm_read_byte(_u8g2_decode_ptr);
val >>= bit_pos;
bit_pos_plus_cnt = bit_pos;
bit_pos_plus_cnt += cnt;
if (bit_pos_plus_cnt >= 8)
{
uint8_t s = 8;
s -= bit_pos;
_u8g2_decode_ptr++;
val |= pgm_read_byte(_u8g2_decode_ptr) << (s);
bit_pos_plus_cnt -= 8;
}
val &= (1U << cnt) - 1;
_u8g2_decode_bit_pos = bit_pos_plus_cnt;
return val;
}
int8_t Arduino_GFX::u8g2_font_decode_get_signed_bits(uint8_t cnt)
{
int8_t v, d;
v = (int8_t)u8g2_font_decode_get_unsigned_bits(cnt);
d = 1;
cnt--;
d <<= cnt;
v -= d;
return v;
}
void Arduino_GFX::u8g2_font_decode_len(uint8_t len, uint8_t is_foreground, uint16_t color, uint16_t bg)
{
uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
uint8_t rem; /* remaining pixel to the right edge of the glyph */
uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
/* current is either equal to cnt or equal to rem */
/* target position on the screen */
uint16_t x, y;
cnt = len;
/* get the local position */
uint8_t lx = _u8g2_dx;
uint8_t ly = _u8g2_dy;
for (;;)
{
/* calculate the number of pixel to the right edge of the glyph */
rem = _u8g2_char_width;
rem -= lx;
/* calculate how many pixel to draw. This is either to the right edge */
/* or lesser, if not enough pixel are left */
current = rem;
if (cnt < rem)
current = cnt;
/* now draw the line, but apply the rotation around the glyph target position */
// u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
if (textsize_x == 1 && textsize_y == 1)
{
/* get target position */
x = _u8g2_target_x + lx;
y = _u8g2_target_y + ly;
/* draw foreground and background (if required) */
if (is_foreground)
{
writeFastHLine(x, y, current, color);
}
else if (bg != color)
{
writeFastHLine(x, y, current, bg);
}
}
else
{
/* get target position */
x = _u8g2_target_x + (lx * textsize_x);
y = _u8g2_target_y + (ly * textsize_y);
/* draw foreground and background (if required) */
if (is_foreground)
{
writeFillRect(x, y, (current * textsize_x) - text_pixel_margin,
textsize_y - text_pixel_margin, color);
}
else if (bg != color)
{
writeFillRect(x, y, (current * textsize_x) - text_pixel_margin,
textsize_y - text_pixel_margin, bg);
}
}
/* check, whether the end of the run length code has been reached */
if (cnt < rem)
break;
cnt -= rem;
lx = 0;
ly++;
}
lx += cnt;
_u8g2_dx = lx;
_u8g2_dy = ly;
}
#endif // defined(U8G2_FONT_SUPPORT)
// TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
// Draw a character
/**************************************************************************/
/*!
@brief Draw a single character
@param x Bottom left corner x coordinate
@param y Bottom left corner y coordinate
@param c The 8-bit font-indexed character (likely ascii)
@param color 16-bit 5-6-5 Color to draw chraracter with
@param bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
*/
/**************************************************************************/
void Arduino_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
uint16_t color, uint16_t bg)
{
int16_t block_w;
int16_t block_h;
#if !defined(ATTINY_CORE)
if (gfxFont) // custom font
{
// Character is assumed previously filtered by write() to eliminate
// newlines, returns, non-printable characters, etc. Calling
// drawChar() directly with 'bad' characters of font may cause mayhem!
c -= (uint8_t)pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height),
xAdvance = pgm_read_byte(&glyph->xAdvance),
yAdvance = pgm_read_byte(&gfxFont->yAdvance),
baseline = yAdvance * 2 / 3; // TODO: baseline is an arbitrary currently, may be define in font file
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 = xo, yo16 = yo;
if (xAdvance < w)
{
xAdvance = w; // Don't know why it exists
}
block_w = xAdvance * textsize_x;
block_h = yAdvance * textsize_y;
if (
(x > _max_x) || // Clip right
(y > _max_y) || // Clip bottom
((x + block_w - 1) < 0) || // Clip left
((y + block_h - 1) < 0) // Clip top
)
{
return;
}
// NOTE: Different from Adafruit_GFX design, Adruino_GFX also cater background.
// Since it may introduce many ugly output, it should limited using on mono font only.
startWrite();
if (bg != color) // have background color
{
writeFillRect(x, y - (baseline * textsize_y), block_w, block_h, bg);
}
for (yy = 0; yy < h; yy++)
{
for (xx = 0; xx < w; xx++)
{
if (!(bit++ & 7))
{
bits = pgm_read_byte(&bitmap[bo++]);
}
if (bits & 0x80)
{
if (textsize_x == 1 && textsize_y == 1)
{
writePixel(x + xo + xx, y + yo + yy, color);
}
else
{
writeFillRect(x + (xo16 + xx) * textsize_x, y + (yo16 + yy) * textsize_y,
textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
}
}
bits <<= 1;
}
}
endWrite();
}
else // 'Classic' built-in font
#endif // !defined(ATTINY_CORE)
#if defined(U8G2_FONT_SUPPORT)
if (u8g2Font)
{
if ((_u8g2_decode_ptr) && (_u8g2_char_width > 0))
{
uint8_t a, b;
_u8g2_target_x = x + (_u8g2_char_x * textsize_x);
_u8g2_target_y = y - ((_u8g2_char_height + _u8g2_char_y) * textsize_y);
// log_d("_u8g2_target_x: %d, _u8g2_target_y: %d", _u8g2_target_x, _u8g2_target_y);
/* reset local x/y position */
_u8g2_dx = 0;
_u8g2_dy = 0;
/* decode glyph */
startWrite();
for (;;)
{
a = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_0);
b = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_1);
// log_d("a: %d, b: %d", a, b);
do
{
u8g2_font_decode_len(a, 0, color, bg);
u8g2_font_decode_len(b, 1, color, bg);
} while (u8g2_font_decode_get_unsigned_bits(1) != 0);
if (_u8g2_dy >= _u8g2_char_height)
break;
}
endWrite();
}
}
else // glcdfont
#endif // defined(U8G2_FONT_SUPPORT)
{
block_w = 6 * textsize_x;
block_h = 8 * textsize_y;
if (
(x > _max_x) || // Clip right
(y > _max_y) || // Clip bottom
((x + block_w - 1) < 0) || // Clip left
((y + block_h - 1) < 0) // Clip top
)
{
return;
}
startWrite();
for (int8_t i = 0; i < 5; i++)
{ // Char bitmap = 5 columns
uint8_t line = pgm_read_byte(&font[c * 5 + i]);
for (int8_t j = 0; j < 8; j++, line >>= 1)
{
if (line & 1)
{
if (textsize_x == 1 && textsize_y == 1)
{
writePixel(x + i, y + j, color);
}
else
{
if (text_pixel_margin > 0)
{
writeFillRect(x + (i * textsize_x), y + j * textsize_y, textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
writeFillRect(x + ((i + 1) * textsize_x) - text_pixel_margin, y + j * textsize_y, text_pixel_margin, textsize_y, bg);
writeFillRect(x + (i * textsize_x), y + ((j + 1) * textsize_y) - text_pixel_margin, textsize_x - text_pixel_margin, text_pixel_margin, bg);
}
else
{
writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, color);
}
}
}
else if (bg != color)
{
if (textsize_x == 1 && textsize_y == 1)
{
writePixel(x + i, y + j, bg);
}
else
{
writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, bg);
}
}
}
}
if (bg != color)
{ // If opaque, draw vertical line for last column
if (textsize_x == 1 && textsize_y == 1)
{
writeFastVLine(x + 5, y, 8, bg);
}
else
{
writeFillRect(x + 5 * textsize_x, y, textsize_x, 8 * textsize_y, bg);
}
}
endWrite();
}
}
/**************************************************************************/
/*!
@brief Print one byte/character of data, used to support print()
@param c The 8-bit ascii character to write
*/
/**************************************************************************/
size_t Arduino_GFX::write(uint8_t c)
{
#if !defined(ATTINY_CORE)
if (gfxFont) // custom font
{
if (c == '\n')
{
cursor_x = 0;
cursor_y += (int16_t)textsize_y *
(uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
else if (c != '\r')
{
uint8_t first = pgm_read_byte(&gfxFont->first);
if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last)))
{
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
uint8_t w = pgm_read_byte(&glyph->xAdvance);
// int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
if (wrap && ((cursor_x + (textsize_x * w) - 1) > _max_x))
{
cursor_x = 0;
cursor_y += (int16_t)textsize_y *
(uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
cursor_x += textsize_x * w;
}
}
}
else // 'Classic' built-in font
#endif // !defined(ATTINY_CORE)
#if defined(U8G2_FONT_SUPPORT)
if (u8g2Font)
{
_u8g2_decode_ptr = 0;
if (_enableUTF8Print)
{
if (_utf8_state == 0)
{
if (c >= 0xfc) /* 6 byte sequence */
{
_utf8_state = 5;
c &= 1;
}
else if (c >= 0xf8)
{
_utf8_state = 4;
c &= 3;
}
else if (c >= 0xf0)
{
_utf8_state = 3;
c &= 7;
}
else if (c >= 0xe0)
{
_utf8_state = 2;
c &= 15;
}
else if (c >= 0xc0)
{
_utf8_state = 1;
c &= 0x01f;
}
_encoding = c;
}
else
{
_utf8_state--;
/* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
_encoding <<= 6;
c &= 0x03f;
_encoding |= c;
}
} // _enableUTF8Print
else
{
_encoding = c;
}
if (_utf8_state == 0)
{
if (_encoding == '\n')
{
cursor_x = 0;
cursor_y += (int16_t)textsize_y * _u8g2_max_char_height;
}
else if (_encoding != '\r')
{ // Ignore carriage returns
uint8_t *font = u8g2Font;
const uint8_t *glyph_data = 0;
// extract from u8g2_font_get_glyph_data()
font += 23; // U8G2_FONT_DATA_STRUCT_SIZE
if (_encoding <= 255)
{
if (_encoding >= 'a')
{
font += _u8g2_start_pos_lower_a;
}
else if (_encoding >= 'A')
{
font += _u8g2_start_pos_upper_A;
}
for (;;)
{
if (pgm_read_byte(font + 1) == 0)
break;
if (pgm_read_byte(font) == _encoding)
{
glyph_data = font + 2; /* skip encoding and glyph size */
}
font += pgm_read_byte(font + 1);
}
}
#ifdef U8G2_WITH_UNICODE
else
{
uint16_t e;
font += _u8g2_start_pos_unicode;
const uint8_t *unicode_lookup_table = font;
/* issue 596: search for the glyph start in the unicode lookup table */
do
{
font += u8g2_font_get_word(unicode_lookup_table, 0);
e = u8g2_font_get_word(unicode_lookup_table, 2);
unicode_lookup_table += 4;
} while (e < _encoding);
for (;;)
{
e = u8g2_font_get_word(font, 0);
if (e == 0)
break;
if (e == _encoding)
{
glyph_data = font + 3; /* skip encoding and glyph size */
break;
}
font += pgm_read_byte(font + 2);
}
}
#endif
if (glyph_data)
{
// u8g2_font_decode_glyph
_u8g2_decode_ptr = glyph_data;
_u8g2_decode_bit_pos = 0;
_u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width);
_u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height);
_u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x);
_u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y);
_u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x);
// log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d",
// c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x);
if (_u8g2_char_width > 0)
{
if (wrap && ((cursor_x + (textsize_x * _u8g2_char_width) - 1) > _max_x))
{
cursor_x = 0;
cursor_y += (int16_t)textsize_y * _u8g2_max_char_height;
}
}
drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
cursor_x += textsize_x * _u8g2_delta_x;
}
}
}
}
else // glcdfont
#endif // defined(U8G2_FONT_SUPPORT)
{
if (c == '\n')
{ // Newline?
cursor_x = 0; // Reset x to zero,
cursor_y += textsize_y * 8; // advance y one line
}
else if (c != '\r')
{ // Ignore carriage returns
if (wrap && ((cursor_x + (textsize_x * 6) - 1) > _max_x))
{ // Off right?
cursor_x = 0; // Reset x to zero,
cursor_y += textsize_y * 8; // advance y one line
}
drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
cursor_x += textsize_x * 6; // Advance x one char
}
}
return 1;
}
/**************************************************************************/
/*!
@brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
@param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
*/
/**************************************************************************/
void Arduino_GFX::setTextSize(uint8_t s)
{
setTextSize(s, s, 0);
}
/**************************************************************************/
/*!
@brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
@param s_x Desired text width magnification level in X-axis. 1 is default
@param s_y Desired text width magnification level in Y-axis. 1 is default
*/
/**************************************************************************/
void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y)
{
setTextSize(s_x, s_y, 0);
}
/**************************************************************************/
/*!
@brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
@param s_x Desired text width magnification level in X-axis. 1 is default
@param s_y Desired text width magnification level in Y-axis. 1 is default
@param pixel_margin Margin for each text pixel. 0 is default
*/
/**************************************************************************/
void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y, uint8_t pixel_margin)
{
text_pixel_margin = ((pixel_margin < s_x) && (pixel_margin < s_y)) ? pixel_margin : 0;
textsize_x = (s_x > 0) ? s_x : 1;
textsize_y = (s_y > 0) ? s_y : 1;
}
/**************************************************************************/
/*!
@brief Set rotation setting for display
@param r 0 thru 3 corresponding to 4 cardinal rotations
*/
/**************************************************************************/
void Arduino_GFX::setRotation(uint8_t r)
{
_rotation = (r & 7);
switch (_rotation)
{
case 7:
case 5:
case 3:
case 1:
_width = HEIGHT;
_height = WIDTH;
_max_x = _width - 1; ///< x zero base bound
_max_y = _height - 1; ///< y zero base bound
break;
case 6:
case 4:
case 2:
default: // case 0:
_width = WIDTH;
_height = HEIGHT;
_max_x = _width - 1; ///< x zero base bound
_max_y = _height - 1; ///< y zero base bound
break;
}
}
#if !defined(ATTINY_CORE)
/**************************************************************************/
/*!
@brief Set the font to display when print()ing, either custom or default
@param f The GFXfont object, if NULL use built in 6x8 font
*/
/**************************************************************************/
void Arduino_GFX::setFont(const GFXfont *f)
{
gfxFont = (GFXfont *)f;
#if defined(U8G2_FONT_SUPPORT)
u8g2Font = NULL;
#endif // defined(U8G2_FONT_SUPPORT)
}
/**************************************************************************/
/*!
@brief flush framebuffer to output (for Canvas or NeoPixel sub-class)
*/
/**************************************************************************/
void Arduino_GFX::flush()
{
}
#endif // !defined(ATTINY_CORE)
#if defined(U8G2_FONT_SUPPORT)
void Arduino_GFX::setFont(const uint8_t *font)
{
gfxFont = NULL;
u8g2Font = (uint8_t *)font;
// extract from u8g2_read_font_info()
/* offset 0 */
_u8g2_glyph_cnt = pgm_read_byte(font);
// uint8_t bbx_mode = pgm_read_byte(font + 1);
_u8g2_bits_per_0 = pgm_read_byte(font + 2);
_u8g2_bits_per_1 = pgm_read_byte(font + 3);
// log_d("_u8g2_glyph_cnt: %d, bbx_mode: %d, _u8g2_bits_per_0: %d, _u8g2_bits_per_1: %d",
// _u8g2_glyph_cnt, bbx_mode, _u8g2_bits_per_0, _u8g2_bits_per_1);
/* offset 4 */
_u8g2_bits_per_char_width = pgm_read_byte(font + 4);
_u8g2_bits_per_char_height = pgm_read_byte(font + 5);
_u8g2_bits_per_char_x = pgm_read_byte(font + 6);
_u8g2_bits_per_char_y = pgm_read_byte(font + 7);
_u8g2_bits_per_delta_x = pgm_read_byte(font + 8);
// log_d("_u8g2_bits_per_char_width: %d, _u8g2_bits_per_char_height: %d, _u8g2_bits_per_char_x: %d, _u8g2_bits_per_char_y: %d, _u8g2_bits_per_delta_x: %d",
// _u8g2_bits_per_char_width, _u8g2_bits_per_char_height, _u8g2_bits_per_char_x, _u8g2_bits_per_char_y, _u8g2_bits_per_delta_x);
/* offset 9 */
_u8g2_max_char_width = pgm_read_byte(font + 9);
_u8g2_max_char_height = pgm_read_byte(font + 10);
// int8_t x_offset = pgm_read_byte(font + 11);
// int8_t y_offset = pgm_read_byte(font + 12);
// log_d("_u8g2_max_char_width: %d, _u8g2_max_char_height: %d, x_offset: %d, y_offset: %d",
// _u8g2_max_char_width, _u8g2_max_char_height, x_offset, y_offset);
/* offset 13 */
// int8_t ascent_A = pgm_read_byte(font + 13);
// int8_t descent_g = pgm_read_byte(font + 14);
// int8_t ascent_para = pgm_read_byte(font + 15);
// int8_t descent_para = pgm_read_byte(font + 16);
// log_d("ascent_A: %d, descent_g: %d, ascent_para: %d, descent_para: %d",
// ascent_A, descent_g, ascent_para, descent_para);
/* offset 17 */
_u8g2_start_pos_upper_A = u8g2_font_get_word(font, 17);
_u8g2_start_pos_lower_a = u8g2_font_get_word(font, 19);
#ifdef U8G2_WITH_UNICODE
_u8g2_start_pos_unicode = u8g2_font_get_word(font, 21);
#endif
_u8g2_first_char = pgm_read_byte(font + 23);
// log_d("_u8g2_start_pos_upper_A: %d, _u8g2_start_pos_lower_a: %d, _u8g2_start_pos_unicode: %d, _u8g2_first_char: %d",
// _u8g2_start_pos_upper_A, _u8g2_start_pos_lower_a, _u8g2_start_pos_unicode, _u8g2_first_char);
}
void Arduino_GFX::setUTF8Print(bool isEnable)
{
_enableUTF8Print = isEnable;
}
#endif // defined(U8G2_FONT_SUPPORT)
/**************************************************************************/
/*!
@brief Helper to determine size of a character with current font/size.
Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
@param c The ascii character in question
@param x Pointer to x location of character
@param y Pointer to y location of character
@param minx Minimum clipping value for X
@param miny Minimum clipping value for Y
@param maxx Maximum clipping value for X
@param maxy Maximum clipping value for Y
*/
/**************************************************************************/
void Arduino_GFX::charBounds(char c, int16_t *x, int16_t *y,
int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy)
{
#if !defined(ATTINY_CORE)
if (gfxFont) // custom font
{
if (c == '\n')
{ // Newline?
*x = 0; // Reset x to zero, advance y by one line
*y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
else if (c != '\r')
{ // Not a carriage return; is normal char
uint8_t first = pgm_read_byte(&gfxFont->first),
last = pgm_read_byte(&gfxFont->last);
if ((c >= first) && (c <= last))
{ // Char present in this font?
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
uint8_t gw = pgm_read_byte(&glyph->width),
gh = 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);
if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x) - 1) > _max_x))
{
*x = 0; // Reset x to zero, advance y by one line
*y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
}
int16_t tsx = (int16_t)textsize_x,
tsy = (int16_t)textsize_y,
x1 = *x + xo * tsx,
y1 = *y + yo * tsy,
x2 = x1 + gw * tsx - 1,
y2 = y1 + gh * tsy - 1;
if (x1 < *minx)
{
*minx = x1;
}
if (y1 < *miny)
{
*miny = y1;
}
if (x2 > *maxx)
{
*maxx = x2;
}
if (y2 > *maxy)
{
*maxy = y2;
}
*x += xa * tsx;
}
}
}
else // not gfxFont
#endif // !defined(ATTINY_CORE)
#if defined(U8G2_FONT_SUPPORT)
if (u8g2Font)
{
// not yet implement
}
else // glcdfont
#endif // defined(U8G2_FONT_SUPPORT)
{
if (c == '\n')
{ // Newline?
*x = 0; // Reset x to zero,
*y += textsize_y * 8; // advance y one line
// min/max x/y unchaged -- that waits for next 'normal' character
}
else if (c != '\r')
{ // Normal char; ignore carriage returns
if (wrap && ((*x + (textsize_x * 6) - 1) > _max_x))
{ // Off right?
*x = 0; // Reset x to zero,
*y += textsize_y * 8; // advance y one line
}
int16_t x2 = *x + textsize_x * 6 - 1; // Lower-right pixel of char
int16_t y2 = *y + textsize_y * 8 - 1;
if (x2 > *maxx)
{
*maxx = x2; // Track max x, y
}
if (y2 > *maxy)
{
*maxy = y2;
}
if (*x < *minx)
{
*minx = *x; // Track min x, y
}
if (*y < *miny)
{
*miny = *y;
}
*x += textsize_x * 6; // Advance x one char
}
}
}
/**************************************************************************/
/*!
@brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
@param str The ascii string to measure
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, set by function
@param y1 The boundary Y coordinate, set by function
@param w The boundary width, set by function
@param h The boundary height, set by function
*/
/**************************************************************************/
void Arduino_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
{
uint8_t c; // Current character
*x1 = x;
*y1 = y;
*w = *h = 0;
int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
while ((c = *str++))
{
charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
}
if (maxx >= minx)
{
*x1 = minx;
*w = maxx - minx + 1;
}
if (maxy >= miny)
{
*y1 = miny;
*h = maxy - miny + 1;
}
}
/**************************************************************************/
/*!
@brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
@param str The ascii string to measure (as an arduino String() class)
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, set by function
@param y1 The boundary Y coordinate, set by function
@param w The boundary width, set by function
@param h The boundary height, set by function
*/
/**************************************************************************/
void Arduino_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
{
if (str.length() != 0)
{
getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h);
}
}
/**************************************************************************/
/*!
@brief Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
@param str The flash-memory ascii string to measure
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, set by function
@param y1 The boundary Y coordinate, set by function
@param w The boundary width, set by function
@param h The boundary height, set by function
*/
/**************************************************************************/
void Arduino_GFX::getTextBounds(const __FlashStringHelper *str,
int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
{
uint8_t *s = (uint8_t *)str, c;
*x1 = x;
*y1 = y;
*w = *h = 0;
int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
while ((c = pgm_read_byte(s++)))
charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
if (maxx >= minx)
{
*x1 = minx;
*w = maxx - minx + 1;
}
if (maxy >= miny)
{
*y1 = miny;
*h = maxy - miny + 1;
}
}
/**************************************************************************/
/*!
@brief Invert the display (ideally using built-in hardware command)
@param i True if you want to invert, false to make 'normal'
*/
/**************************************************************************/
void Arduino_GFX::invertDisplay(bool i)
{
// Do nothing, must be subclassed if supported by hardware
UNUSED(i);
}
/**************************************************************************/
/*!
@brief Turn on display after turned off
*/
/**************************************************************************/
void Arduino_GFX::displayOn()
{
}
/**************************************************************************/
/*!
@brief Turn off display
*/
/**************************************************************************/
void Arduino_GFX::displayOff()
{
}