Merge pull request #23 from nitko12/master
Added polygon triangulation and drawing + elipse
This commit is contained in:
commit
9bff038099
264
Inkplate.cpp
264
Inkplate.cpp
|
@ -298,12 +298,12 @@ void Inkplate::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, i
|
|||
{
|
||||
for (j = 0; j < xSize - 1; j++)
|
||||
{
|
||||
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i)+j) >> 4) >> 1);
|
||||
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i)+j) & 0xff) >> 1);
|
||||
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1);
|
||||
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1);
|
||||
}
|
||||
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i)+j) >> 4) >> 1);
|
||||
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1);
|
||||
if (_rem == 0)
|
||||
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i)+j) & 0xff) >> 1);
|
||||
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,6 +515,120 @@ int Inkplate::drawBitmapFromWeb(char *url, int x, int y, bool dither, bool inver
|
|||
return ret;
|
||||
}
|
||||
|
||||
void Inkplate::drawElipse(int rx, int ry,
|
||||
int xc, int yc,
|
||||
int c)
|
||||
{
|
||||
float dx, dy, d1, d2, x, y;
|
||||
x = 0;
|
||||
y = ry;
|
||||
|
||||
d1 = (ry * ry) - (rx * rx * ry) +
|
||||
(0.25 * rx * rx);
|
||||
dx = 2 * ry * ry * x;
|
||||
dy = 2 * rx * rx * y;
|
||||
|
||||
while (dx < dy)
|
||||
{
|
||||
drawPixel(x + xc, y + yc, c);
|
||||
drawPixel(-x + xc, y + yc, c);
|
||||
drawPixel(x + xc, -y + yc, c);
|
||||
drawPixel(-x + xc, -y + yc, c);
|
||||
|
||||
if (d1 < 0)
|
||||
{
|
||||
x++;
|
||||
dx = dx + (2 * ry * ry);
|
||||
d1 = d1 + dx + (ry * ry);
|
||||
}
|
||||
else
|
||||
{
|
||||
x++;
|
||||
y--;
|
||||
dx = dx + (2 * ry * ry);
|
||||
dy = dy - (2 * rx * rx);
|
||||
d1 = d1 + dx - dy + (ry * ry);
|
||||
}
|
||||
}
|
||||
|
||||
d2 = ((ry * ry) * ((x + 0.5) * (x + 0.5))) +
|
||||
((rx * rx) * ((y - 1) * (y - 1))) -
|
||||
(rx * rx * ry * ry);
|
||||
while (y >= 0)
|
||||
{
|
||||
drawPixel(x + xc, y + yc, c);
|
||||
drawPixel(-x + xc, y + yc, c);
|
||||
drawPixel(x + xc, -y + yc, c);
|
||||
drawPixel(-x + xc, -y + yc, c);
|
||||
|
||||
if (d2 > 0)
|
||||
{
|
||||
y--;
|
||||
dy = dy - (2 * rx * rx);
|
||||
d2 = d2 + (rx * rx) - dy;
|
||||
}
|
||||
else
|
||||
{
|
||||
y--;
|
||||
x++;
|
||||
dx = dx + (2 * ry * ry);
|
||||
dy = dy - (2 * rx * rx);
|
||||
d2 = d2 + dx - dy + (rx * rx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Inkplate::fillElipse(int rx, int ry,
|
||||
int xc, int yc,
|
||||
int c)
|
||||
{
|
||||
int hh = ry * ry;
|
||||
int ww = rx * rx;
|
||||
int hhww = hh * ww;
|
||||
int x0 = rx;
|
||||
int dx = 0;
|
||||
|
||||
for (int x = -rx; x <= rx; x++)
|
||||
drawPixel(xc + x, yc, c);
|
||||
|
||||
for (int y = 1; y <= ry; y++)
|
||||
{
|
||||
int x1 = x0 - (dx - 1);
|
||||
for (; x1 > 0; x1--)
|
||||
if (x1 * x1 * hh + y * y * ww <= hhww)
|
||||
break;
|
||||
dx = x0 - x1;
|
||||
x0 = x1;
|
||||
|
||||
for (int x = -x0; x <= x0; x++)
|
||||
{
|
||||
drawPixel(xc + x, yc - y, c);
|
||||
drawPixel(xc + x, yc + y, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Inkplate::fillPolygon(int *x, int *y, int n, int color)
|
||||
{
|
||||
int tx[100], ty[100];
|
||||
triangulate.triangulate(x, y, n, tx, ty);
|
||||
|
||||
for (int i = 0; i < n - 2; ++i)
|
||||
{
|
||||
fillTriangle(
|
||||
tx[i * 3 + 0], ty[i * 3 + 0],
|
||||
tx[i * 3 + 1], ty[i * 3 + 1],
|
||||
tx[i * 3 + 2], ty[i * 3 + 2],
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
void Inkplate::drawPolygon(int *x, int *y, int n, int color)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
drawLine(x[i], y[i], x[(i + 1) % n], y[(i + 1) % n], color);
|
||||
}
|
||||
|
||||
void Inkplate::drawThickLine(int x1, int y1, int x2, int y2, int color, float thickness)
|
||||
{
|
||||
float deg = atan2f((float)(y2 - y1), (float)(x2 - x1));
|
||||
|
@ -1088,32 +1202,36 @@ int Inkplate::drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, i
|
|||
|
||||
uint8_t *bufferPtr;
|
||||
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
f->read(pixelBuffer, w * 4 + (paddingBits? 4 : 0));
|
||||
f->read(pixelBuffer, w * 4 + (paddingBits ? 4 : 0));
|
||||
|
||||
ditherStart(pixelBuffer, bufferPtr, w * 8 + (paddingBits? 4 : 0), invert, 4);
|
||||
ditherStart(pixelBuffer, bufferPtr, w * 8 + (paddingBits ? 4 : 0), invert, 4);
|
||||
}
|
||||
|
||||
for (j = 0; j < h; j++)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
f->read(pixelBuffer, w * 4 + (paddingBits? 4 : 0));
|
||||
f->read(pixelBuffer, w * 4 + (paddingBits ? 4 : 0));
|
||||
|
||||
if (dither && j != h - 1) {
|
||||
ditherLoadNextLine(pixelBuffer, bufferPtr, w * 8 + (paddingBits? 4 : 0), invert, 4);
|
||||
if (dither && j != h - 1)
|
||||
{
|
||||
ditherLoadNextLine(pixelBuffer, bufferPtr, w * 8 + (paddingBits ? 4 : 0), invert, 4);
|
||||
}
|
||||
|
||||
for (i = 0; i < w; i++)
|
||||
{
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
|
||||
for (int n = 0; n < 8; n++)
|
||||
{
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits? 4 : 0), h) >> 5);
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits ? 4 : 0), h) >> 5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++);
|
||||
if (invert)
|
||||
pixelRow = ~pixelRow;
|
||||
|
@ -1125,13 +1243,15 @@ int Inkplate::drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, i
|
|||
}
|
||||
if (paddingBits)
|
||||
{
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
for (int n = 0; n < paddingBits; n++)
|
||||
{
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits? 4 : 0), h) >> 5);
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits ? 4 : 0), h) >> 5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++);
|
||||
if (invert)
|
||||
pixelRow = ~pixelRow;
|
||||
|
@ -1158,7 +1278,8 @@ int Inkplate::drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, i
|
|||
|
||||
uint8_t *bufferPtr;
|
||||
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
f->read(pixelBuffer, w);
|
||||
|
||||
|
@ -1170,7 +1291,8 @@ int Inkplate::drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, i
|
|||
bufferPtr = pixelBuffer;
|
||||
f->read(pixelBuffer, w);
|
||||
|
||||
if (dither && j != h - 1) {
|
||||
if (dither && j != h - 1)
|
||||
{
|
||||
ditherLoadNextLine(pixelBuffer, bufferPtr, w, invert, 8);
|
||||
}
|
||||
|
||||
|
@ -1178,7 +1300,8 @@ int Inkplate::drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, i
|
|||
{
|
||||
if (dither)
|
||||
drawPixel(i + x, h - 1 - j + y, ditherGetPixel(i, j, w, h) >> 5);
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint8_t px = 0;
|
||||
if (invert)
|
||||
px = 255 - *(bufferPtr++);
|
||||
|
@ -1213,7 +1336,8 @@ int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader,
|
|||
|
||||
uint8_t *bufferPtr;
|
||||
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
f->read(pixelBuffer, w * 3);
|
||||
|
||||
|
@ -1225,7 +1349,8 @@ int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader,
|
|||
bufferPtr = pixelBuffer;
|
||||
f->read(pixelBuffer, w * 3);
|
||||
|
||||
if (dither && j != h - 1) {
|
||||
if (dither && j != h - 1)
|
||||
{
|
||||
ditherLoadNextLine(pixelBuffer, bufferPtr, w, invert, 24);
|
||||
}
|
||||
|
||||
|
@ -1238,7 +1363,8 @@ int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader,
|
|||
|
||||
if (dither)
|
||||
drawPixel(i + x, h - 1 - j + y, ditherGetPixel(i, j, w, h) >> 5);
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint8_t px = 0;
|
||||
//So then, we are convertng it to grayscale using good old average and gamma correction (from LUT). With this metod, it is still slow (full size image takes 4 seconds), but much beter than prev mentioned method.
|
||||
if (invert)
|
||||
|
@ -1268,31 +1394,38 @@ int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader,
|
|||
}
|
||||
|
||||
//Loads first line in current dither buffer
|
||||
void Inkplate::ditherStart(uint8_t *pixelBuffer, uint8_t* bufferPtr, int w, bool invert, uint8_t bits) {
|
||||
void Inkplate::ditherStart(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits)
|
||||
{
|
||||
for (int i = 0; i < w; ++i)
|
||||
if (bits == 24) {
|
||||
if (bits == 24)
|
||||
{
|
||||
if (invert)
|
||||
ditherBuffer[0][i] = ((255 - *(bufferPtr++)) * 2126 / 10000) + ((255 - *(bufferPtr++)) * 7152 / 10000) + ((255 - *(bufferPtr++)) * 722 / 10000);
|
||||
else
|
||||
ditherBuffer[0][i] = (*(bufferPtr++) * 2126 / 10000) + (*(bufferPtr++) * 7152 / 10000) + (*(bufferPtr++) * 722 / 10000);
|
||||
}
|
||||
else if (bits == 8) {
|
||||
else if (bits == 8)
|
||||
{
|
||||
if (invert)
|
||||
ditherBuffer[0][i] = 255 - *(bufferPtr++);
|
||||
else
|
||||
ditherBuffer[0][i] = *(bufferPtr++);
|
||||
}
|
||||
if (bits == 4) {
|
||||
if (bits == 4)
|
||||
{
|
||||
int _w = w / 8;
|
||||
int paddingBits = w % 8;
|
||||
|
||||
for (int i = 0; i < _w; ++i) {
|
||||
for (int n = 0; n < 4; n++) {
|
||||
for (int i = 0; i < _w; ++i)
|
||||
{
|
||||
for (int n = 0; n < 4; n++)
|
||||
{
|
||||
uint8_t temp = *(bufferPtr++);
|
||||
ditherBuffer[0][i * 8 + n * 2] = temp & 0xF0;
|
||||
ditherBuffer[0][i * 8 + n * 2 + 1] = (temp & 0x0F) << 4;
|
||||
|
||||
if (invert) {
|
||||
if (invert)
|
||||
{
|
||||
ditherBuffer[0][i * 8 + n * 2] = ~ditherBuffer[0][i * 8 + n * 2];
|
||||
ditherBuffer[0][i * 8 + n * 2 + 1] = ~ditherBuffer[0][i * 8 + n * 2 + 1];
|
||||
}
|
||||
|
@ -1312,33 +1445,40 @@ void Inkplate::ditherStart(uint8_t *pixelBuffer, uint8_t* bufferPtr, int w, bool
|
|||
}
|
||||
|
||||
//Loads next line, after this ditherGetPixel can be called and alters values in next line
|
||||
void Inkplate::ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t* bufferPtr, int w, bool invert, uint8_t bits) {
|
||||
void Inkplate::ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits)
|
||||
{
|
||||
for (int i = 0; i < w; ++i)
|
||||
{
|
||||
if (bits == 24) {
|
||||
if (bits == 24)
|
||||
{
|
||||
if (invert)
|
||||
ditherBuffer[1][i] = ((255 - *(bufferPtr++)) * 2126 / 10000) + ((255 - *(bufferPtr++)) * 7152 / 10000) + ((255 - *(bufferPtr++)) * 722 / 10000);
|
||||
else
|
||||
ditherBuffer[1][i] = (*(bufferPtr++) * 2126 / 10000) + (*(bufferPtr++) * 7152 / 10000) + (*(bufferPtr++) * 722 / 10000);
|
||||
}
|
||||
else if (bits == 8) {
|
||||
else if (bits == 8)
|
||||
{
|
||||
if (invert)
|
||||
ditherBuffer[1][i] = 255 - *(bufferPtr++);
|
||||
else
|
||||
ditherBuffer[1][i] = *(bufferPtr++);
|
||||
}
|
||||
}
|
||||
if (bits == 4) {
|
||||
if (bits == 4)
|
||||
{
|
||||
int _w = w / 8;
|
||||
int paddingBits = w % 8;
|
||||
|
||||
for (int i = 0; i < _w; ++i) {
|
||||
for (int n = 0; n < 4; n++) {
|
||||
for (int i = 0; i < _w; ++i)
|
||||
{
|
||||
for (int n = 0; n < 4; n++)
|
||||
{
|
||||
uint8_t temp = *(bufferPtr++);
|
||||
ditherBuffer[0][i * 8 + n * 2] = temp & 0xF0;
|
||||
ditherBuffer[0][i * 8 + n * 2 + 1] = (temp & 0x0F) << 4;
|
||||
|
||||
if (invert) {
|
||||
if (invert)
|
||||
{
|
||||
ditherBuffer[0][i * 8 + n * 2] = ~ditherBuffer[0][i * 8 + n * 2];
|
||||
ditherBuffer[0][i * 8 + n * 2 + 1] = ~ditherBuffer[0][i * 8 + n * 2 + 1];
|
||||
}
|
||||
|
@ -1358,7 +1498,8 @@ void Inkplate::ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t* bufferPtr, int
|
|||
}
|
||||
|
||||
//Gets specific pixel, mainly at i, j is just used for bound checking when changing next line values
|
||||
uint8_t Inkplate::ditherGetPixel(int i, int j, int w, int h) {
|
||||
uint8_t Inkplate::ditherGetPixel(int i, int j, int w, int h)
|
||||
{
|
||||
uint8_t oldpixel = ditherBuffer[0][i];
|
||||
uint8_t newpixel = (oldpixel & B11100000);
|
||||
|
||||
|
@ -1379,7 +1520,8 @@ uint8_t Inkplate::ditherGetPixel(int i, int j, int w, int h) {
|
|||
}
|
||||
|
||||
//Swaps current and next line, for next one to be overwritten
|
||||
uint8_t Inkplate::ditherSwap(int w) {
|
||||
uint8_t Inkplate::ditherSwap(int w)
|
||||
{
|
||||
for (int i = 0; i < w; ++i)
|
||||
ditherBuffer[0][i] = ditherBuffer[1][i];
|
||||
}
|
||||
|
@ -1467,9 +1609,10 @@ int Inkplate::drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHead
|
|||
uint8_t *bufferPtr;
|
||||
uint8_t *f_pointer = buf + (bmpHeader.startRAW - 34);
|
||||
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
for (i = 0; i < w * 4 + (paddingBits? 1 : 0); i++)
|
||||
for (i = 0; i < w * 4 + (paddingBits ? 1 : 0); i++)
|
||||
pixelBuffer[i] = *(f_pointer++);
|
||||
|
||||
ditherStart(pixelBuffer, bufferPtr, w, invert, 4);
|
||||
|
@ -1478,23 +1621,26 @@ int Inkplate::drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHead
|
|||
for (j = 0; j < h; j++)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
for (i = 0; i < w * 4 + (paddingBits? 1 : 0); i++)
|
||||
for (i = 0; i < w * 4 + (paddingBits ? 1 : 0); i++)
|
||||
pixelBuffer[i] = *(f_pointer++);
|
||||
|
||||
if (dither && j != h - 1) {
|
||||
ditherLoadNextLine(pixelBuffer, bufferPtr, w * 8 + (paddingBits? 4 : 0), invert, 4);
|
||||
if (dither && j != h - 1)
|
||||
{
|
||||
ditherLoadNextLine(pixelBuffer, bufferPtr, w * 8 + (paddingBits ? 4 : 0), invert, 4);
|
||||
}
|
||||
|
||||
for (i = 0; i < w; i++)
|
||||
{
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
|
||||
for (int n = 0; n < 8; n++)
|
||||
{
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits? 4 : 0), h) >> 5);
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits ? 4 : 0), h) >> 5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++);
|
||||
if (invert)
|
||||
pixelRow = ~pixelRow;
|
||||
|
@ -1506,13 +1652,15 @@ int Inkplate::drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHead
|
|||
}
|
||||
if (paddingBits)
|
||||
{
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
for (int n = 0; n < paddingBits; n++)
|
||||
{
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits? 4 : 0), h) >> 5);
|
||||
drawPixel((i * 8) + n + x, h - 1 - j + y, ditherGetPixel((i * 8) + n, h - 1 - j, w * 8 + (paddingBits ? 4 : 0), h) >> 5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint32_t pixelRow = *(bufferPtr++) << 24 | *(bufferPtr++) << 16 | *(bufferPtr++) << 8 | *(bufferPtr++);
|
||||
if (invert)
|
||||
pixelRow = ~pixelRow;
|
||||
|
@ -1559,7 +1707,8 @@ int Inkplate::drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHead
|
|||
|
||||
int i, j;
|
||||
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
for (i = 0; i < w; i++)
|
||||
pixelBuffer[i] = *(f_pointer++);
|
||||
|
@ -1573,7 +1722,8 @@ int Inkplate::drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHead
|
|||
for (i = 0; i < w; i++)
|
||||
pixelBuffer[i] = *(f_pointer++);
|
||||
|
||||
if (dither && j != h - 1) {
|
||||
if (dither && j != h - 1)
|
||||
{
|
||||
ditherLoadNextLine(buf, bufferPtr, w, invert, 8);
|
||||
}
|
||||
|
||||
|
@ -1581,7 +1731,8 @@ int Inkplate::drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHead
|
|||
{
|
||||
if (dither)
|
||||
drawPixel(i + x, h - 1 - j + y, ditherGetPixel(i, j, w, h) >> 5);
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint8_t px = 0;
|
||||
if (invert)
|
||||
px = 255 - *(bufferPtr++);
|
||||
|
@ -1636,7 +1787,8 @@ int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHea
|
|||
|
||||
int i, j;
|
||||
|
||||
if (dither) {
|
||||
if (dither)
|
||||
{
|
||||
bufferPtr = pixelBuffer;
|
||||
for (i = 0; i < w * 3; i++)
|
||||
pixelBuffer[i] = *(f_pointer++);
|
||||
|
@ -1650,7 +1802,8 @@ int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHea
|
|||
for (i = 0; i < w * 3; i++)
|
||||
pixelBuffer[i] = *(f_pointer++);
|
||||
|
||||
if (dither && j != h - 1) {
|
||||
if (dither && j != h - 1)
|
||||
{
|
||||
ditherLoadNextLine(buf, bufferPtr, w, invert, 24);
|
||||
}
|
||||
|
||||
|
@ -1664,7 +1817,8 @@ int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHea
|
|||
//So then, we are convertng it to grayscale using good old average and gamma correction (from LUT). With this metod, it is still slow (full size image takes 4 seconds), but much beter than prev mentioned method.
|
||||
if (dither)
|
||||
drawPixel(i + x, h - 1 - j + y, ditherGetPixel(i, j, w, h) >> 5);
|
||||
else {
|
||||
else
|
||||
{
|
||||
uint8_t px = 0;
|
||||
if (invert)
|
||||
px = ((255 - *(bufferPtr++)) * 2126 / 10000) + ((255 - *(bufferPtr++)) * 7152 / 10000) + ((255 - *(bufferPtr++)) * 722 / 10000);
|
||||
|
|
27
Inkplate.h
27
Inkplate.h
|
@ -16,6 +16,7 @@
|
|||
#include "Adafruit_MCP23017.h"
|
||||
#include "SdFat.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "Triangulate.h"
|
||||
|
||||
#define INKPLATE_GAMMA 1.45
|
||||
#define E_INK_WIDTH 800
|
||||
|
@ -160,19 +161,19 @@ public:
|
|||
uint8_t *_partial;
|
||||
uint8_t *D_memory4Bit;
|
||||
uint8_t *_pBuffer;
|
||||
const uint8_t LUT2[16] ={ B10101010, B10101001, B10100110, B10100101, B10011010, B10011001, B10010110, B10010101, B01101010, B01101001, B01100110, B01100101, B01011010, B01011001, B01010110, B01010101 };
|
||||
const uint8_t LUTW[16] ={ B11111111, B11111110, B11111011, B11111010, B11101111, B11101110, B11101011, B11101010, B10111111, B10111110, B10111011, B10111010, B10101111, B10101110, B10101011, B10101010 };
|
||||
const uint8_t LUTB[16] ={ B11111111, B11111101, B11110111, B11110101, B11011111, B11011101, B11010111, B11010101, B01111111, B01111101, B01110111, B01110101, B01011111, B01011101, B01010111, B01010101 };
|
||||
const uint8_t pixelMaskLUT[8] ={ B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000 };
|
||||
const uint8_t pixelMaskGLUT[2] ={ B00001111, B11110000 };
|
||||
const uint8_t discharge[16] ={ B11111111, B11111100, B11110011, B11110000, B11001111, B11001100, B11000011, B11000000, B00111111, B00111100, B00110011, B00110000, B00001111, B00001100, B00000011, B00000000 };
|
||||
const uint8_t LUT2[16] = {B10101010, B10101001, B10100110, B10100101, B10011010, B10011001, B10010110, B10010101, B01101010, B01101001, B01100110, B01100101, B01011010, B01011001, B01010110, B01010101};
|
||||
const uint8_t LUTW[16] = {B11111111, B11111110, B11111011, B11111010, B11101111, B11101110, B11101011, B11101010, B10111111, B10111110, B10111011, B10111010, B10101111, B10101110, B10101011, B10101010};
|
||||
const uint8_t LUTB[16] = {B11111111, B11111101, B11110111, B11110101, B11011111, B11011101, B11010111, B11010101, B01111111, B01111101, B01110111, B01110101, B01011111, B01011101, B01010111, B01010101};
|
||||
const uint8_t pixelMaskLUT[8] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
|
||||
const uint8_t pixelMaskGLUT[2] = {B00001111, B11110000};
|
||||
const uint8_t discharge[16] = {B11111111, B11111100, B11110011, B11110000, B11001111, B11001100, B11000011, B11000000, B00111111, B00111100, B00110011, B00110000, B00001111, B00001100, B00000011, B00000000};
|
||||
//BLACK->WHITE
|
||||
//THIS IS OKAYISH WAVEFORM FOR GRAYSCALE. IT CAN BE MUCH BETTER.
|
||||
const uint8_t waveform3Bit[8][7] ={ { 0, 0, 0, 0, 1, 1, 1 }, { 0, 0, 1, 1, 1, 2, 1 }, { 0, 1, 1, 2, 1, 2, 1 }, { 0, 0, 1, 1, 2, 1, 2 }, { 1, 1, 1, 2, 2, 1, 2 }, { 0, 0, 1, 1, 1, 2, 2 }, { 0, 1, 1, 2, 1, 2, 2 }, { 0, 0, 0, 0, 0, 0, 2 } };
|
||||
const uint8_t waveform3Bit[8][7] = {{0, 0, 0, 0, 1, 1, 1}, {0, 0, 1, 1, 1, 2, 1}, {0, 1, 1, 2, 1, 2, 1}, {0, 0, 1, 1, 2, 1, 2}, {1, 1, 1, 2, 2, 1, 2}, {0, 0, 1, 1, 1, 2, 2}, {0, 1, 1, 2, 1, 2, 2}, {0, 0, 0, 0, 0, 0, 2}};
|
||||
//const uint8_t waveform3Bit[8][12] = {{3,3,3,1,1,1,1,1,1,1,2,0}, {3,3,3,3,1,1,1,1,1,1,2,0}, {3,3,3,3,3,1,1,1,1,1,2,0}, {3,3,3,3,3,3,1,1,1,1,2,0}, {3,3,3,3,3,3,3,1,1,1,2,0}, {3,3,3,3,3,3,3,2,1,1,2,0}, {3,3,3,3,3,3,3,3,3,1,2,0}, {3,3,3,3,3,3,3,3,3,3,2,0}};
|
||||
//const uint8_t waveform3Bit[16][12] = {{0,0,0,0,0,0,1,2,1,1,0,3},{0,0,1,1,1,2,2,2,1,1,0,3},{0,0,0,1,1,2,2,2,1,1,0,3}, {0,0,0,1,2,1,2,1,2,1,3}, {0,0,2,1,2,1,2,1,2,1,3}, {0,0,1,2,2,1,1,1,1,2,0,3}, {0,0,0,2,1,1,1,1,0,2,0,3}, {0,0,2,1,2,2,1,1,1,2,0,3}, {0,0,0,2,2,2,1,1,1,2,0,3}, {0,0,0,0,0,0,2,1,1,2,0,3}, {0,0,0,0,0,2,2,1,1,2,0,3}, {0,0,0,0,0,1,1,1,2,2,0,3}, {0,0,0,0,1,2,1,2,1,2,0,3}, {0,0,0,0,1,1,2,2,1,2,0,3},{0,0,0,0,1,1,1,2,2,2,0,3}, {0,0,0,0,0,0,0,0,0,2,0,3}};
|
||||
//PVI waveform for cleaning screen, not sure if it is correct, but it cleans screen properly.
|
||||
const uint32_t waveform[50] ={ 0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60a81898, 0x60a8a8a8, 0x60a8a8a8, 0x6068a868, 0x6868a868, 0x6868a868, 0x68686868, 0x6a686868, 0x5a686868, 0x5a686868, 0x5a586a68, 0x5a5a6a68, 0x5a5a6a68, 0x55566a68, 0x55565a64, 0x55555654, 0x55555556, 0x55555556, 0x55555556, 0x55555516, 0x55555596, 0x15555595, 0x95955595, 0x95959595, 0x95949495, 0x94949495, 0x94949495, 0xa4949494, 0x9494a4a4, 0x84a49494, 0x84948484, 0x84848484, 0x84848484, 0x84848484, 0xa5a48484, 0xa9a4a4a8, 0xa9a8a8a8, 0xa5a9a9a4, 0xa5a5a5a4, 0xa1a5a5a1, 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0x15151515, 0x11111111 };
|
||||
const uint32_t waveform[50] = {0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60a81898, 0x60a8a8a8, 0x60a8a8a8, 0x6068a868, 0x6868a868, 0x6868a868, 0x68686868, 0x6a686868, 0x5a686868, 0x5a686868, 0x5a586a68, 0x5a5a6a68, 0x5a5a6a68, 0x55566a68, 0x55565a64, 0x55555654, 0x55555556, 0x55555556, 0x55555556, 0x55555516, 0x55555596, 0x15555595, 0x95955595, 0x95959595, 0x95949495, 0x94949495, 0x94949495, 0xa4949494, 0x9494a4a4, 0x84a49494, 0x84948484, 0x84848484, 0x84848484, 0x84848484, 0xa5a48484, 0xa9a4a4a8, 0xa9a8a8a8, 0xa5a9a9a4, 0xa5a5a5a4, 0xa1a5a5a1, 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0x15151515, 0x11111111};
|
||||
|
||||
struct bitmapHeader
|
||||
{
|
||||
|
@ -203,6 +204,10 @@ public:
|
|||
int drawBitmapFromSD(char *fileName, int x, int y, bool dither = false, bool invert = false);
|
||||
int drawBitmapFromWeb(WiFiClient *s, int x, int y, int len, bool dither = false, bool invert = false);
|
||||
int drawBitmapFromWeb(char *url, int x, int y, bool dither = false, bool invert = false);
|
||||
void drawElipse(int rx, int ry, int xc, int yc, int c);
|
||||
void fillElipse(int rx, int ry, int xc, int yc, int c);
|
||||
void drawPolygon(int *x, int *y, int n, int color);
|
||||
void fillPolygon(int *x, int *y, int n, int color);
|
||||
void drawThickLine(int x1, int y1, int x2, int y2, int color, float thickness);
|
||||
void drawGradientLine(int x1, int y1, int x2, int y2, int color1, int color2, float thickness = -1);
|
||||
int sdCardInit();
|
||||
|
@ -234,12 +239,14 @@ private:
|
|||
uint8_t _blockPartial = 1;
|
||||
uint8_t _beginDone = 0;
|
||||
|
||||
Triangulate triangulate;
|
||||
|
||||
void display1b();
|
||||
void display3b();
|
||||
uint32_t read32(uint8_t *c);
|
||||
uint16_t read16(uint8_t *c);
|
||||
void ditherStart(uint8_t *pixelBuffer, uint8_t* bufferPtr, int w, bool invert, uint8_t bits);
|
||||
void ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t* bufferPtr, int w, bool invert, uint8_t bits);
|
||||
void ditherStart(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits);
|
||||
void ditherLoadNextLine(uint8_t *pixelBuffer, uint8_t *bufferPtr, int w, bool invert, uint8_t bits);
|
||||
uint8_t ditherGetPixel(int i, int j, int w, int h);
|
||||
uint8_t ditherSwap(int w);
|
||||
void readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h);
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
#include "Arduino.h"
|
||||
#include "math.h"
|
||||
#include "Triangulate.h"
|
||||
|
||||
float Triangulate::area(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
return fabs((float)((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))) / 2.0);
|
||||
}
|
||||
|
||||
bool Triangulate::isInside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y)
|
||||
{
|
||||
float A = area(x1, y1, x2, y2, x3, y3);
|
||||
float A1 = area(x, y, x2, y2, x3, y3);
|
||||
float A2 = area(x1, y1, x, y, x3, y3);
|
||||
float A3 = area(x1, y1, x2, y2, x, y);
|
||||
return fabs(-A + A1 + A2 + A3) < 1e-3;
|
||||
}
|
||||
|
||||
void Triangulate::preProcess(int *x, int *y, int n)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
int prev = (i - 1 + n) % n;
|
||||
int next = (i + 1 + n) % n;
|
||||
float deg = atan2(y[prev] - y[i], x[prev] - x[i]) - atan2(y[next] - y[i], x[next] - x[i]);
|
||||
if (deg < 0.0)
|
||||
deg += 2 * M_PI;
|
||||
innerAngle[i] = deg;
|
||||
}
|
||||
}
|
||||
|
||||
void Triangulate::updateVertex(int p, int *x, int *y, int n)
|
||||
{
|
||||
int prev = (p - 1 + n) % n;
|
||||
int next = (p + 1 + n) % n;
|
||||
float deg = atan2(y[prev] - y[p], x[prev] - x[p]) - atan2(y[next] - y[p], x[next] - x[p]);
|
||||
if (deg < 0.0)
|
||||
deg += 2 * M_PI;
|
||||
innerAngle[p] = deg;
|
||||
bool f = 0;
|
||||
for (int j = 0; j < n; ++j)
|
||||
{
|
||||
if (prev != j && p != j && next != j &&
|
||||
innerAngle[p] > M_PI &&
|
||||
isInside(x[prev], y[prev], x[p], y[p], x[next], y[next], x[j], y[j]))
|
||||
f = 1;
|
||||
}
|
||||
earTip[p] = !f;
|
||||
}
|
||||
|
||||
bool Triangulate::isConvex(int *x, int *y, int n)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (innerAngle[i] > M_PI)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Triangulate::trivialTriangles(int *x, int *y, int n)
|
||||
{
|
||||
for (int i = 0; i < n - 2; ++i)
|
||||
{
|
||||
tx[tc] = x[0];
|
||||
ty[tc] = y[0];
|
||||
++tc;
|
||||
tx[tc] = x[i + 1];
|
||||
ty[tc] = y[i + 1];
|
||||
++tc;
|
||||
tx[tc] = x[i + 2];
|
||||
ty[tc] = y[i + 2];
|
||||
++tc;
|
||||
}
|
||||
}
|
||||
|
||||
void Triangulate::findEars(int *x, int *y, int n)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (innerAngle[i] > M_PI)
|
||||
continue;
|
||||
int prev = (i - 1 + n) % n;
|
||||
int next = (i + 1 + n) % n;
|
||||
bool f = 0;
|
||||
for (int j = 0; j < n; ++j)
|
||||
{
|
||||
if (prev != j && i != j && next != j &&
|
||||
innerAngle[i] > M_PI &&
|
||||
isInside(x[prev], y[prev], x[i], y[i], x[next], y[next], x[j], y[j]))
|
||||
f = 1;
|
||||
}
|
||||
earTip[i] = !f;
|
||||
}
|
||||
}
|
||||
|
||||
int Triangulate::smallestEar(int *x, int *y, int n)
|
||||
{
|
||||
int mn = 0;
|
||||
for (int i = 1; i < n; ++i)
|
||||
if (earTip[i] && innerAngle[i] < innerAngle[mn])
|
||||
mn = i;
|
||||
return mn;
|
||||
}
|
||||
|
||||
void Triangulate::nonTrivialTriangles(int *x, int *y, int n)
|
||||
{
|
||||
findEars(x, y, n);
|
||||
int initialN = n;
|
||||
while (tc / 3 < initialN - 2)
|
||||
{
|
||||
int pos = smallestEar(x, y, n);
|
||||
int prev = (pos - 1 + n) % n;
|
||||
int next = (pos + 1 + n) % n;
|
||||
tx[tc] = x[prev];
|
||||
ty[tc] = y[prev];
|
||||
++tc;
|
||||
tx[tc] = x[pos];
|
||||
ty[tc] = y[pos];
|
||||
++tc;
|
||||
tx[tc] = x[next];
|
||||
ty[tc] = y[next];
|
||||
++tc;
|
||||
for (int i = pos; i < n - 1; i++)
|
||||
{
|
||||
x[i] = x[i + 1];
|
||||
y[i] = y[i + 1];
|
||||
innerAngle[i] = innerAngle[i + 1];
|
||||
earTip[i] = earTip[i + 1];
|
||||
}
|
||||
--n;
|
||||
updateVertex(prev, x, y, n);
|
||||
updateVertex(prev + 1, x, y, n);
|
||||
}
|
||||
}
|
||||
|
||||
void Triangulate::triangulate(int *x, int *y, int n, int *_tx, int *_ty)
|
||||
{
|
||||
tc = 0;
|
||||
preProcess(x, y, n);
|
||||
if (isConvex(x, y, n))
|
||||
trivialTriangles(x, y, n);
|
||||
else
|
||||
nonTrivialTriangles(x, y, n);
|
||||
memcpy(_tx, tx, 100);
|
||||
memcpy(_ty, ty, 100);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef TRIANGULATE_H
|
||||
#define TRIANGULATE_H
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
class Triangulate
|
||||
{
|
||||
private:
|
||||
int tx[100];
|
||||
int ty[100];
|
||||
int tc = 0;
|
||||
|
||||
float innerAngle[100];
|
||||
bool earTip[100];
|
||||
|
||||
float area(int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
bool isInside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y);
|
||||
void preProcess(int *x, int *y, int n);
|
||||
void updateVertex(int p, int *x, int *y, int n);
|
||||
bool isConvex(int *x, int *y, int n);
|
||||
void trivialTriangles(int *x, int *y, int n);
|
||||
void findEars(int *x, int *y, int n);
|
||||
int smallestEar(int *x, int *y, int n);
|
||||
void nonTrivialTriangles(int *x, int *y, int n);
|
||||
|
||||
public:
|
||||
void triangulate(int *x, int *y, int n, int *_tx, int *_ty);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -361,6 +361,59 @@ void loop()
|
|||
display.display();
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Draws an elipse with x radius, y radius, center x, center y and color
|
||||
display.clearDisplay();
|
||||
display.drawElipse(100, 200, 400, 300, BLACK);
|
||||
displayCurrentAction("Drawing an elipse");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Fills an elipse with x radius, y radius, center x, center y and color
|
||||
display.clearDisplay();
|
||||
display.fillElipse(100, 200, 400, 300, BLACK);
|
||||
displayCurrentAction("Drawing a filled elipse");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Code block for generating random points and sorting them in a counter
|
||||
// clockwise direction.
|
||||
int xt[10];
|
||||
int yt[10];
|
||||
int n = 10;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
xt[i] = random(100, 700);
|
||||
yt[i] = random(100, 500);
|
||||
}
|
||||
int k;
|
||||
for (int i = 0; i < n - 1; ++i)
|
||||
for (int j = i + 1; j < n; ++j)
|
||||
if (atan2(yt[j] - 300, xt[j] - 400) < atan2(yt[i] - 300, xt[i] - 400))
|
||||
{
|
||||
k = xt[i], xt[i] = xt[j], xt[j] = k;
|
||||
k = yt[i], yt[i] = yt[j], yt[j] = k;
|
||||
}
|
||||
|
||||
// Draws a polygon, from x and y coordinate arrays of n points in color c
|
||||
display.clearDisplay();
|
||||
display.drawPolygon(xt, yt, n, BLACK);
|
||||
displayCurrentAction("Drawing a polygon");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Fills a polygon, from x and y coordinate arrays of n points in color c,
|
||||
// Points need to be counter clockwise sorted
|
||||
// Method can be quite slow for now, probably will improve
|
||||
display.clearDisplay();
|
||||
display.fillPolygon(xt, yt, n, BLACK);
|
||||
displayCurrentAction("Drawing a filled polygon");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
//Write text and rotate it by 90 deg. forever
|
||||
int r = 0;
|
||||
display.setTextSize(8);
|
||||
|
|
|
@ -275,6 +275,59 @@ void loop()
|
|||
display.display();
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Draws an elipse with x radius, y radius, center x, center y and color
|
||||
display.clearDisplay();
|
||||
display.drawElipse(100, 200, 400, 300, 0);
|
||||
displayCurrentAction("Drawing an elipse");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Fills an elipse with x radius, y radius, center x, center y and color
|
||||
display.clearDisplay();
|
||||
display.fillElipse(100, 200, 400, 300, 0);
|
||||
displayCurrentAction("Drawing a filled elipse");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Code block for generating random points and sorting them in a counter
|
||||
// clockwise direction.
|
||||
int xt[10];
|
||||
int yt[10];
|
||||
int n = 10;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
xt[i] = random(100, 700);
|
||||
yt[i] = random(100, 500);
|
||||
}
|
||||
int k;
|
||||
for (int i = 0; i < n - 1; ++i)
|
||||
for (int j = i + 1; j < n; ++j)
|
||||
if (atan2(yt[j] - 300, xt[j] - 400) < atan2(yt[i] - 300, xt[i] - 400))
|
||||
{
|
||||
k = xt[i], xt[i] = xt[j], xt[j] = k;
|
||||
k = yt[i], yt[i] = yt[j], yt[j] = k;
|
||||
}
|
||||
|
||||
// Draws a polygon, from x and y coordinate arrays of n points in color c
|
||||
display.clearDisplay();
|
||||
display.drawPolygon(xt, yt, n, 0);
|
||||
displayCurrentAction("Drawing a polygon");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
// Fills a polygon, from x and y coordinate arrays of n points in color c,
|
||||
// Points need to be counter clockwise sorted
|
||||
// Method can be quite slow for now, probably will improve
|
||||
display.clearDisplay();
|
||||
display.fillPolygon(xt, yt, n, 0);
|
||||
displayCurrentAction("Drawing a filled polygon");
|
||||
display.display();
|
||||
|
||||
delay(DELAY_MS);
|
||||
|
||||
//Write text and rotate it by 90 deg. forever
|
||||
int r = 0;
|
||||
display.setTextSize(8);
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -8,7 +8,8 @@
|
|||
#define _GFXFONT_H_
|
||||
|
||||
/// Font data stored PER GLYPH
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
|
||||
uint8_t width; ///< Bitmap dimensions in pixels
|
||||
uint8_t height; ///< Bitmap dimensions in pixels
|
||||
|
@ -18,7 +19,8 @@ typedef struct {
|
|||
} GFXglyph;
|
||||
|
||||
/// Data stored for FONT AS A WHOLE
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
|
||||
GFXglyph *glyph; ///< Glyph array
|
||||
uint8_t first; ///< ASCII extents (first char)
|
||||
|
|
Loading…
Reference in New Issue