Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Adafruit_GFX.cpp
00001 /* 00002 This is the core graphics library for all our displays, providing a common 00003 set of graphics primitives (points, lines, circles, etc.). It needs to be 00004 paired with a hardware-specific library for each display device we carry 00005 (to handle the lower-level functions). 00006 00007 Adafruit invests time and resources providing this open source code, please 00008 support Adafruit & open-source hardware by purchasing products from Adafruit! 00009 00010 Copyright (c) 2013 Adafruit Industries. All rights reserved. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 00015 - Redistributions of source code must retain the above copyright notice, 00016 this list of conditions and the following disclaimer. 00017 - Redistributions in binary form must reproduce the above copyright notice, 00018 this list of conditions and the following disclaimer in the documentation 00019 and/or other materials provided with the distribution. 00020 00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00022 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00023 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00024 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00025 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00026 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00027 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00030 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00031 POSSIBILITY OF SUCH DAMAGE. 00032 */ 00033 00034 #include "Adafruit_GFX.h" 00035 #include "glcdfont.c" 00036 #ifdef __AVR__ 00037 #include <avr/pgmspace.h> 00038 #elif defined(ESP8266) || defined(ESP32) 00039 #include <pgmspace.h> 00040 #endif 00041 00042 // Many (but maybe not all) non-AVR board installs define macros 00043 // for compatibility with existing PROGMEM-reading AVR code. 00044 // Do our own checks and defines here for good measure... 00045 00046 #ifndef pgm_read_byte 00047 #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 00048 #endif 00049 #ifndef pgm_read_word 00050 #define pgm_read_word(addr) (*(const unsigned short *)(addr)) 00051 #endif 00052 #ifndef pgm_read_dword 00053 #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) 00054 #endif 00055 00056 // Pointers are a peculiar case...typically 16-bit on AVR boards, 00057 // 32 bits elsewhere. Try to accommodate both... 00058 00059 #if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF) 00060 #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) 00061 #else 00062 #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) 00063 #endif 00064 00065 #ifndef min 00066 #define min(a,b) (((a) < (b)) ? (a) : (b)) 00067 #endif 00068 00069 #ifndef _swap_int16_t 00070 #define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } 00071 #endif 00072 00073 Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): 00074 WIDTH(w), HEIGHT(h) 00075 { 00076 _width = WIDTH; 00077 _height = HEIGHT; 00078 rotation = 0; 00079 cursor_y = cursor_x = 0; 00080 textsize = 1; 00081 textcolor = textbgcolor = 0xFFFF; 00082 wrap = true; 00083 _cp437 = false; 00084 gfxFont = NULL; 00085 } 00086 00087 // Bresenham's algorithm - thx wikpedia 00088 void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 00089 uint16_t color) { 00090 int16_t steep = abs(y1 - y0) > abs(x1 - x0); 00091 if (steep) { 00092 _swap_int16_t(x0, y0); 00093 _swap_int16_t(x1, y1); 00094 } 00095 00096 if (x0 > x1) { 00097 _swap_int16_t(x0, x1); 00098 _swap_int16_t(y0, y1); 00099 } 00100 00101 int16_t dx, dy; 00102 dx = x1 - x0; 00103 dy = abs(y1 - y0); 00104 00105 int16_t err = dx / 2; 00106 int16_t ystep; 00107 00108 if (y0 < y1) { 00109 ystep = 1; 00110 } else { 00111 ystep = -1; 00112 } 00113 00114 for (; x0<=x1; x0++) { 00115 if (steep) { 00116 writePixel(y0, x0, color); 00117 } else { 00118 writePixel(x0, y0, color); 00119 } 00120 err -= dy; 00121 if (err < 0) { 00122 y0 += ystep; 00123 err += dx; 00124 } 00125 } 00126 } 00127 00128 void Adafruit_GFX::startWrite(){ 00129 // Overwrite in subclasses if desired! 00130 } 00131 00132 void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color){ 00133 // Overwrite in subclasses if startWrite is defined! 00134 drawPixel(x, y, color); 00135 } 00136 00137 // (x,y) is topmost point; if unsure, calling function 00138 // should sort endpoints or call writeLine() instead 00139 void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y, 00140 int16_t h, uint16_t color) { 00141 // Overwrite in subclasses if startWrite is defined! 00142 // Can be just writeLine(x, y, x, y+h-1, color); 00143 // or writeFillRect(x, y, 1, h, color); 00144 drawFastVLine(x, y, h, color); 00145 } 00146 00147 // (x,y) is leftmost point; if unsure, calling function 00148 // should sort endpoints or call writeLine() instead 00149 void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y, 00150 int16_t w, uint16_t color) { 00151 // Overwrite in subclasses if startWrite is defined! 00152 // Example: writeLine(x, y, x+w-1, y, color); 00153 // or writeFillRect(x, y, w, 1, color); 00154 drawFastHLine(x, y, w, color); 00155 } 00156 00157 void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, 00158 uint16_t color) { 00159 // Overwrite in subclasses if desired! 00160 fillRect(x,y,w,h,color); 00161 } 00162 00163 void Adafruit_GFX::endWrite(){ 00164 // Overwrite in subclasses if startWrite is defined! 00165 } 00166 00167 // (x,y) is topmost point; if unsure, calling function 00168 // should sort endpoints or call drawLine() instead 00169 void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, 00170 int16_t h, uint16_t color) { 00171 // Update in subclasses if desired! 00172 startWrite(); 00173 writeLine(x, y, x, y+h-1, color); 00174 endWrite(); 00175 } 00176 00177 // (x,y) is leftmost point; if unsure, calling function 00178 // should sort endpoints or call drawLine() instead 00179 void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, 00180 int16_t w, uint16_t color) { 00181 // Update in subclasses if desired! 00182 startWrite(); 00183 writeLine(x, y, x+w-1, y, color); 00184 endWrite(); 00185 } 00186 00187 void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 00188 uint16_t color) { 00189 // Update in subclasses if desired! 00190 startWrite(); 00191 for (int16_t i=x; i<x+w; i++) { 00192 writeFastVLine(i, y, h, color); 00193 } 00194 endWrite(); 00195 } 00196 00197 void Adafruit_GFX::fillScreen(uint16_t color) { 00198 // Update in subclasses if desired! 00199 fillRect(0, 0, _width, _height, color); 00200 } 00201 00202 void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 00203 uint16_t color) { 00204 // Update in subclasses if desired! 00205 if(x0 == x1){ 00206 if(y0 > y1) _swap_int16_t(y0, y1); 00207 drawFastVLine(x0, y0, y1 - y0 + 1, color); 00208 } else if(y0 == y1){ 00209 if(x0 > x1) _swap_int16_t(x0, x1); 00210 drawFastHLine(x0, y0, x1 - x0 + 1, color); 00211 } else { 00212 startWrite(); 00213 writeLine(x0, y0, x1, y1, color); 00214 endWrite(); 00215 } 00216 } 00217 00218 // Draw a circle outline 00219 void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, 00220 uint16_t color) { 00221 int16_t f = 1 - r; 00222 int16_t ddF_x = 1; 00223 int16_t ddF_y = -2 * r; 00224 int16_t x = 0; 00225 int16_t y = r; 00226 00227 startWrite(); 00228 writePixel(x0 , y0+r, color); 00229 writePixel(x0 , y0-r, color); 00230 writePixel(x0+r, y0 , color); 00231 writePixel(x0-r, y0 , color); 00232 00233 while (x<y) { 00234 if (f >= 0) { 00235 y--; 00236 ddF_y += 2; 00237 f += ddF_y; 00238 } 00239 x++; 00240 ddF_x += 2; 00241 f += ddF_x; 00242 00243 writePixel(x0 + x, y0 + y, color); 00244 writePixel(x0 - x, y0 + y, color); 00245 writePixel(x0 + x, y0 - y, color); 00246 writePixel(x0 - x, y0 - y, color); 00247 writePixel(x0 + y, y0 + x, color); 00248 writePixel(x0 - y, y0 + x, color); 00249 writePixel(x0 + y, y0 - x, color); 00250 writePixel(x0 - y, y0 - x, color); 00251 } 00252 endWrite(); 00253 } 00254 00255 void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, 00256 int16_t r, uint8_t cornername, uint16_t color) { 00257 int16_t f = 1 - r; 00258 int16_t ddF_x = 1; 00259 int16_t ddF_y = -2 * r; 00260 int16_t x = 0; 00261 int16_t y = r; 00262 00263 while (x<y) { 00264 if (f >= 0) { 00265 y--; 00266 ddF_y += 2; 00267 f += ddF_y; 00268 } 00269 x++; 00270 ddF_x += 2; 00271 f += ddF_x; 00272 if (cornername & 0x4) { 00273 writePixel(x0 + x, y0 + y, color); 00274 writePixel(x0 + y, y0 + x, color); 00275 } 00276 if (cornername & 0x2) { 00277 writePixel(x0 + x, y0 - y, color); 00278 writePixel(x0 + y, y0 - x, color); 00279 } 00280 if (cornername & 0x8) { 00281 writePixel(x0 - y, y0 + x, color); 00282 writePixel(x0 - x, y0 + y, color); 00283 } 00284 if (cornername & 0x1) { 00285 writePixel(x0 - y, y0 - x, color); 00286 writePixel(x0 - x, y0 - y, color); 00287 } 00288 } 00289 } 00290 00291 void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, 00292 uint16_t color) { 00293 startWrite(); 00294 writeFastVLine(x0, y0-r, 2*r+1, color); 00295 fillCircleHelper(x0, y0, r, 3, 0, color); 00296 endWrite(); 00297 } 00298 00299 // Used to do circles and roundrects 00300 void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, 00301 uint8_t cornername, int16_t delta, uint16_t color) { 00302 00303 int16_t f = 1 - r; 00304 int16_t ddF_x = 1; 00305 int16_t ddF_y = -2 * r; 00306 int16_t x = 0; 00307 int16_t y = r; 00308 00309 while (x<y) { 00310 if (f >= 0) { 00311 y--; 00312 ddF_y += 2; 00313 f += ddF_y; 00314 } 00315 x++; 00316 ddF_x += 2; 00317 f += ddF_x; 00318 00319 if (cornername & 0x1) { 00320 writeFastVLine(x0+x, y0-y, 2*y+1+delta, color); 00321 writeFastVLine(x0+y, y0-x, 2*x+1+delta, color); 00322 } 00323 if (cornername & 0x2) { 00324 writeFastVLine(x0-x, y0-y, 2*y+1+delta, color); 00325 writeFastVLine(x0-y, y0-x, 2*x+1+delta, color); 00326 } 00327 } 00328 } 00329 00330 // Draw a rectangle 00331 void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, 00332 uint16_t color) { 00333 startWrite(); 00334 writeFastHLine(x, y, w, color); 00335 writeFastHLine(x, y+h-1, w, color); 00336 writeFastVLine(x, y, h, color); 00337 writeFastVLine(x+w-1, y, h, color); 00338 endWrite(); 00339 } 00340 00341 // Draw a rounded rectangle 00342 void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, 00343 int16_t h, int16_t r, uint16_t color) { 00344 // smarter version 00345 startWrite(); 00346 writeFastHLine(x+r , y , w-2*r, color); // Top 00347 writeFastHLine(x+r , y+h-1, w-2*r, color); // Bottom 00348 writeFastVLine(x , y+r , h-2*r, color); // Left 00349 writeFastVLine(x+w-1, y+r , h-2*r, color); // Right 00350 // draw four corners 00351 drawCircleHelper(x+r , y+r , r, 1, color); 00352 drawCircleHelper(x+w-r-1, y+r , r, 2, color); 00353 drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color); 00354 drawCircleHelper(x+r , y+h-r-1, r, 8, color); 00355 endWrite(); 00356 } 00357 00358 // Fill a rounded rectangle 00359 void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, 00360 int16_t h, int16_t r, uint16_t color) { 00361 // smarter version 00362 startWrite(); 00363 writeFillRect(x+r, y, w-2*r, h, color); 00364 00365 // draw four corners 00366 fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color); 00367 fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color); 00368 endWrite(); 00369 } 00370 00371 // Draw a triangle 00372 void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0, 00373 int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) { 00374 drawLine(x0, y0, x1, y1, color); 00375 drawLine(x1, y1, x2, y2, color); 00376 drawLine(x2, y2, x0, y0, color); 00377 } 00378 00379 // Fill a triangle 00380 void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0, 00381 int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) { 00382 00383 int16_t a, b, y, last; 00384 00385 // Sort coordinates by Y order (y2 >= y1 >= y0) 00386 if (y0 > y1) { 00387 _swap_int16_t(y0, y1); _swap_int16_t(x0, x1); 00388 } 00389 if (y1 > y2) { 00390 _swap_int16_t(y2, y1); _swap_int16_t(x2, x1); 00391 } 00392 if (y0 > y1) { 00393 _swap_int16_t(y0, y1); _swap_int16_t(x0, x1); 00394 } 00395 00396 startWrite(); 00397 if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing 00398 a = b = x0; 00399 if(x1 < a) a = x1; 00400 else if(x1 > b) b = x1; 00401 if(x2 < a) a = x2; 00402 else if(x2 > b) b = x2; 00403 writeFastHLine(a, y0, b-a+1, color); 00404 endWrite(); 00405 return; 00406 } 00407 00408 int16_t 00409 dx01 = x1 - x0, 00410 dy01 = y1 - y0, 00411 dx02 = x2 - x0, 00412 dy02 = y2 - y0, 00413 dx12 = x2 - x1, 00414 dy12 = y2 - y1; 00415 int32_t 00416 sa = 0, 00417 sb = 0; 00418 00419 // For upper part of triangle, find scanline crossings for segments 00420 // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 00421 // is included here (and second loop will be skipped, avoiding a /0 00422 // error there), otherwise scanline y1 is skipped here and handled 00423 // in the second loop...which also avoids a /0 error here if y0=y1 00424 // (flat-topped triangle). 00425 if(y1 == y2) last = y1; // Include y1 scanline 00426 else last = y1-1; // Skip it 00427 00428 for(y=y0; y<=last; y++) { 00429 a = x0 + sa / dy01; 00430 b = x0 + sb / dy02; 00431 sa += dx01; 00432 sb += dx02; 00433 /* longhand: 00434 a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); 00435 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 00436 */ 00437 if(a > b) _swap_int16_t(a,b); 00438 writeFastHLine(a, y, b-a+1, color); 00439 } 00440 00441 // For lower part of triangle, find scanline crossings for segments 00442 // 0-2 and 1-2. This loop is skipped if y1=y2. 00443 sa = dx12 * (y - y1); 00444 sb = dx02 * (y - y0); 00445 for(; y<=y2; y++) { 00446 a = x1 + sa / dy12; 00447 b = x0 + sb / dy02; 00448 sa += dx12; 00449 sb += dx02; 00450 /* longhand: 00451 a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); 00452 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 00453 */ 00454 if(a > b) _swap_int16_t(a,b); 00455 writeFastHLine(a, y, b-a+1, color); 00456 } 00457 endWrite(); 00458 } 00459 00460 // BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS --------------------- 00461 00462 // Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, 00463 // using the specified foreground color (unset bits are transparent). 00464 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 00465 const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) { 00466 00467 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 00468 uint8_t byte = 0; 00469 00470 startWrite(); 00471 for(int16_t j=0; j<h; j++, y++) { 00472 for(int16_t i=0; i<w; i++) { 00473 if(i & 7) byte <<= 1; 00474 else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); 00475 if(byte & 0x80) writePixel(x+i, y, color); 00476 } 00477 } 00478 endWrite(); 00479 } 00480 00481 // Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, 00482 // using the specified foreground (for set bits) and background (unset 00483 // bits) colors. 00484 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 00485 const uint8_t bitmap[], int16_t w, int16_t h, 00486 uint16_t color, uint16_t bg) { 00487 00488 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 00489 uint8_t byte = 0; 00490 00491 startWrite(); 00492 for(int16_t j=0; j<h; j++, y++) { 00493 for(int16_t i=0; i<w; i++ ) { 00494 if(i & 7) byte <<= 1; 00495 else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); 00496 writePixel(x+i, y, (byte & 0x80) ? color : bg); 00497 } 00498 } 00499 endWrite(); 00500 } 00501 00502 // Draw a RAM-resident 1-bit image at the specified (x,y) position, 00503 // using the specified foreground color (unset bits are transparent). 00504 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 00505 uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) { 00506 00507 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 00508 uint8_t byte = 0; 00509 00510 startWrite(); 00511 for(int16_t j=0; j<h; j++, y++) { 00512 for(int16_t i=0; i<w; i++ ) { 00513 if(i & 7) byte <<= 1; 00514 else byte = bitmap[j * byteWidth + i / 8]; 00515 if(byte & 0x80) writePixel(x+i, y, color); 00516 } 00517 } 00518 endWrite(); 00519 } 00520 00521 // Draw a RAM-resident 1-bit image at the specified (x,y) position, 00522 // using the specified foreground (for set bits) and background (unset 00523 // bits) colors. 00524 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 00525 uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) { 00526 00527 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 00528 uint8_t byte = 0; 00529 00530 startWrite(); 00531 for(int16_t j=0; j<h; j++, y++) { 00532 for(int16_t i=0; i<w; i++ ) { 00533 if(i & 7) byte <<= 1; 00534 else byte = bitmap[j * byteWidth + i / 8]; 00535 writePixel(x+i, y, (byte & 0x80) ? color : bg); 00536 } 00537 } 00538 endWrite(); 00539 } 00540 00541 // Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP, 00542 // Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. 00543 // C Array can be directly used with this function. 00544 // There is no RAM-resident version of this function; if generating bitmaps 00545 // in RAM, use the format defined by drawBitmap() and call that instead. 00546 void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, 00547 const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) { 00548 00549 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 00550 uint8_t byte = 0; 00551 00552 startWrite(); 00553 for(int16_t j=0; j<h; j++, y++) { 00554 for(int16_t i=0; i<w; i++ ) { 00555 if(i & 7) byte >>= 1; 00556 else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); 00557 // Nearly identical to drawBitmap(), only the bit order 00558 // is reversed here (left-to-right = LSB to MSB): 00559 if(byte & 0x01) writePixel(x+i, y, color); 00560 } 00561 } 00562 endWrite(); 00563 } 00564 00565 // Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) 00566 // pos. Specifically for 8-bit display devices such as IS31FL3731; 00567 // no color reduction/expansion is performed. 00568 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 00569 const uint8_t bitmap[], int16_t w, int16_t h) { 00570 startWrite(); 00571 for(int16_t j=0; j<h; j++, y++) { 00572 for(int16_t i=0; i<w; i++ ) { 00573 writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i])); 00574 } 00575 } 00576 endWrite(); 00577 } 00578 00579 // Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) 00580 // pos. Specifically for 8-bit display devices such as IS31FL3731; 00581 // no color reduction/expansion is performed. 00582 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 00583 uint8_t *bitmap, int16_t w, int16_t h) { 00584 startWrite(); 00585 for(int16_t j=0; j<h; j++, y++) { 00586 for(int16_t i=0; i<w; i++ ) { 00587 writePixel(x+i, y, bitmap[j * w + i]); 00588 } 00589 } 00590 endWrite(); 00591 } 00592 00593 // Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask 00594 // (set bits = opaque, unset bits = clear) at the specified (x,y) position. 00595 // BOTH buffers (grayscale and mask) must be PROGMEM-resident. 00596 // Specifically for 8-bit display devices such as IS31FL3731; 00597 // no color reduction/expansion is performed. 00598 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 00599 const uint8_t bitmap[], const uint8_t mask[], 00600 int16_t w, int16_t h) { 00601 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 00602 uint8_t byte = 0; 00603 startWrite(); 00604 for(int16_t j=0; j<h; j++, y++) { 00605 for(int16_t i=0; i<w; i++ ) { 00606 if(i & 7) byte <<= 1; 00607 else byte = pgm_read_byte(&mask[j * bw + i / 8]); 00608 if(byte & 0x80) { 00609 writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i])); 00610 } 00611 } 00612 } 00613 endWrite(); 00614 } 00615 00616 // Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask 00617 // (set bits = opaque, unset bits = clear) at the specified (x,y) pos. 00618 // BOTH buffers (grayscale and mask) must be RAM-resident, no mix-and- 00619 // match. Specifically for 8-bit display devices such as IS31FL3731; 00620 // no color reduction/expansion is performed. 00621 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 00622 uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) { 00623 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 00624 uint8_t byte = 0; 00625 startWrite(); 00626 for(int16_t j=0; j<h; j++, y++) { 00627 for(int16_t i=0; i<w; i++ ) { 00628 if(i & 7) byte <<= 1; 00629 else byte = mask[j * bw + i / 8]; 00630 if(byte & 0x80) { 00631 writePixel(x+i, y, bitmap[j * w + i]); 00632 } 00633 } 00634 } 00635 endWrite(); 00636 } 00637 00638 // Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) 00639 // position. For 16-bit display devices; no color reduction performed. 00640 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, 00641 const uint16_t bitmap[], int16_t w, int16_t h) { 00642 startWrite(); 00643 for(int16_t j=0; j<h; j++, y++) { 00644 for(int16_t i=0; i<w; i++ ) { 00645 writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i])); 00646 } 00647 } 00648 endWrite(); 00649 } 00650 00651 // Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) 00652 // position. For 16-bit display devices; no color reduction performed. 00653 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, 00654 uint16_t *bitmap, int16_t w, int16_t h) { 00655 startWrite(); 00656 for(int16_t j=0; j<h; j++, y++) { 00657 for(int16_t i=0; i<w; i++ ) { 00658 writePixel(x+i, y, bitmap[j * w + i]); 00659 } 00660 } 00661 endWrite(); 00662 } 00663 00664 // Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask 00665 // (set bits = opaque, unset bits = clear) at the specified (x,y) position. 00666 // BOTH buffers (color and mask) must be PROGMEM-resident. 00667 // For 16-bit display devices; no color reduction performed. 00668 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, 00669 const uint16_t bitmap[], const uint8_t mask[], 00670 int16_t w, int16_t h) { 00671 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 00672 uint8_t byte = 0; 00673 startWrite(); 00674 for(int16_t j=0; j<h; j++, y++) { 00675 for(int16_t i=0; i<w; i++ ) { 00676 if(i & 7) byte <<= 1; 00677 else byte = pgm_read_byte(&mask[j * bw + i / 8]); 00678 if(byte & 0x80) { 00679 writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i])); 00680 } 00681 } 00682 } 00683 endWrite(); 00684 } 00685 00686 // Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask 00687 // (set bits = opaque, unset bits = clear) at the specified (x,y) pos. 00688 // BOTH buffers (color and mask) must be RAM-resident, no mix-and-match. 00689 // For 16-bit display devices; no color reduction performed. 00690 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, 00691 uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h) { 00692 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 00693 uint8_t byte = 0; 00694 startWrite(); 00695 for(int16_t j=0; j<h; j++, y++) { 00696 for(int16_t i=0; i<w; i++ ) { 00697 if(i & 7) byte <<= 1; 00698 else byte = mask[j * bw + i / 8]; 00699 if(byte & 0x80) { 00700 writePixel(x+i, y, bitmap[j * w + i]); 00701 } 00702 } 00703 } 00704 endWrite(); 00705 } 00706 00707 // TEXT- AND CHARACTER-HANDLING FUNCTIONS ---------------------------------- 00708 00709 // Draw a character 00710 void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, 00711 uint16_t color, uint16_t bg, uint8_t size) { 00712 00713 if(!gfxFont) { // 'Classic' built-in font 00714 00715 if((x >= _width) || // Clip right 00716 (y >= _height) || // Clip bottom 00717 ((x + 6 * size - 1) < 0) || // Clip left 00718 ((y + 8 * size - 1) < 0)) // Clip top 00719 return; 00720 00721 if(!_cp437 && (c >= 176)) c++; // Handle 'classic' charset behavior 00722 00723 startWrite(); 00724 for(int8_t i=0; i<5; i++ ) { // Char bitmap = 5 columns 00725 uint8_t line = pgm_read_byte(&font[c * 5 + i]); 00726 for(int8_t j=0; j<8; j++, line >>= 1) { 00727 if(line & 1) { 00728 if(size == 1) 00729 writePixel(x+i, y+j, color); 00730 else 00731 writeFillRect(x+i*size, y+j*size, size, size, color); 00732 } else if(bg != color) { 00733 if(size == 1) 00734 writePixel(x+i, y+j, bg); 00735 else 00736 writeFillRect(x+i*size, y+j*size, size, size, bg); 00737 } 00738 } 00739 } 00740 if(bg != color) { // If opaque, draw vertical line for last column 00741 if(size == 1) writeFastVLine(x+5, y, 8, bg); 00742 else writeFillRect(x+5*size, y, size, 8*size, bg); 00743 } 00744 endWrite(); 00745 00746 } else { // Custom font 00747 00748 // Character is assumed previously filtered by write() to eliminate 00749 // newlines, returns, non-printable characters, etc. Calling 00750 // drawChar() directly with 'bad' characters of font may cause mayhem! 00751 00752 c -= (uint8_t)pgm_read_byte(&gfxFont->first); 00753 GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); 00754 uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); 00755 00756 uint16_t bo = pgm_read_word(&glyph->bitmapOffset); 00757 uint8_t w = pgm_read_byte(&glyph->width), 00758 h = pgm_read_byte(&glyph->height); 00759 int8_t xo = pgm_read_byte(&glyph->xOffset), 00760 yo = pgm_read_byte(&glyph->yOffset); 00761 uint8_t xx, yy, bits = 0, bit = 0; 00762 int16_t xo16 = 0, yo16 = 0; 00763 00764 if(size > 1) { 00765 xo16 = xo; 00766 yo16 = yo; 00767 } 00768 00769 // Todo: Add character clipping here 00770 00771 // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS. 00772 // THIS IS ON PURPOSE AND BY DESIGN. The background color feature 00773 // has typically been used with the 'classic' font to overwrite old 00774 // screen contents with new data. This ONLY works because the 00775 // characters are a uniform size; it's not a sensible thing to do with 00776 // proportionally-spaced fonts with glyphs of varying sizes (and that 00777 // may overlap). To replace previously-drawn text when using a custom 00778 // font, use the getTextBounds() function to determine the smallest 00779 // rectangle encompassing a string, erase the area with fillRect(), 00780 // then draw new text. This WILL infortunately 'blink' the text, but 00781 // is unavoidable. Drawing 'background' pixels will NOT fix this, 00782 // only creates a new set of problems. Have an idea to work around 00783 // this (a canvas object type for MCUs that can afford the RAM and 00784 // displays supporting setAddrWindow() and pushColors()), but haven't 00785 // implemented this yet. 00786 00787 startWrite(); 00788 for(yy=0; yy<h; yy++) { 00789 for(xx=0; xx<w; xx++) { 00790 if(!(bit++ & 7)) { 00791 bits = pgm_read_byte(&bitmap[bo++]); 00792 } 00793 if(bits & 0x80) { 00794 if(size == 1) { 00795 writePixel(x+xo+xx, y+yo+yy, color); 00796 } else { 00797 writeFillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, 00798 size, size, color); 00799 } 00800 } 00801 bits <<= 1; 00802 } 00803 } 00804 endWrite(); 00805 00806 } // End classic vs custom font 00807 } 00808 00809 #if ARDUINO >= 100 00810 size_t Adafruit_GFX::write(uint8_t c) { 00811 #else 00812 void Adafruit_GFX::write(uint8_t c) { 00813 #endif 00814 if(!gfxFont) { // 'Classic' built-in font 00815 00816 if(c == '\n') { // Newline? 00817 cursor_x = 0; // Reset x to zero, 00818 cursor_y += textsize * 8; // advance y one line 00819 } else if(c != '\r') { // Ignore carriage returns 00820 if(wrap && ((cursor_x + textsize * 6) > _width)) { // Off right? 00821 cursor_x = 0; // Reset x to zero, 00822 cursor_y += textsize * 8; // advance y one line 00823 } 00824 drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); 00825 cursor_x += textsize * 6; // Advance x one char 00826 } 00827 00828 } else { // Custom font 00829 00830 if(c == '\n') { 00831 cursor_x = 0; 00832 cursor_y += (int16_t)textsize * 00833 (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 00834 } else if(c != '\r') { 00835 uint8_t first = pgm_read_byte(&gfxFont->first); 00836 if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { 00837 GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer( 00838 &gfxFont->glyph))[c - first]); 00839 uint8_t w = pgm_read_byte(&glyph->width), 00840 h = pgm_read_byte(&glyph->height); 00841 if((w > 0) && (h > 0)) { // Is there an associated bitmap? 00842 int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic 00843 if(wrap && ((cursor_x + textsize * (xo + w)) > _width)) { 00844 cursor_x = 0; 00845 cursor_y += (int16_t)textsize * 00846 (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 00847 } 00848 drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); 00849 } 00850 cursor_x += (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize; 00851 } 00852 } 00853 00854 } 00855 #if ARDUINO >= 100 00856 return 1; 00857 #endif 00858 } 00859 00860 void Adafruit_GFX::print(char* textPtr) { 00861 while(*textPtr != 0) write(*textPtr++); 00862 } 00863 00864 void Adafruit_GFX::setCursor(int16_t x, int16_t y) { 00865 cursor_x = x; 00866 cursor_y = y; 00867 } 00868 00869 int16_t Adafruit_GFX::getCursorX(void) const { 00870 return cursor_x; 00871 } 00872 00873 int16_t Adafruit_GFX::getCursorY(void) const { 00874 return cursor_y; 00875 } 00876 00877 void Adafruit_GFX::setTextSize(uint8_t s) { 00878 textsize = (s > 0) ? s : 1; 00879 } 00880 00881 void Adafruit_GFX::setTextColor(uint16_t c) { 00882 // For 'transparent' background, we'll set the bg 00883 // to the same as fg instead of using a flag 00884 textcolor = textbgcolor = c; 00885 } 00886 00887 void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { 00888 textcolor = c; 00889 textbgcolor = b; 00890 } 00891 00892 void Adafruit_GFX::setTextWrap(boolean w) { 00893 wrap = w; 00894 } 00895 00896 uint8_t Adafruit_GFX::getRotation(void) const { 00897 return rotation; 00898 } 00899 00900 void Adafruit_GFX::setRotation(uint8_t x) { 00901 rotation = (x & 3); 00902 switch(rotation) { 00903 case 0: 00904 case 2: 00905 _width = WIDTH; 00906 _height = HEIGHT; 00907 break; 00908 case 1: 00909 case 3: 00910 _width = HEIGHT; 00911 _height = WIDTH; 00912 break; 00913 } 00914 } 00915 00916 // Enable (or disable) Code Page 437-compatible charset. 00917 // There was an error in glcdfont.c for the longest time -- one character 00918 // (#176, the 'light shade' block) was missing -- this threw off the index 00919 // of every character that followed it. But a TON of code has been written 00920 // with the erroneous character indices. By default, the library uses the 00921 // original 'wrong' behavior and old sketches will still work. Pass 'true' 00922 // to this function to use correct CP437 character values in your code. 00923 void Adafruit_GFX::cp437(boolean x) { 00924 _cp437 = x; 00925 } 00926 00927 void Adafruit_GFX::setFont(const GFXfont *f) { 00928 if(f) { // Font struct pointer passed in? 00929 if(!gfxFont) { // And no current font struct? 00930 // Switching from classic to new font behavior. 00931 // Move cursor pos down 6 pixels so it's on baseline. 00932 cursor_y += 6; 00933 } 00934 } else if(gfxFont) { // NULL passed. Current font struct defined? 00935 // Switching from new to classic font behavior. 00936 // Move cursor pos up 6 pixels so it's at top-left of char. 00937 cursor_y -= 6; 00938 } 00939 gfxFont = (GFXfont *)f; 00940 } 00941 00942 // Broke this out as it's used by both the PROGMEM- and RAM-resident 00943 // getTextBounds() functions. 00944 void Adafruit_GFX::charBounds(char c, int16_t *x, int16_t *y, 00945 int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) { 00946 00947 if(gfxFont) { 00948 00949 if(c == '\n') { // Newline? 00950 *x = 0; // Reset x to zero, advance y by one line 00951 *y += textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 00952 } else if(c != '\r') { // Not a carriage return; is normal char 00953 uint8_t first = pgm_read_byte(&gfxFont->first), 00954 last = pgm_read_byte(&gfxFont->last); 00955 if((c >= first) && (c <= last)) { // Char present in this font? 00956 GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer( 00957 &gfxFont->glyph))[c - first]); 00958 uint8_t gw = pgm_read_byte(&glyph->width), 00959 gh = pgm_read_byte(&glyph->height), 00960 xa = pgm_read_byte(&glyph->xAdvance); 00961 int8_t xo = pgm_read_byte(&glyph->xOffset), 00962 yo = pgm_read_byte(&glyph->yOffset); 00963 if(wrap && ((*x+(((int16_t)xo+gw)*textsize)) > _width)) { 00964 *x = 0; // Reset x to zero, advance y by one line 00965 *y += textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 00966 } 00967 int16_t ts = (int16_t)textsize, 00968 x1 = *x + xo * ts, 00969 y1 = *y + yo * ts, 00970 x2 = x1 + gw * ts - 1, 00971 y2 = y1 + gh * ts - 1; 00972 if(x1 < *minx) *minx = x1; 00973 if(y1 < *miny) *miny = y1; 00974 if(x2 > *maxx) *maxx = x2; 00975 if(y2 > *maxy) *maxy = y2; 00976 *x += xa * ts; 00977 } 00978 } 00979 00980 } else { // Default font 00981 00982 if(c == '\n') { // Newline? 00983 *x = 0; // Reset x to zero, 00984 *y += textsize * 8; // advance y one line 00985 // min/max x/y unchaged -- that waits for next 'normal' character 00986 } else if(c != '\r') { // Normal char; ignore carriage returns 00987 if(wrap && ((*x + textsize * 6) > _width)) { // Off right? 00988 *x = 0; // Reset x to zero, 00989 *y += textsize * 8; // advance y one line 00990 } 00991 int x2 = *x + textsize * 6 - 1, // Lower-right pixel of char 00992 y2 = *y + textsize * 8 - 1; 00993 if(x2 > *maxx) *maxx = x2; // Track max x, y 00994 if(y2 > *maxy) *maxy = y2; 00995 if(*x < *minx) *minx = *x; // Track min x, y 00996 if(*y < *miny) *miny = *y; 00997 *x += textsize * 6; // Advance x one char 00998 } 00999 } 01000 } 01001 01002 // Pass string and a cursor position, returns UL corner and W,H. 01003 void Adafruit_GFX::getTextBounds(char *str, int16_t x, int16_t y, 01004 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { 01005 uint8_t c; // Current character 01006 01007 *x1 = x; 01008 *y1 = y; 01009 *w = *h = 0; 01010 01011 int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; 01012 01013 while((c = *str++)) 01014 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); 01015 01016 if(maxx >= minx) { 01017 *x1 = minx; 01018 *w = maxx - minx + 1; 01019 } 01020 if(maxy >= miny) { 01021 *y1 = miny; 01022 *h = maxy - miny + 1; 01023 } 01024 } 01025 01026 // Same as above, but for PROGMEM strings 01027 /*void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, 01028 int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { 01029 uint8_t *s = (uint8_t *)str, c; 01030 01031 *x1 = x; 01032 *y1 = y; 01033 *w = *h = 0; 01034 01035 int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; 01036 01037 while((c = pgm_read_byte(s++))) 01038 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); 01039 01040 if(maxx >= minx) { 01041 *x1 = minx; 01042 *w = maxx - minx + 1; 01043 } 01044 if(maxy >= miny) { 01045 *y1 = miny; 01046 *h = maxy - miny + 1; 01047 } 01048 }*/ 01049 01050 // Return the size of the display (per current rotation) 01051 int16_t Adafruit_GFX::width(void) const { 01052 return _width; 01053 } 01054 01055 int16_t Adafruit_GFX::height(void) const { 01056 return _height; 01057 } 01058 01059 void Adafruit_GFX::invertDisplay(boolean i) { 01060 // Do nothing, must be subclassed if supported by hardware 01061 } 01062 01063 /***************************************************************************/ 01064 // code for the GFX button UI element 01065 01066 Adafruit_GFX_Button::Adafruit_GFX_Button(void) { 01067 _gfx = 0; 01068 } 01069 01070 // Classic initButton() function: pass center & size 01071 void Adafruit_GFX_Button::initButton( 01072 Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h, 01073 uint16_t outline, uint16_t fill, uint16_t textcolor, 01074 char *label, uint8_t textsize) 01075 { 01076 // Tweak arguments and pass to the newer initButtonUL() function... 01077 initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, 01078 textcolor, label, textsize); 01079 } 01080 01081 // Newer function instead accepts upper-left corner & size 01082 void Adafruit_GFX_Button::initButtonUL( 01083 Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h, 01084 uint16_t outline, uint16_t fill, uint16_t textcolor, 01085 char *label, uint8_t textsize) 01086 { 01087 _x1 = x1; 01088 _y1 = y1; 01089 _w = w; 01090 _h = h; 01091 _outlinecolor = outline; 01092 _fillcolor = fill; 01093 _textcolor = textcolor; 01094 _textsize = textsize; 01095 _gfx = gfx; 01096 strncpy(_label, label, 9); 01097 } 01098 01099 void Adafruit_GFX_Button::drawButton(boolean inverted) { 01100 uint16_t fill, outline, text; 01101 01102 if(!inverted) { 01103 fill = _fillcolor; 01104 outline = _outlinecolor; 01105 text = _textcolor; 01106 } else { 01107 fill = _textcolor; 01108 outline = _outlinecolor; 01109 text = _fillcolor; 01110 } 01111 01112 uint8_t r = min(_w, _h) / 4; // Corner radius 01113 _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill); 01114 _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline); 01115 01116 _gfx->setCursor(_x1 + (_w/2) - (strlen(_label) * 3 * _textsize), 01117 _y1 + (_h/2) - (4 * _textsize)); 01118 _gfx->setTextColor(text); 01119 _gfx->setTextSize(_textsize); 01120 _gfx->print(_label); 01121 } 01122 01123 boolean Adafruit_GFX_Button::contains(int16_t x, int16_t y) { 01124 return ((x >= _x1) && (x < (_x1 + _w)) && 01125 (y >= _y1) && (y < (_y1 + _h))); 01126 } 01127 01128 void Adafruit_GFX_Button::press(boolean p) { 01129 laststate = currstate; 01130 currstate = p; 01131 } 01132 01133 boolean Adafruit_GFX_Button::isPressed() { return currstate; } 01134 boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); } 01135 boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); } 01136 01137 // ------------------------------------------------------------------------- 01138 01139 // GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too 01140 // comfy with the implementation) provide 1-, 8- and 16-bit offscreen 01141 // canvases, the address of which can be passed to drawBitmap() or 01142 // pushColors() (the latter appears only in a couple of GFX-subclassed TFT 01143 // libraries at this time). This is here mostly to help with the recently- 01144 // added proportionally-spaced fonts; adds a way to refresh a section of the 01145 // screen without a massive flickering clear-and-redraw...but maybe you'll 01146 // find other uses too. VERY RAM-intensive, since the buffer is in MCU 01147 // memory and not the display driver...GXFcanvas1 might be minimally useful 01148 // on an Uno-class board, but this and the others are much more likely to 01149 // require at least a Mega or various recent ARM-type boards (recommended, 01150 // as the text+bitmap draw can be pokey). GFXcanvas1 requires 1 bit per 01151 // pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte 01152 // per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no 01153 // scanline pad). 01154 // NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND. 01155 01156 GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { 01157 uint16_t bytes = ((w + 7) / 8) * h; 01158 if((buffer = (uint8_t *)malloc(bytes))) { 01159 memset(buffer, 0, bytes); 01160 } 01161 } 01162 01163 GFXcanvas1::~GFXcanvas1(void) { 01164 if(buffer) free(buffer); 01165 } 01166 01167 uint8_t* GFXcanvas1::getBuffer(void) { 01168 return buffer; 01169 } 01170 01171 void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) { 01172 #ifdef __AVR__ 01173 // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR 01174 static const uint8_t PROGMEM 01175 GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, 01176 GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE }; 01177 #endif 01178 01179 if(buffer) { 01180 if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return; 01181 01182 int16_t t; 01183 switch(rotation) { 01184 case 1: 01185 t = x; 01186 x = WIDTH - 1 - y; 01187 y = t; 01188 break; 01189 case 2: 01190 x = WIDTH - 1 - x; 01191 y = HEIGHT - 1 - y; 01192 break; 01193 case 3: 01194 t = x; 01195 x = y; 01196 y = HEIGHT - 1 - t; 01197 break; 01198 } 01199 01200 uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)]; 01201 #ifdef __AVR__ 01202 if(color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]); 01203 else *ptr &= pgm_read_byte(&GFXclrBit[x & 7]); 01204 #else 01205 if(color) *ptr |= 0x80 >> (x & 7); 01206 else *ptr &= ~(0x80 >> (x & 7)); 01207 #endif 01208 } 01209 } 01210 01211 void GFXcanvas1::fillScreen(uint16_t color) { 01212 if(buffer) { 01213 uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT; 01214 memset(buffer, color ? 0xFF : 0x00, bytes); 01215 } 01216 } 01217 01218 GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { 01219 uint32_t bytes = w * h; 01220 if((buffer = (uint8_t *)malloc(bytes))) { 01221 memset(buffer, 0, bytes); 01222 } 01223 } 01224 01225 GFXcanvas8::~GFXcanvas8(void) { 01226 if(buffer) free(buffer); 01227 } 01228 01229 uint8_t* GFXcanvas8::getBuffer(void) { 01230 return buffer; 01231 } 01232 01233 void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) { 01234 if(buffer) { 01235 if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return; 01236 01237 int16_t t; 01238 switch(rotation) { 01239 case 1: 01240 t = x; 01241 x = WIDTH - 1 - y; 01242 y = t; 01243 break; 01244 case 2: 01245 x = WIDTH - 1 - x; 01246 y = HEIGHT - 1 - y; 01247 break; 01248 case 3: 01249 t = x; 01250 x = y; 01251 y = HEIGHT - 1 - t; 01252 break; 01253 } 01254 01255 buffer[x + y * WIDTH] = color; 01256 } 01257 } 01258 01259 void GFXcanvas8::fillScreen(uint16_t color) { 01260 if(buffer) { 01261 memset(buffer, color, WIDTH * HEIGHT); 01262 } 01263 } 01264 01265 void GFXcanvas8::writeFastHLine(int16_t x, int16_t y, 01266 int16_t w, uint16_t color) { 01267 01268 if((x >= _width) || (y < 0) || (y >= _height)) return; 01269 int16_t x2 = x + w - 1; 01270 if(x2 < 0) return; 01271 01272 // Clip left/right 01273 if(x < 0) { 01274 x = 0; 01275 w = x2 + 1; 01276 } 01277 if(x2 >= _width) w = _width - x; 01278 01279 int16_t t; 01280 switch(rotation) { 01281 case 1: 01282 t = x; 01283 x = WIDTH - 1 - y; 01284 y = t; 01285 break; 01286 case 2: 01287 x = WIDTH - 1 - x; 01288 y = HEIGHT - 1 - y; 01289 break; 01290 case 3: 01291 t = x; 01292 x = y; 01293 y = HEIGHT - 1 - t; 01294 break; 01295 } 01296 01297 memset(buffer + y * WIDTH + x, color, w); 01298 } 01299 01300 GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { 01301 uint32_t bytes = w * h * 2; 01302 if((buffer = (uint16_t *)malloc(bytes))) { 01303 memset(buffer, 0, bytes); 01304 } 01305 } 01306 01307 GFXcanvas16::~GFXcanvas16(void) { 01308 if(buffer) free(buffer); 01309 } 01310 01311 uint16_t* GFXcanvas16::getBuffer(void) { 01312 return buffer; 01313 } 01314 01315 void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) { 01316 if(buffer) { 01317 if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return; 01318 01319 int16_t t; 01320 switch(rotation) { 01321 case 1: 01322 t = x; 01323 x = WIDTH - 1 - y; 01324 y = t; 01325 break; 01326 case 2: 01327 x = WIDTH - 1 - x; 01328 y = HEIGHT - 1 - y; 01329 break; 01330 case 3: 01331 t = x; 01332 x = y; 01333 y = HEIGHT - 1 - t; 01334 break; 01335 } 01336 01337 buffer[x + y * WIDTH] = color; 01338 } 01339 } 01340 01341 void GFXcanvas16::fillScreen(uint16_t color) { 01342 if(buffer) { 01343 uint8_t hi = color >> 8, lo = color & 0xFF; 01344 if(hi == lo) { 01345 memset(buffer, lo, WIDTH * HEIGHT * 2); 01346 } else { 01347 uint32_t i, pixels = WIDTH * HEIGHT; 01348 for(i=0; i<pixels; i++) buffer[i] = color; 01349 } 01350 } 01351 } 01352
Generated on Wed Jul 13 2022 06:22:19 by
1.7.2