1104 lines
25 KiB
C++
1104 lines
25 KiB
C++
/*
|
|
* start rewrite from:
|
|
* https://github.com/adafruit/Adafruit-GFX-Library.git
|
|
*/
|
|
#include "Arduino_DataBus.h"
|
|
#include "Arduino_GFX.h"
|
|
#include "Arduino_TFT.h"
|
|
#include "font/glcdfont.h"
|
|
|
|
Arduino_TFT::Arduino_TFT(
|
|
Arduino_DataBus *bus, int8_t rst, uint8_t r,
|
|
bool ips, int16_t w, int16_t h,
|
|
uint8_t col_offset1, uint8_t row_offset1, uint8_t col_offset2, uint8_t row_offset2)
|
|
: Arduino_GFX(w, h), _bus(bus), _rst(rst), _ips(ips),
|
|
COL_OFFSET1(col_offset1), ROW_OFFSET1(row_offset1),
|
|
COL_OFFSET2(col_offset2), ROW_OFFSET2(row_offset2)
|
|
{
|
|
_rotation = r;
|
|
}
|
|
|
|
bool Arduino_TFT::begin(int32_t speed)
|
|
{
|
|
if (_override_datamode != GFX_NOT_DEFINED)
|
|
{
|
|
if (!_bus->begin(speed, _override_datamode))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!_bus->begin(speed))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
tftInit();
|
|
setRotation(_rotation); // apply the setting rotation to the display
|
|
setAddrWindow(0, 0, _width, _height);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Arduino_TFT::startWrite()
|
|
{
|
|
_bus->beginWrite();
|
|
}
|
|
|
|
void Arduino_TFT::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
|
|
{
|
|
writeAddrWindow(x, y, 1, 1);
|
|
_bus->write16(color);
|
|
}
|
|
|
|
void Arduino_TFT::writeRepeat(uint16_t color, uint32_t len)
|
|
{
|
|
_bus->writeRepeat(color, len);
|
|
}
|
|
|
|
void Arduino_TFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
|
{
|
|
if (_ordered_in_range(x, 0, _max_x) && h)
|
|
{ // X on screen, nonzero height
|
|
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 y2 = y + h - 1;
|
|
if (y2 >= 0)
|
|
{ // Not off top
|
|
// Line partly or fully overlaps screen
|
|
if (y < 0)
|
|
{
|
|
y = 0;
|
|
h = y2 + 1;
|
|
} // Clip top
|
|
if (y2 > _max_y)
|
|
{
|
|
h = _max_y - y + 1;
|
|
} // Clip bottom
|
|
writeFillRectPreclipped(x, y, 1, h, color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
|
|
{
|
|
if (_ordered_in_range(y, 0, _max_y) && w)
|
|
{ // Y on screen, nonzero width
|
|
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
|
|
int16_t x2 = x + w - 1;
|
|
if (x2 >= 0)
|
|
{ // Not off left
|
|
// Line partly or fully overlaps screen
|
|
if (x < 0)
|
|
{
|
|
x = 0;
|
|
w = x2 + 1;
|
|
} // Clip left
|
|
if (x2 > _max_x)
|
|
{
|
|
w = _max_x - x + 1;
|
|
} // Clip right
|
|
writeFillRectPreclipped(x, y, w, 1, color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::writeFillRectPreclipped(
|
|
int16_t x, int16_t y,
|
|
int16_t w, int16_t h, uint16_t color)
|
|
{
|
|
#ifdef ESP8266
|
|
yield();
|
|
#endif
|
|
writeAddrWindow(x, y, w, h);
|
|
writeRepeat(color, (uint32_t)w * h);
|
|
}
|
|
|
|
void Arduino_TFT::endWrite()
|
|
{
|
|
_bus->endWrite();
|
|
}
|
|
|
|
void Arduino_TFT::setAddrWindow(int16_t x0, int16_t y0, uint16_t w,
|
|
uint16_t h)
|
|
{
|
|
startWrite();
|
|
|
|
writeAddrWindow(x0, y0, w, h);
|
|
|
|
endWrite();
|
|
}
|
|
|
|
void Arduino_TFT::setRotation(uint8_t r)
|
|
{
|
|
Arduino_GFX::setRotation(r);
|
|
switch (_rotation)
|
|
{
|
|
case 5:
|
|
case 3:
|
|
_xStart = ROW_OFFSET2;
|
|
_yStart = COL_OFFSET1;
|
|
break;
|
|
case 6:
|
|
case 2:
|
|
_xStart = COL_OFFSET2;
|
|
_yStart = ROW_OFFSET2;
|
|
break;
|
|
case 7:
|
|
case 1:
|
|
_xStart = ROW_OFFSET1;
|
|
_yStart = COL_OFFSET2;
|
|
break;
|
|
case 4:
|
|
default: // case 0:
|
|
_xStart = COL_OFFSET1;
|
|
_yStart = ROW_OFFSET1;
|
|
break;
|
|
}
|
|
_currentX = 0xFFFF;
|
|
_currentY = 0xFFFF;
|
|
_currentW = 0xFFFF;
|
|
_currentH = 0xFFFF;
|
|
}
|
|
|
|
void Arduino_TFT::writeColor(uint16_t color)
|
|
{
|
|
_bus->write16(color);
|
|
}
|
|
|
|
// TFT optimization code, too big for ATMEL family
|
|
#if !defined(LITTLE_FOOT_PRINT)
|
|
|
|
void Arduino_TFT::writeBytes(uint8_t *data, uint32_t len)
|
|
{
|
|
_bus->writeBytes(data, len);
|
|
}
|
|
|
|
void Arduino_TFT::writePixels(uint16_t *data, uint32_t len)
|
|
{
|
|
_bus->writePixels(data, len);
|
|
}
|
|
|
|
void Arduino_TFT::pushColor(uint16_t color)
|
|
{
|
|
_bus->beginWrite();
|
|
writeColor(color);
|
|
_bus->endWrite();
|
|
}
|
|
|
|
void Arduino_TFT::writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
|
|
{
|
|
int16_t dx;
|
|
int16_t dy;
|
|
int16_t err;
|
|
int16_t xs;
|
|
int16_t step;
|
|
int16_t len;
|
|
|
|
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);
|
|
}
|
|
|
|
dx = x1 - x0;
|
|
dy = _diff(y1, y0);
|
|
err = dx >> 1;
|
|
xs = x0;
|
|
step = (y0 < y1) ? 1 : -1;
|
|
len = 0;
|
|
|
|
while (x0 <= x1)
|
|
{
|
|
x0++;
|
|
len++;
|
|
err -= dy;
|
|
if ((err < 0) || ((x0 > x1) && len))
|
|
{
|
|
if (steep)
|
|
{
|
|
writeFillRectPreclipped(y0, xs, 1, len, color);
|
|
}
|
|
else
|
|
{
|
|
writeFillRectPreclipped(xs, y0, len, 1, color);
|
|
}
|
|
err += dx;
|
|
y0 += step;
|
|
len = 0;
|
|
xs = x0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TFT tuned BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
|
|
|
|
void Arduino_TFT::writeIndexedPixels(uint8_t *bitmap, uint16_t *color_index, uint32_t len)
|
|
{
|
|
_bus->writeIndexedPixels(bitmap, color_index, len);
|
|
}
|
|
|
|
void Arduino_TFT::writeIndexedPixelsDouble(uint8_t *bitmap, uint16_t *color_index, uint32_t len)
|
|
{
|
|
_bus->writeIndexedPixelsDouble(bitmap, color_index, len);
|
|
}
|
|
|
|
void Arduino_TFT::drawYCbCrBitmap(int16_t x, int16_t y, uint8_t *yData, uint8_t *cbData, uint8_t *crData, int16_t w, int16_t h)
|
|
{
|
|
startWrite();
|
|
writeAddrWindow(0, 0, w, h);
|
|
_bus->writeYCbCrPixels(yData, cbData, crData, w, h);
|
|
endWrite();
|
|
}
|
|
|
|
void Arduino_TFT::drawBitmap(
|
|
int16_t x, int16_t y,
|
|
const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint16_t bg)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::drawBitmap(x, y, bitmap, w, h, color, bg);
|
|
}
|
|
else
|
|
{
|
|
int32_t pixels = w * h;
|
|
uint8_t byte = 0;
|
|
uint16_t idx = 0;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
for (int32_t i = 0; i < pixels; i++)
|
|
{
|
|
if (i & 7)
|
|
{
|
|
byte <<= 1;
|
|
}
|
|
else
|
|
{
|
|
byte = pgm_read_byte(&bitmap[idx++]);
|
|
}
|
|
_bus->write16((byte & 0x80) ? color : bg);
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::drawBitmap(
|
|
int16_t x, int16_t y,
|
|
uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::drawBitmap(x, y, bitmap, w, h, color, bg);
|
|
}
|
|
else
|
|
{
|
|
int32_t pixels = w * h;
|
|
uint8_t byte = 0;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
for (int32_t i = 0; i < pixels; i++)
|
|
{
|
|
if (i & 7)
|
|
{
|
|
byte <<= 1;
|
|
}
|
|
else
|
|
{
|
|
byte = *(bitmap++);
|
|
}
|
|
_bus->write16((byte & 0x80) ? color : bg);
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::drawGrayscaleBitmap(
|
|
int16_t x, int16_t y,
|
|
const uint8_t bitmap[], int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::drawGrayscaleBitmap(x, y, bitmap, w, h);
|
|
}
|
|
else
|
|
{
|
|
uint32_t len = (uint32_t)w * h;
|
|
uint8_t v;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
for (uint32_t i = 0; i < len; i++)
|
|
{
|
|
v = pgm_read_byte(&bitmap[i]);
|
|
_bus->write16(color565(v, v, v));
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::drawGrayscaleBitmap(
|
|
int16_t x, int16_t y,
|
|
uint8_t *bitmap, int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::drawGrayscaleBitmap(x, y, bitmap, w, h);
|
|
}
|
|
else
|
|
{
|
|
uint32_t len = (uint32_t)w * h;
|
|
uint8_t v;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
while (len--)
|
|
{
|
|
v = *(bitmap++);
|
|
_bus->write16(color565(v, v, v));
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::drawIndexedBitmap(
|
|
int16_t x, int16_t y,
|
|
uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, w, h, x_skip);
|
|
}
|
|
else
|
|
{
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
if (x_skip == 0)
|
|
{
|
|
_bus->writeIndexedPixels(bitmap, color_index, h * w);
|
|
}
|
|
else
|
|
{
|
|
while (h--)
|
|
{
|
|
_bus->writeIndexedPixels(bitmap, color_index, w);
|
|
bitmap += w + x_skip;
|
|
}
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw16bitRGBBitmapWithMask(int16_t x, int16_t y,
|
|
uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::draw16bitRGBBitmapWithMask(x, y, bitmap, mask, w, h);
|
|
}
|
|
else
|
|
{
|
|
int32_t offset = 0, maskIdx = 0, len = 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)
|
|
{
|
|
len++;
|
|
}
|
|
else
|
|
{
|
|
if (len)
|
|
{
|
|
writeAddrWindow(x + i - len, y, len, 1);
|
|
_bus->writePixels(&bitmap[offset - len], len);
|
|
len = 0;
|
|
}
|
|
}
|
|
offset++;
|
|
}
|
|
if (len)
|
|
{
|
|
writeAddrWindow(x + w - 1 - len, y, len, 1);
|
|
_bus->writePixels(&bitmap[offset - len], len);
|
|
len = 0;
|
|
}
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw16bitRGBBitmap(
|
|
int16_t x, int16_t y,
|
|
const uint16_t bitmap[], int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::draw16bitRGBBitmap(x, y, bitmap, w, h);
|
|
}
|
|
else
|
|
{
|
|
uint32_t len = (uint32_t)w * h;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
for (uint32_t i = 0; i < len; i++)
|
|
{
|
|
_bus->write16(pgm_read_word(&bitmap[i]));
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw16bitRGBBitmap(
|
|
int16_t x, int16_t y,
|
|
uint16_t *bitmap, int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((y + h - 1) < 0) || // Outside top
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (_isRoundMode)
|
|
{
|
|
if (
|
|
(x > _roundMaxX[y + h - 1]) && // top left
|
|
((x + w - 1) < _roundMinX[y]) && // top right
|
|
(x > _roundMaxX[y + h - 1]) && // bottom left
|
|
((x + w - 1) < _roundMinX[y + h - 1]) // bottom right
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
(x > _max_x) // Outside right
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int16_t out_width = w;
|
|
if ((y + h - 1) > _max_y)
|
|
{
|
|
h -= (y + h - 1) - _max_y;
|
|
}
|
|
if (y < 0)
|
|
{
|
|
bitmap -= y * w;
|
|
h += y;
|
|
y = 0;
|
|
}
|
|
if ((x + w - 1) > _max_x)
|
|
{
|
|
out_width -= (x + w - 1) - _max_x;
|
|
}
|
|
if (x < 0)
|
|
{
|
|
bitmap -= x;
|
|
out_width += x;
|
|
x = 0;
|
|
}
|
|
|
|
startWrite();
|
|
writeAddrWindow(x, y, out_width, h);
|
|
if (out_width < w)
|
|
{
|
|
for (int16_t j = 0; j < h; j++)
|
|
{
|
|
_bus->writePixels(bitmap, out_width);
|
|
bitmap += w;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_bus->writePixels(bitmap, (uint32_t)w * h);
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw16bitBeRGBBitmap(
|
|
int16_t x, int16_t y,
|
|
uint16_t *bitmap, int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int16_t out_width = w;
|
|
if ((y + h - 1) > _max_y)
|
|
{
|
|
h -= (y + h - 1) - _max_y;
|
|
}
|
|
if (y < 0)
|
|
{
|
|
bitmap -= y * w;
|
|
h += y;
|
|
y = 0;
|
|
}
|
|
if ((x + w - 1) > _max_x)
|
|
{
|
|
out_width -= (x + w - 1) - _max_x;
|
|
}
|
|
if (x < 0)
|
|
{
|
|
bitmap -= x;
|
|
out_width += x;
|
|
x = 0;
|
|
}
|
|
|
|
startWrite();
|
|
writeAddrWindow(x, y, out_width, h);
|
|
if (out_width < w)
|
|
{
|
|
out_width <<= 1;
|
|
for (int16_t j = 0; j < h; j++)
|
|
{
|
|
_bus->writeBytes((uint8_t *)bitmap, out_width);
|
|
bitmap += w;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_bus->writeBytes((uint8_t *)bitmap, (uint32_t)w * h * 2);
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw16bitBeRGBBitmapR1(
|
|
int16_t x, int16_t y,
|
|
uint16_t *bitmap, int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + h - 1) < 0) || // Outside left
|
|
((y + w - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + h - 1) > _max_x) || // Clip right
|
|
((y + w - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::draw16bitBeRGBBitmapR1(x, y, bitmap, w, h);
|
|
}
|
|
else
|
|
{
|
|
startWrite();
|
|
writeAddrWindow(x, y, h, w);
|
|
_bus->write16bitBeRGBBitmapR1(bitmap, w, h);
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw24bitRGBBitmap(
|
|
int16_t x, int16_t y,
|
|
const uint8_t bitmap[], int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::draw24bitRGBBitmap(x, y, bitmap, w, h);
|
|
}
|
|
else
|
|
{
|
|
uint32_t len = (uint32_t)w * h;
|
|
uint32_t offset = 0;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
while (len--)
|
|
{
|
|
_bus->write16(color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2])));
|
|
offset += 3;
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::draw24bitRGBBitmap(
|
|
int16_t x, int16_t y,
|
|
uint8_t *bitmap, int16_t w, int16_t h)
|
|
{
|
|
if (
|
|
((x + w - 1) < 0) || // Outside left
|
|
((y + h - 1) < 0) || // Outside top
|
|
(x > _max_x) || // Outside right
|
|
(y > _max_y) // Outside bottom
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
else if (
|
|
(x < 0) || // Clip left
|
|
(y < 0) || // Clip top
|
|
((x + w - 1) > _max_x) || // Clip right
|
|
((y + h - 1) > _max_y) // Clip bottom
|
|
)
|
|
{
|
|
Arduino_GFX::draw24bitRGBBitmap(x, y, bitmap, w, h);
|
|
}
|
|
else
|
|
{
|
|
uint32_t len = (uint32_t)w * h;
|
|
uint32_t offset = 0;
|
|
startWrite();
|
|
writeAddrWindow(x, y, w, h);
|
|
while (len--)
|
|
{
|
|
_bus->write16(color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2]));
|
|
offset += 3;
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
|
|
void Arduino_TFT::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg)
|
|
{
|
|
uint16_t block_w;
|
|
uint16_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!
|
|
uint8_t first = pgm_read_byte(&gfxFont->first);
|
|
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
|
|
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_sbyte(&glyph->xOffset),
|
|
yo = pgm_read_sbyte(&glyph->yOffset);
|
|
// urgly workaround for the character not fit in the box
|
|
if ((bg != color) // have background color
|
|
&& ((xo + w) > xAdvance)) // if character draw outside the box
|
|
{
|
|
xo = xAdvance - w; // pad inside the box
|
|
}
|
|
|
|
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;
|
|
int16_t x1 = (xo < 0) ? (x + xo) : x;
|
|
if (
|
|
(x1 < _min_text_x) || // Clip left
|
|
((y - baseline) < _min_text_y) || // Clip top
|
|
((x1 + block_w - 1) > _max_text_x) || // Clip right
|
|
((y - baseline + block_h - 1) > _max_text_y) // Clip bottom
|
|
)
|
|
{
|
|
// partial draw char by parent class
|
|
Arduino_GFX::drawChar(x, y, c, color, bg);
|
|
}
|
|
else
|
|
{
|
|
// 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.
|
|
if (xo < 0) // padding X offset to >= 0
|
|
{
|
|
x += xo;
|
|
xo = 0;
|
|
}
|
|
|
|
startWrite();
|
|
if (bg != color) // have background color
|
|
{
|
|
writeAddrWindow(x, y - (baseline * textsize_y), block_w, block_h);
|
|
|
|
uint16_t line_buf[block_w];
|
|
int8_t i;
|
|
bool draw_dot;
|
|
for (yy = 0; yy < yAdvance; yy++)
|
|
{
|
|
if ((yy < (baseline + yo)) || (yy > (baseline + yo + h - 1)))
|
|
{
|
|
writeRepeat(bg, block_w * textsize_y);
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
for (xx = 0; xx < xAdvance; xx++)
|
|
{
|
|
if ((xx < xo) || (xx > (xo + w - 1)))
|
|
{
|
|
draw_dot = false;
|
|
}
|
|
else
|
|
{
|
|
if (!(bit++ & 7))
|
|
{
|
|
bits = pgm_read_byte(&bitmap[bo++]);
|
|
}
|
|
draw_dot = bits & 0x80;
|
|
bits <<= 1;
|
|
}
|
|
|
|
if (textsize_x == 1)
|
|
{
|
|
line_buf[i++] = draw_dot ? color : bg;
|
|
}
|
|
else
|
|
{
|
|
if (draw_dot)
|
|
{
|
|
for (int8_t k = 0; k < textsize_x; k++)
|
|
{
|
|
line_buf[i++] = (k < (textsize_x - text_pixel_margin)) ? color : bg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int8_t k = 0; k < textsize_x; k++)
|
|
{
|
|
line_buf[i++] = bg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (textsize_y == 1)
|
|
{
|
|
writePixels(line_buf, block_w);
|
|
}
|
|
else
|
|
{
|
|
for (int8_t l = 0; l < textsize_y; l++)
|
|
{
|
|
if (l < (textsize_y - text_pixel_margin))
|
|
{
|
|
writePixels(line_buf, block_w);
|
|
}
|
|
else
|
|
{
|
|
writeRepeat(bg, block_w);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // (bg == color), no background color
|
|
{
|
|
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)
|
|
{
|
|
writePixelPreclipped(x + xo + xx, y + yo + yy, color);
|
|
}
|
|
else
|
|
{
|
|
writeFillRectPreclipped(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 // not gfxFont
|
|
#endif // !defined(ATTINY_CORE)
|
|
#if defined(U8G2_FONT_SUPPORT)
|
|
if (u8g2Font)
|
|
{
|
|
Arduino_GFX::drawChar(x, y, c, color, bg);
|
|
}
|
|
else // not u8g2Font
|
|
#endif // defined(U8G2_FONT_SUPPORT)
|
|
{
|
|
block_w = 6 * textsize_x;
|
|
block_h = 8 * textsize_y;
|
|
if (
|
|
(x < _min_text_x) || // Clip left
|
|
(y < _min_text_y) || // Clip top
|
|
((x + block_w - 1) > _max_text_x) || // Clip right
|
|
((y + block_h - 1) > _max_text_y) // Clip bottom
|
|
)
|
|
{
|
|
// partial draw char by parent class
|
|
Arduino_GFX::drawChar(x, y, c, color, bg);
|
|
}
|
|
else
|
|
{
|
|
uint8_t col[5];
|
|
for (int8_t i = 0; i < 5; i++)
|
|
{
|
|
col[i] = pgm_read_byte(&font[c * 5 + i]);
|
|
}
|
|
|
|
startWrite();
|
|
if (bg != color) // have background color
|
|
{
|
|
writeAddrWindow(x, y, block_w, block_h);
|
|
|
|
uint16_t line_buf[block_w];
|
|
if (textsize_x == 1)
|
|
{
|
|
line_buf[5] = bg; // last column always bg
|
|
}
|
|
else
|
|
{
|
|
for (int8_t k = 0; k < textsize_x; k++)
|
|
{
|
|
line_buf[5 * textsize_x + k] = bg;
|
|
}
|
|
}
|
|
uint8_t bit = 1;
|
|
bool draw_dot;
|
|
|
|
while (bit)
|
|
{
|
|
for (int8_t i = 0; i < 5; i++)
|
|
{
|
|
draw_dot = col[i] & bit;
|
|
if (textsize_x == 1)
|
|
{
|
|
line_buf[i] = (draw_dot) ? color : bg;
|
|
}
|
|
else
|
|
{
|
|
if (draw_dot)
|
|
{
|
|
for (int8_t k = 0; k < textsize_x; k++)
|
|
{
|
|
line_buf[i * textsize_x + k] = (k < (textsize_x - text_pixel_margin)) ? color : bg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int8_t k = 0; k < textsize_x; k++)
|
|
{
|
|
line_buf[i * textsize_x + k] = bg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (textsize_y == 1)
|
|
{
|
|
writePixels(line_buf, block_w);
|
|
}
|
|
else
|
|
{
|
|
for (int8_t l = 0; l < textsize_y; l++)
|
|
{
|
|
if (l < (textsize_y - text_pixel_margin))
|
|
{
|
|
writePixels(line_buf, block_w);
|
|
}
|
|
else
|
|
{
|
|
writeRepeat(bg, block_w);
|
|
}
|
|
}
|
|
}
|
|
bit <<= 1;
|
|
}
|
|
}
|
|
else // (bg == color), no background color
|
|
{
|
|
for (int8_t i = 0; i < 5; i++)
|
|
{ // Char bitmap = 5 columns
|
|
uint8_t line = col[i];
|
|
for (int8_t j = 0; j < 8; j++, line >>= 1)
|
|
{
|
|
if (line & 1)
|
|
{
|
|
if (textsize_x == 1 && textsize_y == 1)
|
|
{
|
|
writePixelPreclipped(x + i, y + j, color);
|
|
}
|
|
else
|
|
{
|
|
writeFillRectPreclipped(x + i * textsize_x, y + j * textsize_y, textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
endWrite();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // !defined(LITTLE_FOOT_PRINT)
|