Hatef Dabbaghian / Adafruit-GFX-Library
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_GFX.cpp Source File

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