Put canvases back in order :/

This commit is contained in:
Phillip Burgess
2022-07-22 20:06:13 -07:00
parent 1e8b825b60
commit e31f24b911
11 changed files with 367 additions and 333 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
/***
This example is intended to demonstrate the use of getPixel() versus
getRawPixel() and the fast horizontal and vertical drawing routines
getPixelRaw() and the fast horizontal and vertical drawing routines
in the GFXcanvas family of classes,
When using the GFXcanvas* classes as the image buffer for a hardware driver,
@@ -11,7 +11,7 @@ GFXcanvas* classes that allow fetching of specific pixel values.
* getPixel(x, y) : Gets the pixel color value at the rotated coordinates in
the image.
* getRawPixel(x,y) : Gets the pixel color value at the unrotated coordinates
* getPixelRaw(x,y) : Gets the pixel color value at the unrotated coordinates
in the image. This is useful for getting the pixel value to map to a hardware
pixel location. This method was made protected as only the hardware driver
should be accessing it.
+3 -3
View File
@@ -22,7 +22,7 @@ void GFXcanvas1SerialDemo::print(bool rotated) {
if (rotated) {
pixel = this->getPixel(x, y);
} else {
pixel = this->getRawPixel(x, y);
pixel = this->getPixelRaw(x, y);
}
sprintf(pixel_buffer, " %d", pixel);
Serial.print(pixel_buffer);
@@ -52,7 +52,7 @@ void GFXcanvas8SerialDemo::print(bool rotated) {
if (rotated) {
pixel = this->getPixel(x, y);
} else {
pixel = this->getRawPixel(x, y);
pixel = this->getPixelRaw(x, y);
}
sprintf(pixel_buffer, " %02x", pixel);
Serial.print(pixel_buffer);
@@ -82,7 +82,7 @@ void GFXcanvas16SerialDemo::print(bool rotated) {
if (rotated) {
pixel = this->getPixel(x, y);
} else {
pixel = this->getRawPixel(x, y);
pixel = this->getPixelRaw(x, y);
}
sprintf(pixel_buffer, " %04x", pixel);
Serial.print(pixel_buffer);
+4 -4
View File
@@ -52,11 +52,11 @@ public:
virtual void startWrite(void);
virtual void writePixel(int16_t x, int16_t y, uint16_t color);
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color);
uint16_t color);
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color);
uint16_t color);
virtual void endWrite(void);
// CONTROL API
@@ -77,9 +77,9 @@ public:
virtual void fillScreen(uint16_t color);
// Optional and probably not necessary to change
virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color);
uint16_t color);
virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color);
uint16_t color);
// These exist only with Adafruit_GFX (no subclass overrides)
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
+201 -155
View File
@@ -31,92 +31,109 @@ const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
@param h Canvas height in pixels.
*/
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
buffer = (uint8_t *)calloc(((w + 7) / 8) * h, 1); // Rows are byte aligned
// Rows are byte-aligned. If allocation fails, no special action is
// performed here. Drawing functions check for valid buffer.
pixbuf = (uint8_t *)calloc(((w + 7) / 8) * h, 1);
}
/*!
@brief Delete canvas, free memory.
@brief GFXcanvas1 destructor. Frees memory associated with canvas.
*/
GFXcanvas1::~GFXcanvas1(void) {
if (buffer)
free(buffer);
}
if (pixbuf) {
free(pixbuf);
}
};
/*!
@brief Draw a pixel to the canvas framebuffer, applying clipping and/or
rotation as appropriate.
@param x Pixel column (horizonal pos).
@param y Pixel row (vertical pos).
@param color Binary (on or off) color to set pixel.
@param color Pixel draw color. Range depends on canvas depth.
*/
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
// Validate canvas buffer is valid & point is in bounds
if (buffer && (x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
// Apply 'soft' rotation if needed
if (pixbuf && (x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
// Point is valid. Apply 'soft' rotation if needed.
int16_t t;
switch (rotation) {
case 1:
switch (rotation) { // 0 can be ignored
case 1: // 90 degrees CW
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
case 2: // 180 degrees
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
case 3: // 90 degrees CCW
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}
// (x, y) now known in-bounds and in native coordinate system.
uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
#ifdef __AVR__
if (color)
*ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
else
*ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
#else
if (color)
*ptr |= 0x80 >> (x & 7);
else
*ptr &= ~(0x80 >> (x & 7));
#endif
// (x, y) now known in-bounds and in canvas-native coordinate system.
drawPixelRaw(x, y, color);
}
}
/*!
@brief Draw a pixel to the canvas framebuffer. NO CLIPPING, ROTATION OR
VALIDATION OF CANVAS BUFFER IS PERFORMED, calling function must be
AWARE and WELL-BEHAVED. This is a protected function intended for
related class code, not user-facing.
@param x Pixel column (horizonal pos).
@param y Pixel row (vertical pos).
@param color Pixel draw color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas1::drawPixelRaw(int16_t x, int16_t y, uint16_t color) {
uint8_t *ptr = &pixbuf[(x / 8) + y * ((WIDTH + 7) / 8)];
#ifdef __AVR__
if (color)
*ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
else
*ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
#else
if (color)
*ptr |= 0x80 >> (x & 7);
else
*ptr &= ~(0x80 >> (x & 7));
#endif
}
/*!
@brief Retrieve pixel value from the canvas framebuffer, applying
clipping and/or rotation as appropriate.
@param x Pixel column (horizonal pos).
@param y Pixel row (vertical pos).
@return Pixel value (0 or 1) if coordinate is in-bounds. 0 if out-of-
bounds or if canvas buffer previously failed to allocate.
@return Pixel value if coordinate is in-bounds. 0 if out-of-bounds
or if canvas buffer previously failed to allocate.
*/
bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
if (buffer && (x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
// Validate canvas buffer is valid & point is in bounds
if (pixbuf && (x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
// Point is valid. Apply 'soft' rotation if needed.
int16_t t;
switch (rotation) {
case 1:
switch (rotation) { // 0 can be ignored
case 1: // 90 degrees CW
t = x;
x = WIDTH - 1 - y;
y = t;
break;
case 2:
case 2: // 180 degrees
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
break;
case 3:
case 3: // 90 degrees CCW
t = x;
x = y;
y = HEIGHT - 1 - t;
break;
}
// (x, y) now known in-bounds and in native coordinate system.
return getRawPixel(x, y);
// (x, y) now known in-bounds and in canvas-native coordinate system.
return getPixelRaw(x, y);
}
return 0; // Coord out of bounds, or canvas buffer is invalid
}
@@ -124,14 +141,15 @@ bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
/*!
@brief Retrieve pixel value from the canvas framebuffer, where inputs
are known valid in-bounds and in native unrotated coordinates.
NO CLIPPING OR VALIDATION OF CANVAS BUFFER IS PERFORMED,
calling function must be AWARE and WELL-BEHAVED.
NO CLIPPING, ROTATION OR VALIDATION OF CANVAS BUFFER IS PERFORMED,
calling function must be AWARE and WELL-BEHAVED. This is a
protected function intended for driver code, not user-facing.
@param x Pixel column (horizonal pos).
@param y Pixel row (vertical pos).
@return Pixel value (0 or 1).
*/
bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
bool GFXcanvas1::getPixelRaw(int16_t x, int16_t y) const {
uint8_t *ptr = &pixbuf[(x / 8) + y * ((WIDTH + 7) / 8)];
#ifdef __AVR__
return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
#else
@@ -141,142 +159,78 @@ bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
/*!
@brief Fill canvas completely with one color.
@param color Binary (on or off) color to fill with.
@param color Canvas fill color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas1::fillScreen(uint16_t color) {
if (buffer) {
memset(buffer, color ? 0xFF : 0x00, ((WIDTH + 7) / 8) * HEIGHT);
if (pixbuf) {
memset(pixbuf, color ? 0xFF : 0x00, ((WIDTH + 7) / 8) * HEIGHT);
}
}
/*!
@brief Draw vertical line. May allow for optimizations compared to the
generalized drawLine().
generalized drawLine() function.
@param x Column (horizontal position of start and end points)
@param y Row (vertical pos) of start point.
@param h Length of vertical line to be drawn, including first point.
@param color Binary (on or off) color to draw.
@param color Line draw color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h,
uint16_t color) {
if (h < 0) { // Convert negative heights to positive equivalent
h = -h;
y -= h - 1;
if (y < 0) {
h += y;
y = 0;
}
}
// Edge rejection (no-draw if totally off canvas)
if ((x >= 0) && (x < _width) && (y < _height) && ((y + h - 1) >= 0)) {
if (y < 0) { // Clip top
h += y;
y = 0;
}
if (y + h > height()) { // Clip bottom
h = height() - y;
}
int16_t t;
switch (rotation) {
case 0:
drawFastRawVLine(x, y, h, color);
break;
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
x -= h - 1;
drawFastRawHLine(x, y, h, color);
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
if (pixbuf) {
if (h < 0) { // Convert negative heights to positive equivalent
h = -h;
y -= h - 1;
drawFastRawVLine(x, y, h, color);
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
drawFastRawHLine(x, y, h, color);
break;
}
}
}
/*!
@brief Draw horizontal line. May allow for optimizations compared to the
generalized drawLine().
@param x Column (horizontal position) of start point.
@param y Row (vertical position of start and end points)
@param w Width of vertical line to be drawn, including first point.
@param color Binary (on or off) color to draw.
*/
void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w,
uint16_t color) {
if (w < 0) { // Convert negative widths to positive equivalent
w *= -1;
x -= w - 1;
if (x < 0) {
w += x;
x = 0;
}
}
// Edge rejection (no-draw if totally off canvas)
if ((y >= 0) && (y < _height) && (x < _width) && ((x + w - 1) >= 0)) {
if (x < 0) { // Clip left
w += x;
x = 0;
}
if (x + w >= width()) { // Clip right
w = width() - x;
if (y < 0) {
h += y;
y = 0;
}
}
int16_t t;
switch (rotation) {
case 0:
drawFastRawHLine(x, y, w, color);
break;
case 1:
t = x;
x = WIDTH - 1 - y;
y = t;
drawFastRawVLine(x, y, w, color);
break;
case 2:
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
x -= w - 1;
drawFastRawHLine(x, y, w, color);
break;
case 3:
t = x;
x = y;
y = HEIGHT - 1 - t;
y -= w - 1;
drawFastRawVLine(x, y, w, color);
break;
// Reject off-canvas and zero-height lines
if ((h > 0) && (x >= 0) && (x < _width) && (y < _height) &&
((y + h - 1) >= 0)) {
if (y < 0) { // Clip top
h += y;
y = 0;
}
if ((y + h) > _height) { // Clip bottom
h = _height - y;
}
switch (rotation) {
case 0: // No rotation
drawFastVLineRaw(x, y, h, color);
break;
case 1: // 90 degrees CW
drawFastHLineRaw(WIDTH - y - h, x, h, color);
break;
case 2: // 180 degrees
drawFastVLineRaw(WIDTH - 1 - x, HEIGHT - y - h, h, color);
break;
case 3: // 90 degrees CCW
drawFastHLineRaw(y, HEIGHT - 1 - x, h, color);
break;
}
}
}
}
/*!
@brief Draw vertical line into 'raw' canvas buffer. Inputs are assumed
valid and in native coordinates; NO CLIPPING, ROTATION OR BUFFER
VALIDATION IS PERFORMED.
valid and in native coordinates. NO CLIPPING, ROTATION OR
VALIDATION OF CANVAS BUFFER IS PERFORMED, calling function must
be AWARE and WELL-BEHAVED. This is a protected function intended
for related class code, not user-facing.
@param x Column (horizontal position of start and end points)
@param y Row (vertical pos) of start point.
@param h Length of vertical line to be drawn, including first point.
@param color Binary (on or off) color to draw.
@param color Line draw color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
void GFXcanvas1::drawFastVLineRaw(int16_t x, int16_t y, int16_t h,
uint16_t color) {
int16_t row_bytes = ((WIDTH + 7) / 8); // Row-to-row increment
uint8_t *ptr = &buffer[(x / 8) + y * row_bytes];
uint8_t *ptr = &pixbuf[(x / 8) + y * row_bytes];
if (color > 0) {
#ifdef __AVR__
@@ -303,21 +257,112 @@ void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
/*!
@brief Draw horizontal line. May allow for optimizations compared to the
generalized drawLine().
@brief Draw horizontal line into 'raw' canvas buffer. Inputs are assumed
valid and in native coordinates; NO CLIPPING, ROTATION OR BUFFER
VALIDATION IS PERFORMED.
generalized drawLine() function.
@param x Column (horizontal position) of start point.
@param y Row (vertical position of start and end points)
@param w Width of vertical line to be drawn, including first point.
@param color Binary (on or off) color to draw.
@param color Line draw color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w,
uint16_t color) {
if (pixbuf) {
if (w < 0) { // Convert negative widths to positive equivalent
w = -w;
x -= w - 1;
if (x < 0) {
w += x;
x = 0;
}
}
// Reject off-canvas and zero-width lines
if ((w > 0) && (y >= 0) && (y < _height) && (x < _width) &&
((x + w - 1) >= 0)) {
if (x < 0) { // Clip left
w += x;
x = 0;
}
if ((x + w) >= _width) { // Clip right
w = _width - x;
}
switch (rotation) {
case 0: // No rotation
drawFastHLineRaw(x, y, w, color);
break;
case 1: // 90 degrees CW
drawFastVLineRaw(WIDTH - 1 - y, x, w, color);
break;
case 2: // 180 degrees
drawFastHLineRaw(WIDTH - x - w, HEIGHT - 1 - y, w, color);
break;
case 3: // 90 degrees CCW
drawFastVLineRaw(y, HEIGHT - x - w, w, color);
break;
}
}
}
}
/*!
@brief Draw horizontal line into 'raw' canvas buffer. Inputs are assumed
valid and in native coordinates. NO CLIPPING, ROTATION OR
VALIDATION OF CANVAS BUFFER IS PERFORMED, calling function must
be AWARE and WELL-BEHAVED. This is a protected function intended
for related class code, not user-facing.
@param x Column (horizontal position) of start point.
@param y Row (vertical position of start and end points)
@param w Width of vertical line to be drawn, including first point.
@param color Line draw color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas1::drawFastHLineRaw(int16_t x, int16_t y, int16_t w,
uint16_t color) {
int16_t rowBytes = ((WIDTH + 7) / 8);
uint8_t *ptr = &buffer[(x / 8) + y * rowBytes];
uint8_t *ptr = &pixbuf[(x / 8) + y * ((WIDTH + 7) / 8)];
#if 0
// Do partial fill on first byte; may be only byte needed
// If more bytes...
// Fill the solid ones.
// If a lingering byte...
// Do partial fill on that
if (x & 7) { // Partial fill on first byte?
x & 7 = first bit set in first byte
(w & 7) + 1 ??? = number of bits set in first byte
mask = (0xFF >> (7 - (w & 7))) << (x & 7);
if ((color)) {
*ptr |= mask;
} else {
*ptr &= ~mask;
}
ptr++;
w -=
if (x & 7) { // Partial fill on first byte?
uint8_t mask = 0xFF >> mod; // Consider bits from mod to end of 1st byte
foo = 8 - mod; // Bits to end of 1st byte
if (w < foo) { // If line width is less than this,
mask &= (0xFF << (foo - w));
}
// wait - wh if I started with mask of w&7 bits?
*
if (w < mod) {
mask &= 0xFF << (mod - w);
}
w -= mod;
}
if width is less than remainder, mask the mask
if ((x & 7) > 0) { // Partial fill on first byte?
// create bit mask for first byte
uint8_t startByteBitMask = 0x00;
for (int8_t i = (x & 7); ((i < 8) && (w > 0)); i++) {
@@ -360,4 +405,5 @@ void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
}
}
}
#endif
}
+9 -12
View File
@@ -18,30 +18,27 @@
#include "Adafruit_GFX.h"
/// A GFX 1-bit canvas context for graphics
// A 1-bit canvas for offscreen graphics in RAM.
class GFXcanvas1 : public Adafruit_GFX {
public:
GFXcanvas1(uint16_t w, uint16_t h);
~GFXcanvas1(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
bool getPixel(int16_t x, int16_t y) const;
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
bool getPixel(int16_t x, int16_t y) const;
void fillScreen(uint16_t color);
/*!
@brief Get pointer to internal canvas memory.
@return Pointer (uint8_t *) to start of canvas buffer.
*/
uint8_t *getBuffer(void) const { return buffer; }
uint8_t *getBuffer(void) const { return pixbuf; };
protected:
bool getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
private:
uint8_t *buffer;
uint8_t *pixbuf = NULL;
void drawPixelRaw(int16_t x, int16_t y, uint16_t color);
bool getPixelRaw(int16_t x, int16_t y) const;
void drawFastVLineRaw(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLineRaw(int16_t x, int16_t y, int16_t w, uint16_t color);
#ifdef __AVR__
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[];
+35 -33
View File
@@ -24,21 +24,19 @@
*/
/**************************************************************************/
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
uint32_t bytes = w * h * 2;
if ((buffer = (uint16_t *)malloc(bytes))) {
memset(buffer, 0, bytes);
}
// If allocation fails, no special action is performed here.
// Drawing functions check for valid buffer.
pixbuf = (uint16_t *)calloc(w * h * 2, 0);
}
/**************************************************************************/
/*!
@brief Delete the canvas, free memory
@brief GFXcanvas16 destructor. Frees memory associated with canvas.
*/
/**************************************************************************/
GFXcanvas16::~GFXcanvas16(void) {
if (buffer)
free(buffer);
}
if (pixbuf) {
free(pixbuf);
}
};
/**************************************************************************/
/*!
@@ -49,7 +47,7 @@ GFXcanvas16::~GFXcanvas16(void) {
*/
/**************************************************************************/
void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (buffer) {
if (pixbuf) {
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
return;
@@ -71,10 +69,14 @@ void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
break;
}
buffer[x + y * WIDTH] = color;
pixbuf[x + y * WIDTH] = color;
}
}
void GFXcanvas16::drawPixelRaw(int16_t x, int16_t y, uint16_t color) {
pixbuf[x + y * WIDTH] = color;
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given coordinate
@@ -101,7 +103,7 @@ uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
y = HEIGHT - 1 - t;
break;
}
return getRawPixel(x, y);
return getPixelRaw(x, y);
}
/**********************************************************************/
@@ -114,11 +116,11 @@ uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
@returns The desired pixel's 16-bit 5-6-5 color value
*/
/**********************************************************************/
uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
uint16_t GFXcanvas16::getPixelRaw(int16_t x, int16_t y) const {
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
return 0;
if (buffer) {
return buffer[x + y * WIDTH];
if (pixbuf) {
return pixbuf[x + y * WIDTH];
}
return 0;
}
@@ -130,14 +132,14 @@ uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
*/
/**************************************************************************/
void GFXcanvas16::fillScreen(uint16_t color) {
if (buffer) {
if (pixbuf) {
uint8_t hi = color >> 8, lo = color & 0xFF;
if (hi == lo) {
memset(buffer, lo, WIDTH * HEIGHT * 2);
memset(pixbuf, lo, WIDTH * HEIGHT * 2);
} else {
uint32_t i, pixels = WIDTH * HEIGHT;
for (i = 0; i < pixels; i++)
buffer[i] = color;
pixbuf[i] = color;
}
}
}
@@ -156,10 +158,10 @@ void GFXcanvas16::fillScreen(uint16_t color) {
*/
/**************************************************************************/
void GFXcanvas16::byteSwap(void) {
if (buffer) {
if (pixbuf) {
uint32_t i, pixels = WIDTH * HEIGHT;
for (i = 0; i < pixels; i++)
buffer[i] = __builtin_bswap16(buffer[i]);
pixbuf[i] = __builtin_bswap16(pixbuf[i]);
}
}
@@ -197,24 +199,24 @@ void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h,
}
if (getRotation() == 0) {
drawFastRawVLine(x, y, h, color);
drawFastVLineRaw(x, y, h, color);
} else if (getRotation() == 1) {
int16_t t = x;
x = WIDTH - 1 - y;
y = t;
x -= h - 1;
drawFastRawHLine(x, y, h, color);
drawFastHLineRaw(x, y, h, color);
} else if (getRotation() == 2) {
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
y -= h - 1;
drawFastRawVLine(x, y, h, color);
drawFastVLineRaw(x, y, h, color);
} else if (getRotation() == 3) {
int16_t t = x;
x = y;
y = HEIGHT - 1 - t;
drawFastRawHLine(x, y, h, color);
drawFastHLineRaw(x, y, h, color);
}
}
@@ -252,24 +254,24 @@ void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w,
}
if (getRotation() == 0) {
drawFastRawHLine(x, y, w, color);
drawFastHLineRaw(x, y, w, color);
} else if (getRotation() == 1) {
int16_t t = x;
x = WIDTH - 1 - y;
y = t;
drawFastRawVLine(x, y, w, color);
drawFastVLineRaw(x, y, w, color);
} else if (getRotation() == 2) {
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
x -= w - 1;
drawFastRawHLine(x, y, w, color);
drawFastHLineRaw(x, y, w, color);
} else if (getRotation() == 3) {
int16_t t = x;
x = y;
y = HEIGHT - 1 - t;
y -= w - 1;
drawFastRawVLine(x, y, w, color);
drawFastVLineRaw(x, y, w, color);
}
}
@@ -282,10 +284,10 @@ void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w,
@param color color 16-bit 5-6-5 Color to draw line with
*/
/**************************************************************************/
void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
void GFXcanvas16::drawFastVLineRaw(int16_t x, int16_t y, int16_t h,
uint16_t color) {
// x & y already in raw (rotation 0) coordinates, no need to transform.
uint16_t *buffer_ptr = buffer + y * WIDTH + x;
uint16_t *buffer_ptr = &pixbuf[y * WIDTH + x];
for (int16_t i = 0; i < h; i++) {
(*buffer_ptr) = color;
buffer_ptr += WIDTH;
@@ -301,11 +303,11 @@ void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
@param color color 16-bit 5-6-5 Color to draw line with
*/
/**************************************************************************/
void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
void GFXcanvas16::drawFastHLineRaw(int16_t x, int16_t y, int16_t w,
uint16_t color) {
// x & y already in raw (rotation 0) coordinates, no need to transform.
uint32_t buffer_index = y * WIDTH + x;
for (uint32_t i = buffer_index; i < buffer_index + w; i++) {
buffer[i] = color;
pixbuf[i] = color;
}
}
+12 -16
View File
@@ -18,30 +18,26 @@
#include "Adafruit_GFX.h"
/// A GFX 16-bit canvas context for graphics
// A 16-bit canvas for offscreen graphics in RAM.
class GFXcanvas16 : public Adafruit_GFX {
public:
GFXcanvas16(uint16_t w, uint16_t h);
~GFXcanvas16(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
void byteSwap(void);
uint16_t getPixel(int16_t x, int16_t y) const;
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint16_t getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
void fillScreen(uint16_t color);
/*!
@brief Get a pointer to the internal buffer memory
@returns A pointer to the allocated buffer
@brief Get pointer to internal canvas memory.
@return Pointer (uint16_t *) to start of canvas buffer.
*/
/**********************************************************************/
uint16_t *getBuffer(void) const { return buffer; }
uint16_t *getBuffer(void) const { return pixbuf; };
void byteSwap(void);
protected:
uint16_t getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
private:
uint16_t *buffer;
uint16_t *pixbuf = NULL;
void drawPixelRaw(int16_t x, int16_t y, uint16_t color);
uint16_t getPixelRaw(int16_t x, int16_t y) const;
void drawFastVLineRaw(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLineRaw(int16_t x, int16_t y, int16_t w, uint16_t color);
};
+47 -36
View File
@@ -24,21 +24,19 @@
*/
/**************************************************************************/
GFXcanvas4::GFXcanvas4(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
uint16_t bytes = ((w + 1) / 2) * h; // Scanlines are byte-aligned
if ((buffer = (uint8_t *)malloc(bytes))) {
memset(buffer, 0, bytes);
}
// Rows are byte-aligned. If allocation fails, no special action is
// performed here. Drawing functions check for valid buffer.
pixbuf = (uint8_t *)calloc(((w + 1) / 2) * h, 1);
}
/**************************************************************************/
/*!
@brief Delete the canvas, free memory
@brief GFXcanvas4 destructor. Frees memory associated with canvas.
*/
/**************************************************************************/
GFXcanvas4::~GFXcanvas4(void) {
if (buffer)
free(buffer);
}
if (pixbuf) {
free(pixbuf);
}
};
/**************************************************************************/
/*!
@@ -49,7 +47,7 @@ GFXcanvas4::~GFXcanvas4(void) {
*/
/**************************************************************************/
void GFXcanvas4::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (buffer) {
if (pixbuf) {
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
return;
@@ -71,16 +69,29 @@ void GFXcanvas4::drawPixel(int16_t x, int16_t y, uint16_t color) {
break;
}
uint8_t *ptr = &buffer[(x / 2) + y * ((WIDTH + 1) / 2)];
if (x & 1) { // Odd column - lower nybble
*ptr = (*ptr & 0xF0) | (color & 0xF);
} else { // Even column - upper nybble
*ptr = (*ptr & 0x0F) | (color << 4);
}
drawPixelRaw(x, y, color);
}
}
bool GFXcanvas4::getPixel(int16_t x, int16_t y) const {
/*!
@brief Draw a pixel to the canvas framebuffer. NO CLIPPING, ROTATION OR
VALIDATION OF CANVAS BUFFER IS PERFORMED, calling function must be
AWARE and WELL-BEHAVED. This is a protected function intended for
related class code, not user-facing.
@param x Pixel column (horizonal pos).
@param y Pixel row (vertical pos).
@param color Pixel draw color; thresholded to 0 or 1 (any nonzero input).
*/
void GFXcanvas4::drawPixelRaw(int16_t x, int16_t y, uint16_t color) {
uint8_t *ptr = &pixbuf[(x / 2) + y * ((WIDTH + 1) / 2)];
if (x & 1) { // Odd column - lower nybble
*ptr = (*ptr & 0xF0) | (color & 0xF);
} else { // Even column - upper nybble
*ptr = (*ptr & 0x0F) | (color << 4);
}
}
uint8_t GFXcanvas4::getPixel(int16_t x, int16_t y) const {
int16_t t;
switch (rotation) {
case 1:
@@ -98,14 +109,14 @@ bool GFXcanvas4::getPixel(int16_t x, int16_t y) const {
y = HEIGHT - 1 - t;
break;
}
return getRawPixel(x, y);
return getPixelRaw(x, y);
}
bool GFXcanvas4::getRawPixel(int16_t x, int16_t y) const {
uint8_t GFXcanvas4::getPixelRaw(int16_t x, int16_t y) const {
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
return 0;
if (buffer) {
uint8_t *ptr = &buffer[(x / 2) + y * ((WIDTH + 1) / 2)];
if (pixbuf) {
uint8_t *ptr = &pixbuf[(x / 2) + y * ((WIDTH + 1) / 2)];
if (x & 1) { // Odd column - lower nybble
return *ptr & 0xF;
} else { // Even column - upper nybble
@@ -122,8 +133,8 @@ bool GFXcanvas4::getRawPixel(int16_t x, int16_t y) const {
*/
/**************************************************************************/
void GFXcanvas4::fillScreen(uint16_t color) {
if (buffer) {
memset(buffer, (color & 0xF) * 0x11, ((WIDTH + 1) / 2) * HEIGHT);
if (pixbuf) {
memset(pixbuf, (color & 0xF) * 0x11, ((WIDTH + 1) / 2) * HEIGHT);
}
}
@@ -162,24 +173,24 @@ void GFXcanvas4::drawFastVLine(int16_t x, int16_t y, int16_t h,
}
if (getRotation() == 0) {
drawFastRawVLine(x, y, h, color);
drawFastVLineRaw(x, y, h, color);
} else if (getRotation() == 1) {
int16_t t = x;
x = WIDTH - 1 - y;
y = t;
x -= h - 1;
drawFastRawHLine(x, y, h, color);
drawFastHLineRaw(x, y, h, color);
} else if (getRotation() == 2) {
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
y -= h - 1;
drawFastRawVLine(x, y, h, color);
drawFastVLineRaw(x, y, h, color);
} else if (getRotation() == 3) {
int16_t t = x;
x = y;
y = HEIGHT - 1 - t;
drawFastRawHLine(x, y, h, color);
drawFastHLineRaw(x, y, h, color);
}
}
@@ -217,24 +228,24 @@ void GFXcanvas4::drawFastHLine(int16_t x, int16_t y, int16_t w,
}
if (getRotation() == 0) {
drawFastRawHLine(x, y, w, color);
drawFastHLineRaw(x, y, w, color);
} else if (getRotation() == 1) {
int16_t t = x;
x = WIDTH - 1 - y;
y = t;
drawFastRawVLine(x, y, w, color);
drawFastVLineRaw(x, y, w, color);
} else if (getRotation() == 2) {
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
x -= w - 1;
drawFastRawHLine(x, y, w, color);
drawFastHLineRaw(x, y, w, color);
} else if (getRotation() == 3) {
int16_t t = x;
x = y;
y = HEIGHT - 1 - t;
y -= w - 1;
drawFastRawVLine(x, y, w, color);
drawFastVLineRaw(x, y, w, color);
}
}
@@ -247,11 +258,11 @@ void GFXcanvas4::drawFastHLine(int16_t x, int16_t y, int16_t w,
@param color Color to fill with
*/
/**************************************************************************/
void GFXcanvas4::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
void GFXcanvas4::drawFastVLineRaw(int16_t x, int16_t y, int16_t h,
uint16_t color) {
// x & y already in raw (rotation 0) coordinates, no need to transform.
int16_t row_bytes = ((WIDTH + 1) / 2);
uint8_t *ptr = &buffer[(x / 2) + y * row_bytes];
uint8_t *ptr = &pixbuf[(x / 2) + y * row_bytes];
uint8_t mask;
if (x & 1) { // Odd column - lower nybble
@@ -276,11 +287,11 @@ void GFXcanvas4::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
@param color Binary (on or off) color to fill with
*/
/**************************************************************************/
void GFXcanvas4::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
void GFXcanvas4::drawFastHLineRaw(int16_t x, int16_t y, int16_t w,
uint16_t color) {
// x & y already in raw (rotation 0) coordinates, no need to transform.
int16_t rowBytes = ((WIDTH + 1) / 2);
uint8_t *ptr = &buffer[(x / 2) + y * rowBytes];
uint8_t *ptr = &pixbuf[(x / 2) + y * rowBytes];
color &= 0xF;
// check to see if first byte needs to be partially filled
+11 -27
View File
@@ -18,41 +18,25 @@
#include "Adafruit_GFX.h"
/// A GFX 4-bit canvas context for graphics
// A 4-bit canvas for offscreen graphics in RAM.
class GFXcanvas4 : public Adafruit_GFX {
public:
GFXcanvas4(uint16_t w, uint16_t h);
~GFXcanvas4(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
uint8_t getPixel(int16_t x, int16_t y) const;
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void fillScreen(uint16_t color);
/*!
@brief Get the pixel color value at a given coordinate
@param x x coordinate
@param y y coordinate
@returns The pixel's color value, 0 to 15
@brief Get pointer to internal canvas memory.
@return Pointer (uint8_t *) to start of canvas buffer.
*/
bool getPixel(int16_t x, int16_t y) const;
/*!
@brief Get a pointer to the internal buffer memory
@returns A pointer to the allocated buffer
*/
uint8_t *getBuffer(void) const { return buffer; }
uint8_t *getBuffer(void) const { return pixbuf; };
protected:
/*!
@brief Get the pixel color value at a given, unrotated coordinate.
This method is intended for hardware drivers to get pixel value
in native physical coordinates.
@param x x coordinate
@param y y coordinate
@returns The pixel's color value, 0 to 15
*/
bool getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
private:
uint8_t *buffer;
uint8_t *pixbuf = NULL;
void drawPixelRaw(int16_t x, int16_t y, uint16_t color);
uint8_t getPixelRaw(int16_t x, int16_t y) const;
void drawFastVLineRaw(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLineRaw(int16_t x, int16_t y, int16_t w, uint16_t color);
};
+32 -30
View File
@@ -24,21 +24,19 @@
*/
/**************************************************************************/
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
uint32_t bytes = w * h;
if ((buffer = (uint8_t *)malloc(bytes))) {
memset(buffer, 0, bytes);
}
// If allocation fails, no special action is performed here.
// Drawing functions check for valid buffer.
pixbuf = (uint8_t *)calloc(w * h, 1);
}
/**************************************************************************/
/*!
@brief Delete the canvas, free memory
@brief GFXcanvas8 destructor. Frees memory associated with canvas.
*/
/**************************************************************************/
GFXcanvas8::~GFXcanvas8(void) {
if (buffer)
free(buffer);
}
if (pixbuf) {
free(pixbuf);
}
};
/**************************************************************************/
/*!
@@ -49,7 +47,7 @@ GFXcanvas8::~GFXcanvas8(void) {
*/
/**************************************************************************/
void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (buffer) {
if (pixbuf) {
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
return;
@@ -71,10 +69,14 @@ void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
break;
}
buffer[x + y * WIDTH] = color;
pixbuf[x + y * WIDTH] = color;
}
}
void GFXcanvas8::drawPixelRaw(int16_t x, int16_t y, uint16_t color) {
pixbuf[x + y * WIDTH] = color;
}
/**********************************************************************/
/*!
@brief Get the pixel color value at a given coordinate
@@ -101,7 +103,7 @@ uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
y = HEIGHT - 1 - t;
break;
}
return getRawPixel(x, y);
return getPixelRaw(x, y);
}
/**********************************************************************/
@@ -114,11 +116,11 @@ uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
@returns The desired pixel's 8-bit color value
*/
/**********************************************************************/
uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
uint8_t GFXcanvas8::getPixelRaw(int16_t x, int16_t y) const {
if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
return 0;
if (buffer) {
return buffer[x + y * WIDTH];
if (pixbuf) {
return pixbuf[x + y * WIDTH];
}
return 0;
}
@@ -130,8 +132,8 @@ uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
*/
/**************************************************************************/
void GFXcanvas8::fillScreen(uint16_t color) {
if (buffer) {
memset(buffer, color, WIDTH * HEIGHT);
if (pixbuf) {
memset(pixbuf, color, WIDTH * HEIGHT);
}
}
@@ -170,24 +172,24 @@ void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h,
}
if (getRotation() == 0) {
drawFastRawVLine(x, y, h, color);
drawFastVLineRaw(x, y, h, color);
} else if (getRotation() == 1) {
int16_t t = x;
x = WIDTH - 1 - y;
y = t;
x -= h - 1;
drawFastRawHLine(x, y, h, color);
drawFastHLineRaw(x, y, h, color);
} else if (getRotation() == 2) {
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
y -= h - 1;
drawFastRawVLine(x, y, h, color);
drawFastVLineRaw(x, y, h, color);
} else if (getRotation() == 3) {
int16_t t = x;
x = y;
y = HEIGHT - 1 - t;
drawFastRawHLine(x, y, h, color);
drawFastHLineRaw(x, y, h, color);
}
}
@@ -227,24 +229,24 @@ void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w,
}
if (getRotation() == 0) {
drawFastRawHLine(x, y, w, color);
drawFastHLineRaw(x, y, w, color);
} else if (getRotation() == 1) {
int16_t t = x;
x = WIDTH - 1 - y;
y = t;
drawFastRawVLine(x, y, w, color);
drawFastVLineRaw(x, y, w, color);
} else if (getRotation() == 2) {
x = WIDTH - 1 - x;
y = HEIGHT - 1 - y;
x -= w - 1;
drawFastRawHLine(x, y, w, color);
drawFastHLineRaw(x, y, w, color);
} else if (getRotation() == 3) {
int16_t t = x;
x = y;
y = HEIGHT - 1 - t;
y -= w - 1;
drawFastRawVLine(x, y, w, color);
drawFastVLineRaw(x, y, w, color);
}
}
@@ -258,10 +260,10 @@ void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w,
used.
*/
/**************************************************************************/
void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
void GFXcanvas8::drawFastVLineRaw(int16_t x, int16_t y, int16_t h,
uint16_t color) {
// x & y already in raw (rotation 0) coordinates, no need to transform.
uint8_t *buffer_ptr = buffer + y * WIDTH + x;
uint8_t *buffer_ptr = &pixbuf[y * WIDTH + x];
for (int16_t i = 0; i < h; i++) {
(*buffer_ptr) = color;
buffer_ptr += WIDTH;
@@ -278,8 +280,8 @@ void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
used.
*/
/**************************************************************************/
void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
void GFXcanvas8::drawFastHLineRaw(int16_t x, int16_t y, int16_t w,
uint16_t color) {
// x & y already in raw (rotation 0) coordinates, no need to transform.
memset(buffer + y * WIDTH + x, color, w);
memset(pixbuf + y * WIDTH + x, color, w);
}
+11 -15
View File
@@ -18,29 +18,25 @@
#include "Adafruit_GFX.h"
/// A GFX 8-bit canvas context for graphics
// An 8-bit canvas for offscreen graphics in RAM.
class GFXcanvas8 : public Adafruit_GFX {
public:
GFXcanvas8(uint16_t w, uint16_t h);
~GFXcanvas8(void);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void fillScreen(uint16_t color);
uint8_t getPixel(int16_t x, int16_t y) const;
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
uint8_t getPixel(int16_t x, int16_t y) const;
/**********************************************************************/
void fillScreen(uint16_t color);
/*!
@brief Get a pointer to the internal buffer memory
@returns A pointer to the allocated buffer
@brief Get pointer to internal canvas memory.
@return Pointer (uint8_t *) to start of canvas buffer.
*/
/**********************************************************************/
uint8_t *getBuffer(void) const { return buffer; }
uint8_t *getBuffer(void) const { return pixbuf; };
protected:
uint8_t getRawPixel(int16_t x, int16_t y) const;
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
private:
uint8_t *buffer;
uint8_t *pixbuf = NULL;
void drawPixelRaw(int16_t x, int16_t y, uint16_t color);
uint8_t getPixelRaw(int16_t x, int16_t y) const;
void drawFastVLineRaw(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLineRaw(int16_t x, int16_t y, int16_t w, uint16_t color);
};