This commit is contained in:
2026-02-12 01:27:25 -08:00
parent b5c81d79f0
commit e9678dd1ea
322 changed files with 297928 additions and 93 deletions

View File

@@ -0,0 +1,661 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#include "../Arduino_GFX.h"
#include "Arduino_Canvas.h"
Arduino_Canvas::Arduino_Canvas(
int16_t w, int16_t h, Arduino_G *output, int16_t output_x, int16_t output_y, uint8_t r)
: Arduino_GFX(w, h), _output(output), _output_x(output_x), _output_y(output_y)
{
MAX_X = WIDTH - 1;
MAX_Y = HEIGHT - 1;
setRotation(r);
}
Arduino_Canvas::~Arduino_Canvas()
{
if (_framebuffer)
{
free(_framebuffer);
}
}
bool Arduino_Canvas::begin(int32_t speed)
{
if (
(speed != GFX_SKIP_OUTPUT_BEGIN) && (_output))
{
if (!_output->begin(speed))
{
return false;
}
}
if (!_framebuffer)
{
size_t s = _width * _height * 2;
#if defined(ESP32)
_framebuffer = (uint16_t *)aligned_alloc(16, s);
#else
_framebuffer = (uint16_t *)malloc(s);
#endif
if (!_framebuffer)
{
return false;
}
}
return true;
}
void Arduino_Canvas::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
{
uint16_t *fb = _framebuffer;
switch (_rotation)
{
case 1:
fb += (int32_t)x * _height;
fb += _max_y - y;
*fb = color;
break;
case 2:
fb += (int32_t)(_max_y - y) * _width;
fb += _max_x - x;
*fb = color;
break;
case 3:
fb += (int32_t)(_max_x - x) * _height;
fb += y;
*fb = color;
break;
default: // case 0:
fb += (int32_t)y * _width;
fb += x;
*fb = color;
}
}
void Arduino_Canvas::writeFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
switch (_rotation)
{
case 1:
writeFastHLineCore(_height - y - h, x, h, color);
break;
case 2:
writeFastVLineCore(_max_x - x, _height - y - h, h, color);
break;
case 3:
writeFastHLineCore(y, _max_x - x, h, color);
break;
default: // case 0:
writeFastVLineCore(x, y, h, color);
}
}
void Arduino_Canvas::writeFastVLineCore(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
// log_i("writeFastVLineCore(x: %d, y: %d, h: %d)", x, y, h);
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
uint16_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x;
while (h--)
{
*fb = color;
fb += WIDTH;
}
}
}
}
}
void Arduino_Canvas::writeFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
// log_i("writeFastHLine(x: %d, y: %d, w: %d)", x, y, w);
switch (_rotation)
{
case 1:
writeFastVLineCore(_max_y - y, x, w, color);
break;
case 2:
writeFastHLineCore(_width - x - w, _max_y - y, w, color);
break;
case 3:
writeFastVLineCore(y, _width - x - w, w, color);
break;
default: // case 0:
writeFastHLineCore(x, y, w, color);
}
}
void Arduino_Canvas::writeFastHLineCore(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
// log_i("writeFastHLineCore(x: %d, y: %d, w: %d)", x, y, w);
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
uint16_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x;
while (w--)
{
*(fb++) = color;
}
}
}
}
}
void Arduino_Canvas::writeFillRectPreclipped(int16_t x, int16_t y,
int16_t w, int16_t h, uint16_t color)
{
// log_i("writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h);
if (_rotation > 0)
{
int16_t t = x;
switch (_rotation)
{
case 1:
x = WIDTH - y - h;
y = t;
t = w;
w = h;
h = t;
break;
case 2:
x = WIDTH - x - w;
y = HEIGHT - y - h;
break;
case 3:
x = y;
y = HEIGHT - t - w;
t = w;
w = h;
h = t;
break;
}
}
// log_i("adjusted writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h);
uint16_t *row = _framebuffer;
row += y * WIDTH;
row += x;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
row[i] = color;
}
row += WIDTH;
}
}
void Arduino_Canvas::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 (_rotation > 0)
{
Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, w, h, x_skip);
}
else
{
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 ((y + h - 1) > _max_y)
{
h -= (y + h - 1) - _max_y;
}
if (y < 0)
{
bitmap -= y * (w + x_skip);
h += y;
y = 0;
}
if ((x + w - 1) > _max_x)
{
x_skip += (x + w - 1) - _max_x;
w -= (x + w - 1) - _max_x;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint16_t *row = _framebuffer;
row += y * _width;
row += x;
int16_t i;
int16_t wi;
while (h--)
{
i = 0;
wi = w;
while (wi >= 4)
{
uint32_t b32 = *((uint32_t *)bitmap);
row[i++] = color_index[(b32 & 0xff)];
row[i++] = color_index[(b32 & 0xff00) >> 8];
row[i++] = color_index[(b32 & 0xff0000) >> 16];
row[i++] = color_index[(b32 & 0xff000000) >> 24];
wi -= 4;
bitmap += 4;
}
while (i < w)
{
row[i++] = color_index[*bitmap++];
}
bitmap += x_skip;
row += _width;
}
}
}
}
void Arduino_Canvas::drawIndexedBitmap(
int16_t x, int16_t y,
uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip)
{
if (_rotation > 0)
{
Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, chroma_key, w, h, x_skip);
}
else
{
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 ((y + h - 1) > _max_y)
{
h -= (y + h - 1) - _max_y;
}
if (y < 0)
{
bitmap -= y * (w + x_skip);
h += y;
y = 0;
}
if ((x + w - 1) > _max_x)
{
x_skip += (x + w - 1) - _max_x;
w -= (x + w - 1) - _max_x;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint16_t *row = _framebuffer;
row += y * _width;
row += x;
int16_t i;
int16_t wi;
uint8_t color_key;
while (h--)
{
i = 0;
wi = w;
while (wi >= 4)
{
uint32_t b32 = *((uint32_t *)bitmap);
color_key = (b32 & 0xff);
if (color_key != chroma_key)
{
row[i] = color_index[color_key];
}
++i;
color_key = (b32 & 0xff00) >> 8;
if (color_key != chroma_key)
{
row[i] = color_index[color_key];
}
++i;
color_key = (b32 & 0xff0000) >> 16;
if (color_key != chroma_key)
{
row[i] = color_index[color_key];
}
++i;
color_key = (b32 & 0xff000000) >> 24;
if (color_key != chroma_key)
{
row[i] = color_index[color_key];
}
++i;
wi -= 4;
bitmap += 4;
}
while (i < w)
{
color_key = *bitmap++;
if (color_key != chroma_key)
{
row[i] = color_index[color_key];
}
++i;
}
bitmap += x_skip;
row += _width;
}
}
}
}
void Arduino_Canvas::draw16bitRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, int16_t w, int16_t h)
{
switch (_rotation)
{
case 1:
gfx_draw_bitmap_to_framebuffer_rotate_1(bitmap, w, h, _framebuffer, x, y, _width, _height);
break;
case 2:
gfx_draw_bitmap_to_framebuffer_rotate_2(bitmap, w, h, _framebuffer, x, y, _width, _height);
break;
case 3:
gfx_draw_bitmap_to_framebuffer_rotate_3(bitmap, w, h, _framebuffer, x, y, _width, _height);
break;
default: // case 0:
gfx_draw_bitmap_to_framebuffer(bitmap, w, h, _framebuffer, x, y, _width, _height);
}
}
void Arduino_Canvas::draw16bitRGBBitmapWithTranColor(
int16_t x, int16_t y,
uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h)
{
if (_rotation > 0)
{
Arduino_GFX::draw16bitRGBBitmapWithTranColor(x, y, bitmap, transparent_color, w, h);
}
else
{
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 x_skip = 0;
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)
{
x_skip = (x + w - 1) - _max_x;
w -= x_skip;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint16_t *row = _framebuffer;
row += y * _width;
row += x;
int16_t i;
int16_t wi;
uint16_t p;
while (h--)
{
i = 0;
wi = w;
while (wi >= 4)
{
uint32_t b32 = *((uint32_t *)bitmap);
p = (b32 & 0xffff);
if (p != transparent_color)
{
row[i] = p;
}
++i;
p = (b32 & 0xffff0000) >> 16;
if (p != transparent_color)
{
row[i] = p;
}
++i;
wi -= 2;
bitmap += 2;
}
while (i < w)
{
p = *bitmap++;
if (p != transparent_color)
{
row[i] = p;
}
++i;
}
bitmap += x_skip;
row += _width;
}
}
}
}
void Arduino_Canvas::draw16bitBeRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, int16_t w, int16_t h)
{
if (_rotation > 0)
{
Arduino_GFX::draw16bitBeRGBBitmap(x, y, bitmap, w, h);
}
else
{
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 x_skip = 0;
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)
{
x_skip = (x + w - 1) - _max_x;
w -= x_skip;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint16_t *row = _framebuffer;
row += y * _width;
row += x;
uint16_t color;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
color = *bitmap++;
MSB_16_SET(row[i], color);
}
bitmap += x_skip;
row += _width;
}
}
}
}
void Arduino_Canvas::flush(bool force_flush)
{
if (_output)
{
_output->draw16bitRGBBitmap(_output_x, _output_y, _framebuffer, WIDTH, HEIGHT);
}
}
void Arduino_Canvas::flushQuad(bool force_flush)
{
int16_t y = _output_y;
uint16_t *row1 = _framebuffer;
uint16_t *row2 = _framebuffer + WIDTH;
if (_output)
{
int16_t hQuad = HEIGHT / 2;
int16_t wQuad = WIDTH / 2;
if (!_rowBuf)
{
_rowBuf = (uint16_t *)malloc(wQuad * 2);
}
uint16_t p;
while (hQuad--)
{
for (int16_t i = 0; i < wQuad; ++i)
{
p = (*row1++ & 0b1110011110011100) >> 2;
p += (*row1++ & 0b1110011110011100) >> 2;
p += (*row2++ & 0b1110011110011100) >> 2;
p += (*row2++ & 0b1110011110011100) >> 2;
_rowBuf[i] = p;
}
_output->draw16bitRGBBitmap(_output_x, _output_y + y++, _rowBuf, wQuad, 1);
row1 += WIDTH;
row2 += WIDTH;
}
}
}
void Arduino_Canvas::shade(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t shade_mask)
{
if (_rotation > 0)
{
int16_t t = x;
switch (_rotation)
{
case 1:
x = WIDTH - y - h;
y = t;
t = w;
w = h;
h = t;
break;
case 2:
x = WIDTH - x - w;
y = HEIGHT - y - h;
break;
case 3:
x = y;
y = HEIGHT - t - w;
t = w;
w = h;
h = t;
break;
}
}
uint16_t *row = _framebuffer;
row += y * WIDTH;
row += x;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
row[i] &= shade_mask;
}
row += WIDTH;
}
}
uint16_t *Arduino_Canvas::getFramebuffer()
{
return _framebuffer;
}
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,47 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#ifndef _ARDUINO_CANVAS_H_
#define _ARDUINO_CANVAS_H_
#include "../Arduino_GFX.h"
class Arduino_Canvas : public Arduino_GFX
{
public:
Arduino_Canvas(int16_t w, int16_t h, Arduino_G *output, int16_t output_x = 0, int16_t output_y = 0, uint8_t rotation = 0);
~Arduino_Canvas();
bool begin(int32_t speed = GFX_NOT_DEFINED) override;
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override;
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
void writeFastVLineCore(int16_t x, int16_t y, int16_t h, uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
void writeFastHLineCore(int16_t x, int16_t y, int16_t w, uint16_t color);
void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override;
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0) override;
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip = 0) override;
void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override;
void draw16bitRGBBitmapWithTranColor(int16_t x, int16_t y, uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h) override;
void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override;
void flush(bool force_flush = false) override;
void flushQuad(bool force_flush = false);
void shade(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t shade_mask);
uint16_t *getFramebuffer();
protected:
uint16_t *_framebuffer = nullptr;
Arduino_G *_output = nullptr;
int16_t _output_x, _output_y;
int16_t MAX_X, MAX_Y;
// for flushQuad() only
uint16_t *_rowBuf = nullptr;
private:
};
#endif // _ARDUINO_CANVAS_H_
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,84 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#include "../Arduino_GFX.h"
#include "Arduino_Canvas_3bit.h"
Arduino_Canvas_3bit::Arduino_Canvas_3bit(int16_t w, int16_t h, Arduino_G *output, int16_t output_x, int16_t output_y)
: Arduino_GFX(w, h), _output(output), _output_x(output_x), _output_y(output_y)
{
}
Arduino_Canvas_3bit::~Arduino_Canvas_3bit()
{
if (_framebuffer)
{
free(_framebuffer);
}
}
bool Arduino_Canvas_3bit::begin(int32_t speed)
{
if (speed != GFX_SKIP_OUTPUT_BEGIN)
{
if (!_output->begin(speed))
{
return false;
}
}
if (!_framebuffer)
{
size_t s = (_width * _height + 1) / 2;
#if defined(ESP32)
if (psramFound())
{
_framebuffer = (uint8_t *)ps_malloc(s);
}
else
{
_framebuffer = (uint8_t *)malloc(s);
}
#else
_framebuffer = (uint8_t *)malloc(s);
#endif
if (!_framebuffer)
{
return false;
}
}
return true;
}
void Arduino_Canvas_3bit::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
{
int32_t pos = x + (y * _width);
int32_t idx = pos >> 1;
uint8_t c = (((color & 0b1000000000000000) ? 0b100 : 0) |
((color & 0b0000010000000000) ? 0b010 : 0) |
((color & 0b0000000000010000) ? 0b001 : 0));
if (pos & 1)
{
_framebuffer[idx] = (_framebuffer[idx] & 0b00111000) | c;
}
else
{
_framebuffer[idx] = (_framebuffer[idx] & 0b00000111) | (c << 3);
}
}
void Arduino_Canvas_3bit::flush(bool force_flush)
{
if (_output)
{
_output->draw3bitRGBBitmap(_output_x, _output_y, _framebuffer, _width, _height);
}
}
uint8_t *Arduino_Canvas_3bit::getFramebuffer()
{
return _framebuffer;
}
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,31 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#ifndef _ARDUINO_CANVAS_3BIT_H_
#define _ARDUINO_CANVAS_3BIT_H_
#include "../Arduino_GFX.h"
class Arduino_Canvas_3bit : public Arduino_GFX
{
public:
Arduino_Canvas_3bit(int16_t w, int16_t h, Arduino_G *output, int16_t output_x = 0, int16_t output_y = 0);
~Arduino_Canvas_3bit();
bool begin(int32_t speed = GFX_NOT_DEFINED) override;
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override;
void flush(bool force_flush = false) override;
uint8_t *getFramebuffer();
protected:
uint8_t *_framebuffer = nullptr;
Arduino_G *_output = nullptr;
int16_t _output_x, _output_y;
private:
};
#endif // _ARDUINO_CANVAS_3BIT_H_
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,564 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#include "../Arduino_GFX.h"
#include "Arduino_Canvas_Indexed.h"
Arduino_Canvas_Indexed::Arduino_Canvas_Indexed(int16_t w, int16_t h, Arduino_G *output, int16_t output_x, int16_t output_y, uint8_t r, uint8_t mask_level)
: Arduino_GFX(w, h), _output(output), _output_x(output_x), _output_y(output_y)
{
MAX_X = WIDTH - 1;
MAX_Y = HEIGHT - 1;
setRotation(r);
if (mask_level >= MAXMASKLEVEL)
{
mask_level = MAXMASKLEVEL - 1;
}
_current_mask_level = mask_level;
_color_mask = mask_level_list[_current_mask_level];
}
Arduino_Canvas_Indexed::~Arduino_Canvas_Indexed()
{
if (_framebuffer)
{
free(_framebuffer);
}
}
bool Arduino_Canvas_Indexed::begin(int32_t speed)
{
if (speed != GFX_SKIP_OUTPUT_BEGIN)
{
if (!_output->begin(speed))
{
return false;
}
}
if (!_framebuffer)
{
size_t s = _width * _height;
#if defined(ESP32)
if (psramFound())
{
_framebuffer = (uint8_t *)ps_malloc(s);
}
else
{
_framebuffer = (uint8_t *)malloc(s);
}
#else
_framebuffer = (uint8_t *)malloc(s);
#endif
if (!_framebuffer)
{
return false;
}
}
return true;
}
void Arduino_Canvas_Indexed::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
{
uint8_t idx;
if (_isDirectUseColorIndex)
{
idx = (uint8_t)color;
}
else
{
idx = get_color_index(color);
}
uint8_t *fb = _framebuffer;
switch (_rotation)
{
case 1:
fb += (int32_t)x * _height;
fb += _max_y - y;
*fb = idx;
break;
case 2:
fb += (int32_t)(_max_y - y) * _width;
fb += _max_x - x;
*fb = idx;
break;
case 3:
fb += (int32_t)(_max_x - x) * _height;
fb += y;
*fb = idx;
break;
default: // case 0:
fb += (int32_t)y * _width;
fb += x;
*fb = idx;
}
}
void Arduino_Canvas_Indexed::writeFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
uint8_t idx;
if (_isDirectUseColorIndex)
{
idx = (uint8_t)color;
}
else
{
idx = get_color_index(color);
}
switch (_rotation)
{
case 1:
writeFastHLineCore(_height - y - h, x, h, idx);
break;
case 2:
writeFastVLineCore(_max_x - x, _height - y - h, h, idx);
break;
case 3:
writeFastHLineCore(y, _max_x - x, h, idx);
break;
default: // case 0:
writeFastVLineCore(x, y, h, idx);
}
}
void Arduino_Canvas_Indexed::writeFastVLineCore(int16_t x, int16_t y,
int16_t h, uint8_t idx)
{
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
uint8_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x;
while (h--)
{
*fb = idx;
fb += WIDTH;
}
}
}
}
}
void Arduino_Canvas_Indexed::writeFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
uint8_t idx;
if (_isDirectUseColorIndex)
{
idx = (uint8_t)color;
}
else
{
idx = get_color_index(color);
}
switch (_rotation)
{
case 1:
writeFastVLineCore(_max_y - y, x, w, idx);
break;
case 2:
writeFastHLineCore(_width - x - w, _max_y - y, w, idx);
break;
case 3:
writeFastVLineCore(y, _width - x - w, w, idx);
break;
default: // case 0:
writeFastHLineCore(x, y, w, idx);
}
}
void Arduino_Canvas_Indexed::writeFastHLineCore(int16_t x, int16_t y,
int16_t w, uint8_t idx)
{
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
uint8_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x;
while (w--)
{
*(fb++) = idx;
}
}
}
}
}
void Arduino_Canvas_Indexed::writeFillRectPreclipped(int16_t x, int16_t y,
int16_t w, int16_t h, uint16_t color)
{
uint8_t idx;
if (_isDirectUseColorIndex)
{
idx = (uint8_t)color;
}
else
{
idx = get_color_index(color);
}
if (_rotation > 0)
{
int16_t t = x;
switch (_rotation)
{
case 1:
x = WIDTH - y - h;
y = t;
t = w;
w = h;
h = t;
break;
case 2:
x = WIDTH - x - w;
y = HEIGHT - y - h;
break;
case 3:
x = y;
y = HEIGHT - t - w;
t = w;
w = h;
h = t;
break;
}
}
// log_i("adjusted writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h);
uint8_t *row = _framebuffer;
row += y * WIDTH;
row += x;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
row[i] = idx;
}
row += WIDTH;
}
}
void Arduino_Canvas_Indexed::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 (_rotation > 0)
{
if (!_isDirectUseColorIndex)
{
Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, w, h, x_skip);
}
else
{
int32_t offset = 0;
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
writePixel(x + i, y, bitmap[offset++]);
}
offset += x_skip;
}
}
}
else
{
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 ((y + h - 1) > _max_y)
{
h -= (y + h - 1) - _max_y;
}
if (y < 0)
{
bitmap -= y * (w + x_skip);
h += y;
y = 0;
}
if ((x + w - 1) > _max_x)
{
x_skip += (x + w - 1) - _max_x;
w -= (x + w - 1) - _max_x;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint8_t *row = _framebuffer;
row += y * _width;
row += x;
int16_t i;
int16_t wi;
if (_isDirectUseColorIndex)
{
while (h--)
{
i = 0;
wi = w;
while (wi >= 4)
{
*((uint32_t *)&row[i]) = *((uint32_t *)bitmap);
i += 4;
wi -= 4;
bitmap += 4;
}
while (i < w)
{
row[i++] = *bitmap++;
}
bitmap += x_skip;
row += _width;
}
}
else
{
while (h--)
{
for (int i = 0; i < w; i++)
{
row[i] = get_color_index(color_index[*bitmap++]);
}
bitmap += x_skip;
row += _width;
}
}
}
}
}
void Arduino_Canvas_Indexed::drawIndexedBitmap(
int16_t x, int16_t y,
uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip)
{
if (_rotation > 0)
{
if (!_isDirectUseColorIndex)
{
Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, chroma_key, w, h, x_skip);
}
else
{
int32_t offset = 0;
uint8_t color_key;
for (int16_t j = 0; j < h; j++, y++)
{
for (int16_t i = 0; i < w; i++)
{
color_key = bitmap[offset++];
if (color_key != chroma_key)
{
writePixel(x + i, y, color_key);
}
}
offset += x_skip;
}
}
}
else
{
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 ((y + h - 1) > _max_y)
{
h -= (y + h - 1) - _max_y;
}
if (y < 0)
{
bitmap -= y * (w + x_skip);
h += y;
y = 0;
}
if ((x + w - 1) > _max_x)
{
x_skip += (x + w - 1) - _max_x;
w -= (x + w - 1) - _max_x;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint8_t *row = _framebuffer;
row += y * _width;
row += x;
uint8_t color_key;
if (_isDirectUseColorIndex)
{
while (h--)
{
for (int i = 0; i < w; i++)
{
color_key = *bitmap++;
if (color_key != chroma_key)
{
row[i] = color_key;
}
}
bitmap += x_skip;
row += _width;
}
}
else
{
while (h--)
{
for (int i = 0; i < w; i++)
{
color_key = *bitmap++;
if (color_key != chroma_key)
{
row[i] = get_color_index(color_index[color_key]);
}
}
bitmap += x_skip;
row += _width;
}
}
}
}
}
void Arduino_Canvas_Indexed::flush(bool force_flush)
{
if (_output)
{
_output->drawIndexedBitmap(_output_x, _output_y, _framebuffer, _color_index, WIDTH, HEIGHT);
}
}
uint8_t *Arduino_Canvas_Indexed::getFramebuffer()
{
return _framebuffer;
}
uint16_t *Arduino_Canvas_Indexed::getColorIndex()
{
return _color_index;
}
void Arduino_Canvas_Indexed::setDirectUseColorIndex(bool isEnable)
{
_isDirectUseColorIndex = isEnable;
}
uint8_t Arduino_Canvas_Indexed::get_color_index(uint16_t color)
{
color &= _color_mask;
for (uint8_t i = 0; i < _indexed_size; i++)
{
if (_color_index[i] == color)
{
return i;
}
}
if (_indexed_size == (COLOR_IDX_SIZE - 1)) // overflowed
{
raise_mask_level();
}
_color_index[_indexed_size] = color;
// print("color_index[");
// print(_indexed_size);
// print("] = ");
// println(color);
return _indexed_size++;
}
GFX_INLINE uint16_t Arduino_Canvas_Indexed::get_index_color(uint8_t idx)
{
return _color_index[idx];
}
void Arduino_Canvas_Indexed::raise_mask_level()
{
if ((_current_mask_level + 1) < MAXMASKLEVEL)
{
int32_t buffer_size = _width * _height;
uint8_t old_indexed_size = _indexed_size;
uint8_t new_color;
_indexed_size = 0;
_color_mask = mask_level_list[++_current_mask_level];
// print("Raised mask level: ");
// println(_current_mask_level);
// update _framebuffer color index, it is a time consuming job
for (uint8_t old_color = 0; old_color < old_indexed_size; old_color++)
{
new_color = get_color_index(_color_index[old_color]);
for (int32_t i = 0; i < buffer_size; i++)
{
if (_framebuffer[i] == old_color)
{
_framebuffer[i] = new_color;
}
}
}
}
}
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,60 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#ifndef _ARDUINO_CANVAS_INDEXED_H_
#define _ARDUINO_CANVAS_INDEXED_H_
#include "../Arduino_GFX.h"
#define COLOR_IDX_SIZE 256
class Arduino_Canvas_Indexed : public Arduino_GFX
{
public:
Arduino_Canvas_Indexed(int16_t w, int16_t h, Arduino_G *output, int16_t output_x = 0, int16_t output_y = 0, uint8_t rotation = 0, uint8_t mask_level = 0);
~Arduino_Canvas_Indexed();
bool begin(int32_t speed = GFX_NOT_DEFINED) override;
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override;
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
void writeFastVLineCore(int16_t x, int16_t y, int16_t h, uint8_t idx);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
void writeFastHLineCore(int16_t x, int16_t y, int16_t w, uint8_t idx);
void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override;
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0) override;
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip = 0) override;
void flush(bool force_flush = false) override;
uint8_t *getFramebuffer();
uint16_t *getColorIndex();
void setDirectUseColorIndex(bool isEnable);
uint8_t get_color_index(uint16_t color);
uint16_t get_index_color(uint8_t idx);
void raise_mask_level();
protected:
uint8_t *_framebuffer = nullptr;
Arduino_G *_output = nullptr;
int16_t _output_x, _output_y;
int16_t MAX_X, MAX_Y;
uint16_t _color_index[COLOR_IDX_SIZE];
uint8_t _indexed_size = 0;
bool _isDirectUseColorIndex = false;
uint8_t _current_mask_level;
uint16_t _color_mask;
#define MAXMASKLEVEL 3
uint16_t mask_level_list[MAXMASKLEVEL] = {
0b1111111111111111, // 16-bit, 65536 colors
0b1111011110011110, // 12-bit, 4096 colors
0b1100011100011000 // 7-bit, 128 colors
};
private:
};
#endif // _ARDUINO_CANVAS_INDEXED_H_
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,116 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#include "../Arduino_GFX.h"
#include "Arduino_Canvas_Mono.h"
Arduino_Canvas_Mono::Arduino_Canvas_Mono(int16_t w, int16_t h, Arduino_G *output, int16_t output_x, int16_t output_y, bool verticalByte)
: Arduino_GFX(w, h), _output(output), _output_x(output_x), _output_y(output_y), _verticalByte(verticalByte),
_canvas_width(w), _canvas_height(h)
{
}
Arduino_Canvas_Mono::~Arduino_Canvas_Mono()
{
if (_framebuffer)
{
free(_framebuffer);
}
}
bool Arduino_Canvas_Mono::begin(int32_t speed)
{
if (speed != GFX_SKIP_OUTPUT_BEGIN)
{
if (_output)
{
if (!_output->begin(speed))
{
return false;
}
}
}
if (!_framebuffer)
{
size_t s;
// allocate memory by full bytes.
if (_verticalByte)
{
s = _canvas_width * (_canvas_height + 7) / 8;
}
else
{
s = (_canvas_width + 7) / 8 * _canvas_height;
}
#if defined(ESP32)
if (psramFound())
{
_framebuffer = (uint8_t *)ps_malloc(s);
}
else
{
_framebuffer = (uint8_t *)malloc(s);
}
#else
_framebuffer = (uint8_t *)malloc(s);
#endif
if (!_framebuffer)
{
return false;
}
}
return true;
}
void Arduino_Canvas_Mono::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
{
// change the pixel in the original orientation of the bitmap buffer
if (_verticalByte)
{
// vertical buffer layout: 1 byte in the buffer contains 8 vertical pixels
int32_t pos = x + (y / 8) * _canvas_width;
if (color & 0b1000010000010000)
{
_framebuffer[pos] |= (1 << (y & 7));
}
else
{
_framebuffer[pos] &= ~(1 << (y & 7));
}
}
else
{
// horizontal buffer layout: 1 byte in the buffer contains 8 horizontal pixels
int16_t w = (_canvas_width + 7) / 8;
int32_t pos = (y * w) + (x / 8);
if (color & 0b1000010000010000)
{
_framebuffer[pos] |= 0x80 >> (x & 7);
}
else
{
_framebuffer[pos] &= ~(0x80 >> (x & 7));
}
}
}
void Arduino_Canvas_Mono::flush(bool force_flush)
{
if (_output)
{
_output->drawBitmap(_output_x, _output_y, _framebuffer, _canvas_width, _canvas_height, RGB565_WHITE, RGB565_BLACK);
}
}
uint8_t *Arduino_Canvas_Mono::getFramebuffer()
{
return _framebuffer;
}
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,33 @@
#include "../Arduino_DataBus.h"
#if !defined(LITTLE_FOOT_PRINT)
#ifndef _ARDUINO_CANVAS_MONO_H_
#define _ARDUINO_CANVAS_MONO_H_
#include "../Arduino_GFX.h"
class Arduino_Canvas_Mono : public Arduino_GFX
{
public:
Arduino_Canvas_Mono(int16_t w, int16_t h, Arduino_G *output, int16_t output_x = 0, int16_t output_y = 0, bool verticalByte = false);
~Arduino_Canvas_Mono();
bool begin(int32_t speed = GFX_NOT_DEFINED) override;
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override;
void flush(bool force_flush = false) override;
uint8_t *getFramebuffer();
protected:
uint8_t *_framebuffer = nullptr;
Arduino_G *_output = nullptr;
int16_t _output_x, _output_y;
bool _verticalByte;
int16_t _canvas_width, _canvas_height; // width and height of canvas buffer
private:
};
#endif // _ARDUINO_CANVAS_MONO_H_
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,15 @@
# About the canvas mono class of the GFX library
There are some Display Chips on the market that can display a small amount of graphic data but
don't offer much functionality on it's own on other than data transfer. Examples are the OLED
Displays Chips SSD1306 or SH1106.
These displays need an in memory copy of the graphics and updating the display is implemented by
a bulk data transfer of the internal memory to the display.
Therefore the Canvas Mono class must be initialized in a way the internal memory fits to the
memory inside the graphic driver chip including the width and height of the display memory and
the orientation of a byte to either horizontal or vertical.
Bei changing the orientation of the canvas the graphics elements like lines or characters are positioned on the display memory accordingly. When the rotating in 90 or 270 degrees der width and height of the logical display will be swapped but not the memory organization.