Skip to content

Commit 9cb1ec4

Browse files
Bitmap fixes, initial canvas support
1 parent fb9e169 commit 9cb1ec4

File tree

3 files changed

+185
-16
lines changed

3 files changed

+185
-16
lines changed

Adafruit_GFX.cpp

Lines changed: 162 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ POSSIBILITY OF SUCH DAMAGE.
4646
#define min(a,b) (((a) < (b)) ? (a) : (b))
4747
#endif
4848

49+
// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
50+
static const uint8_t PROGMEM
51+
GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
52+
GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE };
53+
4954
Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
5055
WIDTH(w), HEIGHT(h)
5156
{
@@ -354,64 +359,82 @@ void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
354359
}
355360
}
356361

362+
// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
363+
// provided bitmap buffer (must be PROGMEM memory) using the specified
364+
// foreground color (unset bits are transparent).
357365
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
358366
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
359367

360368
int16_t i, j, byteWidth = (w + 7) / 8;
369+
uint8_t bitnum, byte;
361370

362371
for(j=0; j<h; j++) {
363-
for(i=0; i<w; i++ ) {
364-
if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
372+
for(i=0; i<w; i++) {
373+
bitnum = i & 7;
374+
if(!bitnum) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
375+
if(byte & pgm_read_byte(&GFXsetBit[bitnum])) {
365376
drawPixel(x+i, y+j, color);
366377
}
367378
}
368379
}
369380
}
370381

371-
// Draw a 1-bit color bitmap at the specified x, y position from the
372-
// provided bitmap buffer (must be PROGMEM memory) using color as the
373-
// foreground color and bg as the background color.
382+
// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
383+
// provided bitmap buffer (must be PROGMEM memory) using the specified
384+
// foreground (for set bits) and background (for clear bits) colors.
374385
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
375386
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
376387

377388
int16_t i, j, byteWidth = (w + 7) / 8;
389+
uint8_t bitnum, byte;
378390

379391
for(j=0; j<h; j++) {
380392
for(i=0; i<w; i++ ) {
381-
if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
393+
bitnum = i & 7;
394+
if(!bitnum) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
395+
if(byte & pgm_read_byte(&GFXsetBit[bitnum])) {
382396
drawPixel(x+i, y+j, color);
383-
}
384-
else {
397+
} else {
385398
drawPixel(x+i, y+j, bg);
386399
}
387400
}
388401
}
389402
}
390403

404+
// drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps.
391405
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
392406
uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
393407

394408
int16_t i, j, byteWidth = (w + 7) / 8;
409+
uint8_t bitnum, byte;
395410

396411
for(j=0; j<h; j++) {
397412
for(i=0; i<w; i++ ) {
398-
if(bitRead(bitmap[j], 7-i)) drawPixel(x+i, y+j, color);
413+
bitnum = i & 7;
414+
if(!bitnum) byte = bitmap[j * byteWidth + i / 8];
415+
if(byte & pgm_read_byte(&GFXsetBit[bitnum])) {
416+
drawPixel(x+i, y+j, color);
417+
}
399418
}
400419
}
401420
}
402421

403-
// Draw a 1-bit color bitmap at the specified x, y position from the
404-
// provided bitmap buffer (NOT PROGMEM memory nor a const) using color
405-
// as the foreground color and bg as the background color.
422+
// drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps.
406423
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
407424
uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
408425

409426
int16_t i, j, byteWidth = (w + 7) / 8;
427+
uint8_t bitnum, byte;
410428

411429
for(j=0; j<h; j++) {
412430
for(i=0; i<w; i++ ) {
413-
if(bitRead(bitmap[j], 7-i)) drawPixel(x+i, y+j, color);
414-
else drawPixel(x+i, y+j, bg);
431+
bitnum = i & 7;
432+
if(!bitnum) byte = bitmap[j * byteWidth + i / 8];
433+
if(byte & pgm_read_byte(&GFXsetBit[bitnum])) {
434+
drawPixel(x+i, y+j, color);
435+
} else {
436+
drawPixel(x+i, y+j, bg);
437+
}
415438
}
416439
}
417440
}
@@ -423,10 +446,13 @@ void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
423446
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
424447

425448
int16_t i, j, byteWidth = (w + 7) / 8;
449+
uint8_t bitnum, byte;
426450

427451
for(j=0; j<h; j++) {
428452
for(i=0; i<w; i++ ) {
429-
if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i % 8))) {
453+
bitnum = i & 7;
454+
if(!bitnum) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
455+
if(byte & pgm_read_byte(&GFXsetBit[7-bitnum])) {
430456
drawPixel(x+i, y+j, color);
431457
}
432458
}
@@ -909,3 +935,124 @@ void Adafruit_GFX_Button::press(boolean p) {
909935
boolean Adafruit_GFX_Button::isPressed() { return currstate; }
910936
boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }
911937
boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
938+
939+
// -------------------------------------------------------------------------
940+
941+
// GFXcanvas1 and GFXcanvas16 (currently a WIP, don't get too comfy with the
942+
// implementation) provide 1- and 16-bit offscreen canvases, the address of
943+
// which can be passed to drawBitmap() or pushColors() (the latter appears
944+
// to only be in Adafruit_TFTLCD at this time). This is here mostly to
945+
// help with the recently-added proportionally-spaced fonts; adds a way to
946+
// refresh a section of the screen without a massive flickering clear-and-
947+
// redraw...but maybe you'll find other uses too. VERY RAM-intensive, since
948+
// the buffer is in MCU memory and not the display driver...GXFcanvas1 might
949+
// be minimally useful on an Uno-class board, but this and GFXcanvas16 are
950+
// much more likely to require at least a Mega or various recent ARM-type
951+
// boards (recomment, as the text+bitmap draw can be pokey). GFXcanvas1
952+
// requires 1 bit per pixel (rounded up to nearest byte per scanline),
953+
// GFXcanvas16 requires 2 bytes per pixel (no scanline pad).
954+
// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
955+
956+
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
957+
uint16_t bytes = ((w + 7) / 8) * h;
958+
if((buffer = (uint8_t *)malloc(bytes))) {
959+
memset(buffer, 0, bytes);
960+
}
961+
}
962+
963+
GFXcanvas1::~GFXcanvas1(void) {
964+
if(buffer) free(buffer);
965+
}
966+
967+
uint8_t* GFXcanvas1::getBuffer(void) {
968+
return buffer;
969+
}
970+
971+
void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
972+
if(buffer) {
973+
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
974+
975+
int16_t t;
976+
switch(rotation) {
977+
case 1:
978+
t = x;
979+
x = WIDTH - 1 - y;
980+
y = t;
981+
break;
982+
case 2:
983+
x = WIDTH - 1 - x;
984+
y = HEIGHT - 1 - y;
985+
break;
986+
case 3:
987+
t = x;
988+
x = y;
989+
y = HEIGHT - 1 - t;
990+
break;
991+
}
992+
993+
uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
994+
if(color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
995+
else *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
996+
}
997+
}
998+
999+
void GFXcanvas1::fillScreen(uint16_t color) {
1000+
if(buffer) {
1001+
uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
1002+
memset(buffer, color ? 0xFF : 0x00, bytes);
1003+
}
1004+
}
1005+
1006+
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
1007+
uint16_t bytes = w * h * 2;
1008+
if((buffer = (uint16_t *)malloc(bytes))) {
1009+
memset(buffer, 0, bytes);
1010+
}
1011+
}
1012+
1013+
GFXcanvas16::~GFXcanvas16(void) {
1014+
if(buffer) free(buffer);
1015+
}
1016+
1017+
uint16_t* GFXcanvas16::getBuffer(void) {
1018+
return buffer;
1019+
}
1020+
1021+
void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
1022+
if(buffer) {
1023+
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
1024+
1025+
int16_t t;
1026+
switch(rotation) {
1027+
case 1:
1028+
t = x;
1029+
x = WIDTH - 1 - y;
1030+
y = t;
1031+
break;
1032+
case 2:
1033+
x = WIDTH - 1 - x;
1034+
y = HEIGHT - 1 - y;
1035+
break;
1036+
case 3:
1037+
t = x;
1038+
x = y;
1039+
y = HEIGHT - 1 - t;
1040+
break;
1041+
}
1042+
1043+
buffer[x + y * WIDTH] = color;
1044+
}
1045+
}
1046+
1047+
void GFXcanvas16::fillScreen(uint16_t color) {
1048+
if(buffer) {
1049+
uint8_t hi = color >> 8, lo = color & 0xFF;
1050+
if(hi == lo) {
1051+
memset(buffer, lo, WIDTH * HEIGHT * 2);
1052+
} else {
1053+
uint16_t i, pixels = WIDTH * HEIGHT;
1054+
for(i=0; i<pixels; i++) buffer[i] = color;
1055+
}
1056+
}
1057+
}
1058+

Adafruit_GFX.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,26 @@ class Adafruit_GFX_Button {
136136
boolean currstate, laststate;
137137
};
138138

139+
class GFXcanvas1 : public Adafruit_GFX {
140+
141+
public:
142+
GFXcanvas1(uint16_t w, uint16_t h);
143+
~GFXcanvas1(void);
144+
void drawPixel(int16_t x, int16_t y, uint16_t color),
145+
fillScreen(uint16_t color);
146+
uint8_t *getBuffer(void);
147+
private:
148+
uint8_t *buffer;
149+
};
150+
151+
class GFXcanvas16 : public Adafruit_GFX {
152+
GFXcanvas16(uint16_t w, uint16_t h);
153+
~GFXcanvas16(void);
154+
void drawPixel(int16_t x, int16_t y, uint16_t color),
155+
fillScreen(uint16_t color);
156+
uint16_t *getBuffer(void);
157+
private:
158+
uint16_t *buffer;
159+
};
160+
139161
#endif // _ADAFRUIT_GFX_H

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Adafruit GFX Library
2-
version=1.1.1
2+
version=1.1.2
33
author=Adafruit
44
maintainer=Adafruit <[email protected]>
55
sentence=Adafruit GFX graphics core library, this is the 'core' class that all our other graphics libraries derive from.

0 commit comments

Comments
 (0)