arduinoprojects

git clone https://git.tarina.org/arduinoprojects
Log | Files | Refs

Adafruit_GFX.cpp (93575B)


      1 /*
      2 This is the core graphics library for all our displays, providing a common
      3 set of graphics primitives (points, lines, circles, etc.).  It needs to be
      4 paired with a hardware-specific library for each display device we carry
      5 (to handle the lower-level functions).
      6 
      7 Adafruit invests time and resources providing this open source code, please
      8 support Adafruit & open-source hardware by purchasing products from Adafruit!
      9 
     10 Copyright (c) 2013 Adafruit Industries.  All rights reserved.
     11 
     12 Redistribution and use in source and binary forms, with or without
     13 modification, are permitted provided that the following conditions are met:
     14 
     15 - Redistributions of source code must retain the above copyright notice,
     16   this list of conditions and the following disclaimer.
     17 - Redistributions in binary form must reproduce the above copyright notice,
     18   this list of conditions and the following disclaimer in the documentation
     19   and/or other materials provided with the distribution.
     20 
     21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31 POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include "Adafruit_GFX.h"
     35 #include "glcdfont.c"
     36 #ifdef __AVR__
     37 #include <avr/pgmspace.h>
     38 #elif defined(ESP8266) || defined(ESP32)
     39 #include <pgmspace.h>
     40 #endif
     41 
     42 // Many (but maybe not all) non-AVR board installs define macros
     43 // for compatibility with existing PROGMEM-reading AVR code.
     44 // Do our own checks and defines here for good measure...
     45 
     46 #ifndef pgm_read_byte
     47 #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
     48 #endif
     49 #ifndef pgm_read_word
     50 #define pgm_read_word(addr) (*(const unsigned short *)(addr))
     51 #endif
     52 #ifndef pgm_read_dword
     53 #define pgm_read_dword(addr) (*(const unsigned long *)(addr))
     54 #endif
     55 
     56 // Pointers are a peculiar case...typically 16-bit on AVR boards,
     57 // 32 bits elsewhere.  Try to accommodate both...
     58 
     59 #if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
     60 #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
     61 #else
     62 #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
     63 #endif
     64 
     65 inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
     66 #ifdef __AVR__
     67   return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
     68 #else
     69   // expression in __AVR__ section may generate "dereferencing type-punned
     70   // pointer will break strict-aliasing rules" warning In fact, on other
     71   // platforms (such as STM32) there is no need to do this pointer magic as
     72   // program memory may be read in a usual way So expression may be simplified
     73   return gfxFont->glyph + c;
     74 #endif //__AVR__
     75 }
     76 
     77 inline uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) {
     78 #ifdef __AVR__
     79   return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
     80 #else
     81   // expression in __AVR__ section generates "dereferencing type-punned pointer
     82   // will break strict-aliasing rules" warning In fact, on other platforms (such
     83   // as STM32) there is no need to do this pointer magic as program memory may
     84   // be read in a usual way So expression may be simplified
     85   return gfxFont->bitmap;
     86 #endif //__AVR__
     87 }
     88 
     89 #ifndef min
     90 #define min(a, b) (((a) < (b)) ? (a) : (b))
     91 #endif
     92 
     93 #ifndef _swap_int16_t
     94 #define _swap_int16_t(a, b)                                                    \
     95   {                                                                            \
     96     int16_t t = a;                                                             \
     97     a = b;                                                                     \
     98     b = t;                                                                     \
     99   }
    100 #endif
    101 
    102 /**************************************************************************/
    103 /*!
    104    @brief    Instatiate a GFX context for graphics! Can only be done by a
    105    superclass
    106    @param    w   Display width, in pixels
    107    @param    h   Display height, in pixels
    108 */
    109 /**************************************************************************/
    110 Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) {
    111   _width = WIDTH;
    112   _height = HEIGHT;
    113   rotation = 0;
    114   cursor_y = cursor_x = 0;
    115   textsize_x = textsize_y = 1;
    116   textcolor = textbgcolor = 0xFFFF;
    117   wrap = true;
    118   _cp437 = false;
    119   gfxFont = NULL;
    120 }
    121 
    122 /**************************************************************************/
    123 /*!
    124    @brief    Write a line.  Bresenham's algorithm - thx wikpedia
    125     @param    x0  Start point x coordinate
    126     @param    y0  Start point y coordinate
    127     @param    x1  End point x coordinate
    128     @param    y1  End point y coordinate
    129     @param    color 16-bit 5-6-5 Color to draw with
    130 */
    131 /**************************************************************************/
    132 void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
    133                              uint16_t color) {
    134 #if defined(ESP8266)
    135   yield();
    136 #endif
    137   int16_t steep = abs(y1 - y0) > abs(x1 - x0);
    138   if (steep) {
    139     _swap_int16_t(x0, y0);
    140     _swap_int16_t(x1, y1);
    141   }
    142 
    143   if (x0 > x1) {
    144     _swap_int16_t(x0, x1);
    145     _swap_int16_t(y0, y1);
    146   }
    147 
    148   int16_t dx, dy;
    149   dx = x1 - x0;
    150   dy = abs(y1 - y0);
    151 
    152   int16_t err = dx / 2;
    153   int16_t ystep;
    154 
    155   if (y0 < y1) {
    156     ystep = 1;
    157   } else {
    158     ystep = -1;
    159   }
    160 
    161   for (; x0 <= x1; x0++) {
    162     if (steep) {
    163       writePixel(y0, x0, color);
    164     } else {
    165       writePixel(x0, y0, color);
    166     }
    167     err -= dy;
    168     if (err < 0) {
    169       y0 += ystep;
    170       err += dx;
    171     }
    172   }
    173 }
    174 
    175 /**************************************************************************/
    176 /*!
    177    @brief    Start a display-writing routine, overwrite in subclasses.
    178 */
    179 /**************************************************************************/
    180 void Adafruit_GFX::startWrite() {}
    181 
    182 /**************************************************************************/
    183 /*!
    184    @brief    Write a pixel, overwrite in subclasses if startWrite is defined!
    185     @param   x   x coordinate
    186     @param   y   y coordinate
    187    @param    color 16-bit 5-6-5 Color to fill with
    188 */
    189 /**************************************************************************/
    190 void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color) {
    191   drawPixel(x, y, color);
    192 }
    193 
    194 /**************************************************************************/
    195 /*!
    196    @brief    Write a perfectly vertical line, overwrite in subclasses if
    197    startWrite is defined!
    198     @param    x   Top-most x coordinate
    199     @param    y   Top-most y coordinate
    200     @param    h   Height in pixels
    201    @param    color 16-bit 5-6-5 Color to fill with
    202 */
    203 /**************************************************************************/
    204 void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y, int16_t h,
    205                                   uint16_t color) {
    206   // Overwrite in subclasses if startWrite is defined!
    207   // Can be just writeLine(x, y, x, y+h-1, color);
    208   // or writeFillRect(x, y, 1, h, color);
    209   drawFastVLine(x, y, h, color);
    210 }
    211 
    212 /**************************************************************************/
    213 /*!
    214    @brief    Write a perfectly horizontal line, overwrite in subclasses if
    215    startWrite is defined!
    216     @param    x   Left-most x coordinate
    217     @param    y   Left-most y coordinate
    218     @param    w   Width in pixels
    219    @param    color 16-bit 5-6-5 Color to fill with
    220 */
    221 /**************************************************************************/
    222 void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y, int16_t w,
    223                                   uint16_t color) {
    224   // Overwrite in subclasses if startWrite is defined!
    225   // Example: writeLine(x, y, x+w-1, y, color);
    226   // or writeFillRect(x, y, w, 1, color);
    227   drawFastHLine(x, y, w, color);
    228 }
    229 
    230 /**************************************************************************/
    231 /*!
    232    @brief    Write a rectangle completely with one color, overwrite in
    233    subclasses if startWrite is defined!
    234     @param    x   Top left corner x coordinate
    235     @param    y   Top left corner y coordinate
    236     @param    w   Width in pixels
    237     @param    h   Height in pixels
    238    @param    color 16-bit 5-6-5 Color to fill with
    239 */
    240 /**************************************************************************/
    241 void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
    242                                  uint16_t color) {
    243   // Overwrite in subclasses if desired!
    244   fillRect(x, y, w, h, color);
    245 }
    246 
    247 /**************************************************************************/
    248 /*!
    249    @brief    End a display-writing routine, overwrite in subclasses if
    250    startWrite is defined!
    251 */
    252 /**************************************************************************/
    253 void Adafruit_GFX::endWrite() {}
    254 
    255 /**************************************************************************/
    256 /*!
    257    @brief    Draw a perfectly vertical line (this is often optimized in a
    258    subclass!)
    259     @param    x   Top-most x coordinate
    260     @param    y   Top-most y coordinate
    261     @param    h   Height in pixels
    262    @param    color 16-bit 5-6-5 Color to fill with
    263 */
    264 /**************************************************************************/
    265 void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h,
    266                                  uint16_t color) {
    267   startWrite();
    268   writeLine(x, y, x, y + h - 1, color);
    269   endWrite();
    270 }
    271 
    272 /**************************************************************************/
    273 /*!
    274    @brief    Draw a perfectly horizontal line (this is often optimized in a
    275    subclass!)
    276     @param    x   Left-most x coordinate
    277     @param    y   Left-most y coordinate
    278     @param    w   Width in pixels
    279    @param    color 16-bit 5-6-5 Color to fill with
    280 */
    281 /**************************************************************************/
    282 void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w,
    283                                  uint16_t color) {
    284   startWrite();
    285   writeLine(x, y, x + w - 1, y, color);
    286   endWrite();
    287 }
    288 
    289 /**************************************************************************/
    290 /*!
    291    @brief    Fill a rectangle completely with one color. Update in subclasses if
    292    desired!
    293     @param    x   Top left corner x coordinate
    294     @param    y   Top left corner y coordinate
    295     @param    w   Width in pixels
    296     @param    h   Height in pixels
    297    @param    color 16-bit 5-6-5 Color to fill with
    298 */
    299 /**************************************************************************/
    300 void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
    301                             uint16_t color) {
    302   startWrite();
    303   for (int16_t i = x; i < x + w; i++) {
    304     writeFastVLine(i, y, h, color);
    305   }
    306   endWrite();
    307 }
    308 
    309 /**************************************************************************/
    310 /*!
    311    @brief    Fill the screen completely with one color. Update in subclasses if
    312    desired!
    313     @param    color 16-bit 5-6-5 Color to fill with
    314 */
    315 /**************************************************************************/
    316 void Adafruit_GFX::fillScreen(uint16_t color) {
    317   fillRect(0, 0, _width, _height, color);
    318 }
    319 
    320 /**************************************************************************/
    321 /*!
    322    @brief    Draw a line
    323     @param    x0  Start point x coordinate
    324     @param    y0  Start point y coordinate
    325     @param    x1  End point x coordinate
    326     @param    y1  End point y coordinate
    327     @param    color 16-bit 5-6-5 Color to draw with
    328 */
    329 /**************************************************************************/
    330 void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
    331                             uint16_t color) {
    332   // Update in subclasses if desired!
    333   if (x0 == x1) {
    334     if (y0 > y1)
    335       _swap_int16_t(y0, y1);
    336     drawFastVLine(x0, y0, y1 - y0 + 1, color);
    337   } else if (y0 == y1) {
    338     if (x0 > x1)
    339       _swap_int16_t(x0, x1);
    340     drawFastHLine(x0, y0, x1 - x0 + 1, color);
    341   } else {
    342     startWrite();
    343     writeLine(x0, y0, x1, y1, color);
    344     endWrite();
    345   }
    346 }
    347 
    348 /**************************************************************************/
    349 /*!
    350    @brief    Draw a circle outline
    351     @param    x0   Center-point x coordinate
    352     @param    y0   Center-point y coordinate
    353     @param    r   Radius of circle
    354     @param    color 16-bit 5-6-5 Color to draw with
    355 */
    356 /**************************************************************************/
    357 void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
    358                               uint16_t color) {
    359 #if defined(ESP8266)
    360   yield();
    361 #endif
    362   int16_t f = 1 - r;
    363   int16_t ddF_x = 1;
    364   int16_t ddF_y = -2 * r;
    365   int16_t x = 0;
    366   int16_t y = r;
    367 
    368   startWrite();
    369   writePixel(x0, y0 + r, color);
    370   writePixel(x0, y0 - r, color);
    371   writePixel(x0 + r, y0, color);
    372   writePixel(x0 - r, y0, color);
    373 
    374   while (x < y) {
    375     if (f >= 0) {
    376       y--;
    377       ddF_y += 2;
    378       f += ddF_y;
    379     }
    380     x++;
    381     ddF_x += 2;
    382     f += ddF_x;
    383 
    384     writePixel(x0 + x, y0 + y, color);
    385     writePixel(x0 - x, y0 + y, color);
    386     writePixel(x0 + x, y0 - y, color);
    387     writePixel(x0 - x, y0 - y, color);
    388     writePixel(x0 + y, y0 + x, color);
    389     writePixel(x0 - y, y0 + x, color);
    390     writePixel(x0 + y, y0 - x, color);
    391     writePixel(x0 - y, y0 - x, color);
    392   }
    393   endWrite();
    394 }
    395 
    396 /**************************************************************************/
    397 /*!
    398     @brief    Quarter-circle drawer, used to do circles and roundrects
    399     @param    x0   Center-point x coordinate
    400     @param    y0   Center-point y coordinate
    401     @param    r   Radius of circle
    402     @param    cornername  Mask bit #1 or bit #2 to indicate which quarters of
    403    the circle we're doing
    404     @param    color 16-bit 5-6-5 Color to draw with
    405 */
    406 /**************************************************************************/
    407 void Adafruit_GFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r,
    408                                     uint8_t cornername, uint16_t color) {
    409   int16_t f = 1 - r;
    410   int16_t ddF_x = 1;
    411   int16_t ddF_y = -2 * r;
    412   int16_t x = 0;
    413   int16_t y = r;
    414 
    415   while (x < y) {
    416     if (f >= 0) {
    417       y--;
    418       ddF_y += 2;
    419       f += ddF_y;
    420     }
    421     x++;
    422     ddF_x += 2;
    423     f += ddF_x;
    424     if (cornername & 0x4) {
    425       writePixel(x0 + x, y0 + y, color);
    426       writePixel(x0 + y, y0 + x, color);
    427     }
    428     if (cornername & 0x2) {
    429       writePixel(x0 + x, y0 - y, color);
    430       writePixel(x0 + y, y0 - x, color);
    431     }
    432     if (cornername & 0x8) {
    433       writePixel(x0 - y, y0 + x, color);
    434       writePixel(x0 - x, y0 + y, color);
    435     }
    436     if (cornername & 0x1) {
    437       writePixel(x0 - y, y0 - x, color);
    438       writePixel(x0 - x, y0 - y, color);
    439     }
    440   }
    441 }
    442 
    443 /**************************************************************************/
    444 /*!
    445    @brief    Draw a circle with filled color
    446     @param    x0   Center-point x coordinate
    447     @param    y0   Center-point y coordinate
    448     @param    r   Radius of circle
    449     @param    color 16-bit 5-6-5 Color to fill with
    450 */
    451 /**************************************************************************/
    452 void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
    453                               uint16_t color) {
    454   startWrite();
    455   writeFastVLine(x0, y0 - r, 2 * r + 1, color);
    456   fillCircleHelper(x0, y0, r, 3, 0, color);
    457   endWrite();
    458 }
    459 
    460 /**************************************************************************/
    461 /*!
    462     @brief  Quarter-circle drawer with fill, used for circles and roundrects
    463     @param  x0       Center-point x coordinate
    464     @param  y0       Center-point y coordinate
    465     @param  r        Radius of circle
    466     @param  corners  Mask bits indicating which quarters we're doing
    467     @param  delta    Offset from center-point, used for round-rects
    468     @param  color    16-bit 5-6-5 Color to fill with
    469 */
    470 /**************************************************************************/
    471 void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
    472                                     uint8_t corners, int16_t delta,
    473                                     uint16_t color) {
    474 
    475   int16_t f = 1 - r;
    476   int16_t ddF_x = 1;
    477   int16_t ddF_y = -2 * r;
    478   int16_t x = 0;
    479   int16_t y = r;
    480   int16_t px = x;
    481   int16_t py = y;
    482 
    483   delta++; // Avoid some +1's in the loop
    484 
    485   while (x < y) {
    486     if (f >= 0) {
    487       y--;
    488       ddF_y += 2;
    489       f += ddF_y;
    490     }
    491     x++;
    492     ddF_x += 2;
    493     f += ddF_x;
    494     // These checks avoid double-drawing certain lines, important
    495     // for the SSD1306 library which has an INVERT drawing mode.
    496     if (x < (y + 1)) {
    497       if (corners & 1)
    498         writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color);
    499       if (corners & 2)
    500         writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color);
    501     }
    502     if (y != py) {
    503       if (corners & 1)
    504         writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color);
    505       if (corners & 2)
    506         writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color);
    507       py = y;
    508     }
    509     px = x;
    510   }
    511 }
    512 
    513 /**************************************************************************/
    514 /*!
    515    @brief   Draw a rectangle with no fill color
    516     @param    x   Top left corner x coordinate
    517     @param    y   Top left corner y coordinate
    518     @param    w   Width in pixels
    519     @param    h   Height in pixels
    520     @param    color 16-bit 5-6-5 Color to draw with
    521 */
    522 /**************************************************************************/
    523 void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
    524                             uint16_t color) {
    525   startWrite();
    526   writeFastHLine(x, y, w, color);
    527   writeFastHLine(x, y + h - 1, w, color);
    528   writeFastVLine(x, y, h, color);
    529   writeFastVLine(x + w - 1, y, h, color);
    530   endWrite();
    531 }
    532 
    533 /**************************************************************************/
    534 /*!
    535    @brief   Draw a rounded rectangle with no fill color
    536     @param    x   Top left corner x coordinate
    537     @param    y   Top left corner y coordinate
    538     @param    w   Width in pixels
    539     @param    h   Height in pixels
    540     @param    r   Radius of corner rounding
    541     @param    color 16-bit 5-6-5 Color to draw with
    542 */
    543 /**************************************************************************/
    544 void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
    545                                  int16_t r, uint16_t color) {
    546   int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    547   if (r > max_radius)
    548     r = max_radius;
    549   // smarter version
    550   startWrite();
    551   writeFastHLine(x + r, y, w - 2 * r, color);         // Top
    552   writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
    553   writeFastVLine(x, y + r, h - 2 * r, color);         // Left
    554   writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
    555   // draw four corners
    556   drawCircleHelper(x + r, y + r, r, 1, color);
    557   drawCircleHelper(x + w - r - 1, y + r, r, 2, color);
    558   drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
    559   drawCircleHelper(x + r, y + h - r - 1, r, 8, color);
    560   endWrite();
    561 }
    562 
    563 /**************************************************************************/
    564 /*!
    565    @brief   Draw a rounded rectangle with fill color
    566     @param    x   Top left corner x coordinate
    567     @param    y   Top left corner y coordinate
    568     @param    w   Width in pixels
    569     @param    h   Height in pixels
    570     @param    r   Radius of corner rounding
    571     @param    color 16-bit 5-6-5 Color to draw/fill with
    572 */
    573 /**************************************************************************/
    574 void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
    575                                  int16_t r, uint16_t color) {
    576   int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    577   if (r > max_radius)
    578     r = max_radius;
    579   // smarter version
    580   startWrite();
    581   writeFillRect(x + r, y, w - 2 * r, h, color);
    582   // draw four corners
    583   fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
    584   fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
    585   endWrite();
    586 }
    587 
    588 /**************************************************************************/
    589 /*!
    590    @brief   Draw a triangle with no fill color
    591     @param    x0  Vertex #0 x coordinate
    592     @param    y0  Vertex #0 y coordinate
    593     @param    x1  Vertex #1 x coordinate
    594     @param    y1  Vertex #1 y coordinate
    595     @param    x2  Vertex #2 x coordinate
    596     @param    y2  Vertex #2 y coordinate
    597     @param    color 16-bit 5-6-5 Color to draw with
    598 */
    599 /**************************************************************************/
    600 void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
    601                                 int16_t x2, int16_t y2, uint16_t color) {
    602   drawLine(x0, y0, x1, y1, color);
    603   drawLine(x1, y1, x2, y2, color);
    604   drawLine(x2, y2, x0, y0, color);
    605 }
    606 
    607 /**************************************************************************/
    608 /*!
    609    @brief     Draw a triangle with color-fill
    610     @param    x0  Vertex #0 x coordinate
    611     @param    y0  Vertex #0 y coordinate
    612     @param    x1  Vertex #1 x coordinate
    613     @param    y1  Vertex #1 y coordinate
    614     @param    x2  Vertex #2 x coordinate
    615     @param    y2  Vertex #2 y coordinate
    616     @param    color 16-bit 5-6-5 Color to fill/draw with
    617 */
    618 /**************************************************************************/
    619 void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
    620                                 int16_t x2, int16_t y2, uint16_t color) {
    621 
    622   int16_t a, b, y, last;
    623 
    624   // Sort coordinates by Y order (y2 >= y1 >= y0)
    625   if (y0 > y1) {
    626     _swap_int16_t(y0, y1);
    627     _swap_int16_t(x0, x1);
    628   }
    629   if (y1 > y2) {
    630     _swap_int16_t(y2, y1);
    631     _swap_int16_t(x2, x1);
    632   }
    633   if (y0 > y1) {
    634     _swap_int16_t(y0, y1);
    635     _swap_int16_t(x0, x1);
    636   }
    637 
    638   startWrite();
    639   if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
    640     a = b = x0;
    641     if (x1 < a)
    642       a = x1;
    643     else if (x1 > b)
    644       b = x1;
    645     if (x2 < a)
    646       a = x2;
    647     else if (x2 > b)
    648       b = x2;
    649     writeFastHLine(a, y0, b - a + 1, color);
    650     endWrite();
    651     return;
    652   }
    653 
    654   int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
    655           dx12 = x2 - x1, dy12 = y2 - y1;
    656   int32_t sa = 0, sb = 0;
    657 
    658   // For upper part of triangle, find scanline crossings for segments
    659   // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
    660   // is included here (and second loop will be skipped, avoiding a /0
    661   // error there), otherwise scanline y1 is skipped here and handled
    662   // in the second loop...which also avoids a /0 error here if y0=y1
    663   // (flat-topped triangle).
    664   if (y1 == y2)
    665     last = y1; // Include y1 scanline
    666   else
    667     last = y1 - 1; // Skip it
    668 
    669   for (y = y0; y <= last; y++) {
    670     a = x0 + sa / dy01;
    671     b = x0 + sb / dy02;
    672     sa += dx01;
    673     sb += dx02;
    674     /* longhand:
    675     a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
    676     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
    677     */
    678     if (a > b)
    679       _swap_int16_t(a, b);
    680     writeFastHLine(a, y, b - a + 1, color);
    681   }
    682 
    683   // For lower part of triangle, find scanline crossings for segments
    684   // 0-2 and 1-2.  This loop is skipped if y1=y2.
    685   sa = (int32_t)dx12 * (y - y1);
    686   sb = (int32_t)dx02 * (y - y0);
    687   for (; y <= y2; y++) {
    688     a = x1 + sa / dy12;
    689     b = x0 + sb / dy02;
    690     sa += dx12;
    691     sb += dx02;
    692     /* longhand:
    693     a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
    694     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
    695     */
    696     if (a > b)
    697       _swap_int16_t(a, b);
    698     writeFastHLine(a, y, b - a + 1, color);
    699   }
    700   endWrite();
    701 }
    702 
    703 // BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
    704 
    705 /**************************************************************************/
    706 /*!
    707    @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y)
    708    position, using the specified foreground color (unset bits are transparent).
    709     @param    x   Top left corner x coordinate
    710     @param    y   Top left corner y coordinate
    711     @param    bitmap  byte array with monochrome bitmap
    712     @param    w   Width of bitmap in pixels
    713     @param    h   Height of bitmap in pixels
    714     @param    color 16-bit 5-6-5 Color to draw with
    715 */
    716 /**************************************************************************/
    717 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
    718                               int16_t w, int16_t h, uint16_t color) {
    719 
    720   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    721   uint8_t byte = 0;
    722 
    723   startWrite();
    724   for (int16_t j = 0; j < h; j++, y++) {
    725     for (int16_t i = 0; i < w; i++) {
    726       if (i & 7)
    727         byte <<= 1;
    728       else
    729         byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
    730       if (byte & 0x80)
    731         writePixel(x + i, y, color);
    732     }
    733   }
    734   endWrite();
    735 }
    736 
    737 /**************************************************************************/
    738 /*!
    739    @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y)
    740    position, using the specified foreground (for set bits) and background (unset
    741    bits) colors.
    742     @param    x   Top left corner x coordinate
    743     @param    y   Top left corner y coordinate
    744     @param    bitmap  byte array with monochrome bitmap
    745     @param    w   Width of bitmap in pixels
    746     @param    h   Height of bitmap in pixels
    747     @param    color 16-bit 5-6-5 Color to draw pixels with
    748     @param    bg 16-bit 5-6-5 Color to draw background with
    749 */
    750 /**************************************************************************/
    751 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
    752                               int16_t w, int16_t h, uint16_t color,
    753                               uint16_t bg) {
    754 
    755   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    756   uint8_t byte = 0;
    757 
    758   startWrite();
    759   for (int16_t j = 0; j < h; j++, y++) {
    760     for (int16_t i = 0; i < w; i++) {
    761       if (i & 7)
    762         byte <<= 1;
    763       else
    764         byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
    765       writePixel(x + i, y, (byte & 0x80) ? color : bg);
    766     }
    767   }
    768   endWrite();
    769 }
    770 
    771 /**************************************************************************/
    772 /*!
    773    @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position,
    774    using the specified foreground color (unset bits are transparent).
    775     @param    x   Top left corner x coordinate
    776     @param    y   Top left corner y coordinate
    777     @param    bitmap  byte array with monochrome bitmap
    778     @param    w   Width of bitmap in pixels
    779     @param    h   Height of bitmap in pixels
    780     @param    color 16-bit 5-6-5 Color to draw with
    781 */
    782 /**************************************************************************/
    783 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
    784                               int16_t h, uint16_t color) {
    785 
    786   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    787   uint8_t byte = 0;
    788 
    789   startWrite();
    790   for (int16_t j = 0; j < h; j++, y++) {
    791     for (int16_t i = 0; i < w; i++) {
    792       if (i & 7)
    793         byte <<= 1;
    794       else
    795         byte = bitmap[j * byteWidth + i / 8];
    796       if (byte & 0x80)
    797         writePixel(x + i, y, color);
    798     }
    799   }
    800   endWrite();
    801 }
    802 
    803 /**************************************************************************/
    804 /*!
    805    @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position,
    806    using the specified foreground (for set bits) and background (unset bits)
    807    colors.
    808     @param    x   Top left corner x coordinate
    809     @param    y   Top left corner y coordinate
    810     @param    bitmap  byte array with monochrome bitmap
    811     @param    w   Width of bitmap in pixels
    812     @param    h   Height of bitmap in pixels
    813     @param    color 16-bit 5-6-5 Color to draw pixels with
    814     @param    bg 16-bit 5-6-5 Color to draw background with
    815 */
    816 /**************************************************************************/
    817 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
    818                               int16_t h, uint16_t color, uint16_t bg) {
    819 
    820   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    821   uint8_t byte = 0;
    822 
    823   startWrite();
    824   for (int16_t j = 0; j < h; j++, y++) {
    825     for (int16_t i = 0; i < w; i++) {
    826       if (i & 7)
    827         byte <<= 1;
    828       else
    829         byte = bitmap[j * byteWidth + i / 8];
    830       writePixel(x + i, y, (byte & 0x80) ? color : bg);
    831     }
    832   }
    833   endWrite();
    834 }
    835 
    836 /**************************************************************************/
    837 /*!
    838    @brief      Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP.
    839    Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
    840    C Array can be directly used with this function.
    841    There is no RAM-resident version of this function; if generating bitmaps
    842    in RAM, use the format defined by drawBitmap() and call that instead.
    843     @param    x   Top left corner x coordinate
    844     @param    y   Top left corner y coordinate
    845     @param    bitmap  byte array with monochrome bitmap
    846     @param    w   Width of bitmap in pixels
    847     @param    h   Height of bitmap in pixels
    848     @param    color 16-bit 5-6-5 Color to draw pixels with
    849 */
    850 /**************************************************************************/
    851 void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
    852                                int16_t w, int16_t h, uint16_t color) {
    853 
    854   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
    855   uint8_t byte = 0;
    856 
    857   startWrite();
    858   for (int16_t j = 0; j < h; j++, y++) {
    859     for (int16_t i = 0; i < w; i++) {
    860       if (i & 7)
    861         byte >>= 1;
    862       else
    863         byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
    864       // Nearly identical to drawBitmap(), only the bit order
    865       // is reversed here (left-to-right = LSB to MSB):
    866       if (byte & 0x01)
    867         writePixel(x + i, y, color);
    868     }
    869   }
    870   endWrite();
    871 }
    872 
    873 /**************************************************************************/
    874 /*!
    875    @brief   Draw a PROGMEM-resident 8-bit image (grayscale) at the specified
    876    (x,y) pos. Specifically for 8-bit display devices such as IS31FL3731; no
    877    color reduction/expansion is performed.
    878     @param    x   Top left corner x coordinate
    879     @param    y   Top left corner y coordinate
    880     @param    bitmap  byte array with grayscale bitmap
    881     @param    w   Width of bitmap in pixels
    882     @param    h   Height of bitmap in pixels
    883 */
    884 /**************************************************************************/
    885 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
    886                                        const uint8_t bitmap[], int16_t w,
    887                                        int16_t h) {
    888   startWrite();
    889   for (int16_t j = 0; j < h; j++, y++) {
    890     for (int16_t i = 0; i < w; i++) {
    891       writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
    892     }
    893   }
    894   endWrite();
    895 }
    896 
    897 /**************************************************************************/
    898 /*!
    899    @brief   Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y)
    900    pos. Specifically for 8-bit display devices such as IS31FL3731; no color
    901    reduction/expansion is performed.
    902     @param    x   Top left corner x coordinate
    903     @param    y   Top left corner y coordinate
    904     @param    bitmap  byte array with grayscale bitmap
    905     @param    w   Width of bitmap in pixels
    906     @param    h   Height of bitmap in pixels
    907 */
    908 /**************************************************************************/
    909 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
    910                                        int16_t w, int16_t h) {
    911   startWrite();
    912   for (int16_t j = 0; j < h; j++, y++) {
    913     for (int16_t i = 0; i < w; i++) {
    914       writePixel(x + i, y, bitmap[j * w + i]);
    915     }
    916   }
    917   endWrite();
    918 }
    919 
    920 /**************************************************************************/
    921 /*!
    922    @brief   Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask
    923    (set bits = opaque, unset bits = clear) at the specified (x,y) position.
    924    BOTH buffers (grayscale and mask) must be PROGMEM-resident.
    925    Specifically for 8-bit display devices such as IS31FL3731; no color
    926    reduction/expansion is performed.
    927     @param    x   Top left corner x coordinate
    928     @param    y   Top left corner y coordinate
    929     @param    bitmap  byte array with grayscale bitmap
    930     @param    mask  byte array with mask bitmap
    931     @param    w   Width of bitmap in pixels
    932     @param    h   Height of bitmap in pixels
    933 */
    934 /**************************************************************************/
    935 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
    936                                        const uint8_t bitmap[],
    937                                        const uint8_t mask[], int16_t w,
    938                                        int16_t h) {
    939   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
    940   uint8_t byte = 0;
    941   startWrite();
    942   for (int16_t j = 0; j < h; j++, y++) {
    943     for (int16_t i = 0; i < w; i++) {
    944       if (i & 7)
    945         byte <<= 1;
    946       else
    947         byte = pgm_read_byte(&mask[j * bw + i / 8]);
    948       if (byte & 0x80) {
    949         writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
    950       }
    951     }
    952   }
    953   endWrite();
    954 }
    955 
    956 /**************************************************************************/
    957 /*!
    958    @brief   Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask
    959    (set bits = opaque, unset bits = clear) at the specified (x,y) position.
    960    BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match
    961    Specifically for 8-bit display devices such as IS31FL3731; no color
    962    reduction/expansion is performed.
    963     @param    x   Top left corner x coordinate
    964     @param    y   Top left corner y coordinate
    965     @param    bitmap  byte array with grayscale bitmap
    966     @param    mask  byte array with mask bitmap
    967     @param    w   Width of bitmap in pixels
    968     @param    h   Height of bitmap in pixels
    969 */
    970 /**************************************************************************/
    971 void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
    972                                        uint8_t *mask, int16_t w, int16_t h) {
    973   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
    974   uint8_t byte = 0;
    975   startWrite();
    976   for (int16_t j = 0; j < h; j++, y++) {
    977     for (int16_t i = 0; i < w; i++) {
    978       if (i & 7)
    979         byte <<= 1;
    980       else
    981         byte = mask[j * bw + i / 8];
    982       if (byte & 0x80) {
    983         writePixel(x + i, y, bitmap[j * w + i]);
    984       }
    985     }
    986   }
    987   endWrite();
    988 }
    989 
    990 /**************************************************************************/
    991 /*!
    992    @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified
    993    (x,y) position. For 16-bit display devices; no color reduction performed.
    994     @param    x   Top left corner x coordinate
    995     @param    y   Top left corner y coordinate
    996     @param    bitmap  byte array with 16-bit color bitmap
    997     @param    w   Width of bitmap in pixels
    998     @param    h   Height of bitmap in pixels
    999 */
   1000 /**************************************************************************/
   1001 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
   1002                                  int16_t w, int16_t h) {
   1003   startWrite();
   1004   for (int16_t j = 0; j < h; j++, y++) {
   1005     for (int16_t i = 0; i < w; i++) {
   1006       writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i]));
   1007     }
   1008   }
   1009   endWrite();
   1010 }
   1011 
   1012 /**************************************************************************/
   1013 /*!
   1014    @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y)
   1015    position. For 16-bit display devices; no color reduction performed.
   1016     @param    x   Top left corner x coordinate
   1017     @param    y   Top left corner y coordinate
   1018     @param    bitmap  byte array with 16-bit color bitmap
   1019     @param    w   Width of bitmap in pixels
   1020     @param    h   Height of bitmap in pixels
   1021 */
   1022 /**************************************************************************/
   1023 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
   1024                                  int16_t w, int16_t h) {
   1025   startWrite();
   1026   for (int16_t j = 0; j < h; j++, y++) {
   1027     for (int16_t i = 0; i < w; i++) {
   1028       writePixel(x + i, y, bitmap[j * w + i]);
   1029     }
   1030   }
   1031   endWrite();
   1032 }
   1033 
   1034 /**************************************************************************/
   1035 /*!
   1036    @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask
   1037    (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH
   1038    buffers (color and mask) must be PROGMEM-resident. For 16-bit display
   1039    devices; no color reduction performed.
   1040     @param    x   Top left corner x coordinate
   1041     @param    y   Top left corner y coordinate
   1042     @param    bitmap  byte array with 16-bit color bitmap
   1043     @param    mask  byte array with monochrome mask bitmap
   1044     @param    w   Width of bitmap in pixels
   1045     @param    h   Height of bitmap in pixels
   1046 */
   1047 /**************************************************************************/
   1048 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
   1049                                  const uint8_t mask[], int16_t w, int16_t h) {
   1050   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1051   uint8_t byte = 0;
   1052   startWrite();
   1053   for (int16_t j = 0; j < h; j++, y++) {
   1054     for (int16_t i = 0; i < w; i++) {
   1055       if (i & 7)
   1056         byte <<= 1;
   1057       else
   1058         byte = pgm_read_byte(&mask[j * bw + i / 8]);
   1059       if (byte & 0x80) {
   1060         writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i]));
   1061       }
   1062     }
   1063   }
   1064   endWrite();
   1065 }
   1066 
   1067 /**************************************************************************/
   1068 /*!
   1069    @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set
   1070    bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH
   1071    buffers (color and mask) must be RAM-resident. For 16-bit display devices; no
   1072    color reduction performed.
   1073     @param    x   Top left corner x coordinate
   1074     @param    y   Top left corner y coordinate
   1075     @param    bitmap  byte array with 16-bit color bitmap
   1076     @param    mask  byte array with monochrome mask bitmap
   1077     @param    w   Width of bitmap in pixels
   1078     @param    h   Height of bitmap in pixels
   1079 */
   1080 /**************************************************************************/
   1081 void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
   1082                                  uint8_t *mask, int16_t w, int16_t h) {
   1083   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1084   uint8_t byte = 0;
   1085   startWrite();
   1086   for (int16_t j = 0; j < h; j++, y++) {
   1087     for (int16_t i = 0; i < w; i++) {
   1088       if (i & 7)
   1089         byte <<= 1;
   1090       else
   1091         byte = mask[j * bw + i / 8];
   1092       if (byte & 0x80) {
   1093         writePixel(x + i, y, bitmap[j * w + i]);
   1094       }
   1095     }
   1096   }
   1097   endWrite();
   1098 }
   1099 
   1100 // TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
   1101 
   1102 // Draw a character
   1103 /**************************************************************************/
   1104 /*!
   1105    @brief   Draw a single character
   1106     @param    x   Bottom left corner x coordinate
   1107     @param    y   Bottom left corner y coordinate
   1108     @param    c   The 8-bit font-indexed character (likely ascii)
   1109     @param    color 16-bit 5-6-5 Color to draw chraracter with
   1110     @param    bg 16-bit 5-6-5 Color to fill background with (if same as color,
   1111    no background)
   1112     @param    size  Font magnification level, 1 is 'original' size
   1113 */
   1114 /**************************************************************************/
   1115 void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
   1116                             uint16_t color, uint16_t bg, uint8_t size) {
   1117   drawChar(x, y, c, color, bg, size, size);
   1118 }
   1119 
   1120 // Draw a character
   1121 /**************************************************************************/
   1122 /*!
   1123    @brief   Draw a single character
   1124     @param    x   Bottom left corner x coordinate
   1125     @param    y   Bottom left corner y coordinate
   1126     @param    c   The 8-bit font-indexed character (likely ascii)
   1127     @param    color 16-bit 5-6-5 Color to draw chraracter with
   1128     @param    bg 16-bit 5-6-5 Color to fill background with (if same as color,
   1129    no background)
   1130     @param    size_x  Font magnification level in X-axis, 1 is 'original' size
   1131     @param    size_y  Font magnification level in Y-axis, 1 is 'original' size
   1132 */
   1133 /**************************************************************************/
   1134 void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
   1135                             uint16_t color, uint16_t bg, uint8_t size_x,
   1136                             uint8_t size_y) {
   1137 
   1138   if (!gfxFont) { // 'Classic' built-in font
   1139 
   1140     if ((x >= _width) ||              // Clip right
   1141         (y >= _height) ||             // Clip bottom
   1142         ((x + 6 * size_x - 1) < 0) || // Clip left
   1143         ((y + 8 * size_y - 1) < 0))   // Clip top
   1144       return;
   1145 
   1146     if (!_cp437 && (c >= 176))
   1147       c++; // Handle 'classic' charset behavior
   1148 
   1149     startWrite();
   1150     for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns
   1151       uint8_t line = pgm_read_byte(&font[c * 5 + i]);
   1152       for (int8_t j = 0; j < 8; j++, line >>= 1) {
   1153         if (line & 1) {
   1154           if (size_x == 1 && size_y == 1)
   1155             writePixel(x + i, y + j, color);
   1156           else
   1157             writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y,
   1158                           color);
   1159         } else if (bg != color) {
   1160           if (size_x == 1 && size_y == 1)
   1161             writePixel(x + i, y + j, bg);
   1162           else
   1163             writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg);
   1164         }
   1165       }
   1166     }
   1167     if (bg != color) { // If opaque, draw vertical line for last column
   1168       if (size_x == 1 && size_y == 1)
   1169         writeFastVLine(x + 5, y, 8, bg);
   1170       else
   1171         writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg);
   1172     }
   1173     endWrite();
   1174 
   1175   } else { // Custom font
   1176 
   1177     // Character is assumed previously filtered by write() to eliminate
   1178     // newlines, returns, non-printable characters, etc.  Calling
   1179     // drawChar() directly with 'bad' characters of font may cause mayhem!
   1180 
   1181     c -= (uint8_t)pgm_read_byte(&gfxFont->first);
   1182     GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
   1183     uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
   1184 
   1185     uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
   1186     uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height);
   1187     int8_t xo = pgm_read_byte(&glyph->xOffset),
   1188            yo = pgm_read_byte(&glyph->yOffset);
   1189     uint8_t xx, yy, bits = 0, bit = 0;
   1190     int16_t xo16 = 0, yo16 = 0;
   1191 
   1192     if (size_x > 1 || size_y > 1) {
   1193       xo16 = xo;
   1194       yo16 = yo;
   1195     }
   1196 
   1197     // Todo: Add character clipping here
   1198 
   1199     // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
   1200     // THIS IS ON PURPOSE AND BY DESIGN.  The background color feature
   1201     // has typically been used with the 'classic' font to overwrite old
   1202     // screen contents with new data.  This ONLY works because the
   1203     // characters are a uniform size; it's not a sensible thing to do with
   1204     // proportionally-spaced fonts with glyphs of varying sizes (and that
   1205     // may overlap).  To replace previously-drawn text when using a custom
   1206     // font, use the getTextBounds() function to determine the smallest
   1207     // rectangle encompassing a string, erase the area with fillRect(),
   1208     // then draw new text.  This WILL infortunately 'blink' the text, but
   1209     // is unavoidable.  Drawing 'background' pixels will NOT fix this,
   1210     // only creates a new set of problems.  Have an idea to work around
   1211     // this (a canvas object type for MCUs that can afford the RAM and
   1212     // displays supporting setAddrWindow() and pushColors()), but haven't
   1213     // implemented this yet.
   1214 
   1215     startWrite();
   1216     for (yy = 0; yy < h; yy++) {
   1217       for (xx = 0; xx < w; xx++) {
   1218         if (!(bit++ & 7)) {
   1219           bits = pgm_read_byte(&bitmap[bo++]);
   1220         }
   1221         if (bits & 0x80) {
   1222           if (size_x == 1 && size_y == 1) {
   1223             writePixel(x + xo + xx, y + yo + yy, color);
   1224           } else {
   1225             writeFillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y,
   1226                           size_x, size_y, color);
   1227           }
   1228         }
   1229         bits <<= 1;
   1230       }
   1231     }
   1232     endWrite();
   1233 
   1234   } // End classic vs custom font
   1235 }
   1236 /**************************************************************************/
   1237 /*!
   1238     @brief  Print one byte/character of data, used to support print()
   1239     @param  c  The 8-bit ascii character to write
   1240 */
   1241 /**************************************************************************/
   1242 size_t Adafruit_GFX::write(uint8_t c) {
   1243   if (!gfxFont) { // 'Classic' built-in font
   1244 
   1245     if (c == '\n') {              // Newline?
   1246       cursor_x = 0;               // Reset x to zero,
   1247       cursor_y += textsize_y * 8; // advance y one line
   1248     } else if (c != '\r') {       // Ignore carriage returns
   1249       if (wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right?
   1250         cursor_x = 0;                                       // Reset x to zero,
   1251         cursor_y += textsize_y * 8; // advance y one line
   1252       }
   1253       drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x,
   1254                textsize_y);
   1255       cursor_x += textsize_x * 6; // Advance x one char
   1256     }
   1257 
   1258   } else { // Custom font
   1259 
   1260     if (c == '\n') {
   1261       cursor_x = 0;
   1262       cursor_y +=
   1263           (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   1264     } else if (c != '\r') {
   1265       uint8_t first = pgm_read_byte(&gfxFont->first);
   1266       if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
   1267         GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
   1268         uint8_t w = pgm_read_byte(&glyph->width),
   1269                 h = pgm_read_byte(&glyph->height);
   1270         if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
   1271           int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
   1272           if (wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) {
   1273             cursor_x = 0;
   1274             cursor_y += (int16_t)textsize_y *
   1275                         (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   1276           }
   1277           drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x,
   1278                    textsize_y);
   1279         }
   1280         cursor_x +=
   1281             (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x;
   1282       }
   1283     }
   1284   }
   1285   return 1;
   1286 }
   1287 
   1288 /**************************************************************************/
   1289 /*!
   1290     @brief   Set text 'magnification' size. Each increase in s makes 1 pixel
   1291    that much bigger.
   1292     @param  s  Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
   1293 */
   1294 /**************************************************************************/
   1295 void Adafruit_GFX::setTextSize(uint8_t s) { setTextSize(s, s); }
   1296 
   1297 /**************************************************************************/
   1298 /*!
   1299     @brief   Set text 'magnification' size. Each increase in s makes 1 pixel
   1300    that much bigger.
   1301     @param  s_x  Desired text width magnification level in X-axis. 1 is default
   1302     @param  s_y  Desired text width magnification level in Y-axis. 1 is default
   1303 */
   1304 /**************************************************************************/
   1305 void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
   1306   textsize_x = (s_x > 0) ? s_x : 1;
   1307   textsize_y = (s_y > 0) ? s_y : 1;
   1308 }
   1309 
   1310 /**************************************************************************/
   1311 /*!
   1312     @brief      Set rotation setting for display
   1313     @param  x   0 thru 3 corresponding to 4 cardinal rotations
   1314 */
   1315 /**************************************************************************/
   1316 void Adafruit_GFX::setRotation(uint8_t x) {
   1317   rotation = (x & 3);
   1318   switch (rotation) {
   1319   case 0:
   1320   case 2:
   1321     _width = WIDTH;
   1322     _height = HEIGHT;
   1323     break;
   1324   case 1:
   1325   case 3:
   1326     _width = HEIGHT;
   1327     _height = WIDTH;
   1328     break;
   1329   }
   1330 }
   1331 
   1332 /**************************************************************************/
   1333 /*!
   1334     @brief Set the font to display when print()ing, either custom or default
   1335     @param  f  The GFXfont object, if NULL use built in 6x8 font
   1336 */
   1337 /**************************************************************************/
   1338 void Adafruit_GFX::setFont(const GFXfont *f) {
   1339   if (f) {          // Font struct pointer passed in?
   1340     if (!gfxFont) { // And no current font struct?
   1341       // Switching from classic to new font behavior.
   1342       // Move cursor pos down 6 pixels so it's on baseline.
   1343       cursor_y += 6;
   1344     }
   1345   } else if (gfxFont) { // NULL passed.  Current font struct defined?
   1346     // Switching from new to classic font behavior.
   1347     // Move cursor pos up 6 pixels so it's at top-left of char.
   1348     cursor_y -= 6;
   1349   }
   1350   gfxFont = (GFXfont *)f;
   1351 }
   1352 
   1353 /**************************************************************************/
   1354 /*!
   1355     @brief  Helper to determine size of a character with current font/size.
   1356             Broke this out as it's used by both the PROGMEM- and RAM-resident
   1357             getTextBounds() functions.
   1358     @param  c     The ASCII character in question
   1359     @param  x     Pointer to x location of character. Value is modified by
   1360                   this function to advance to next character.
   1361     @param  y     Pointer to y location of character. Value is modified by
   1362                   this function to advance to next character.
   1363     @param  minx  Pointer to minimum X coordinate, passed in to AND returned
   1364                   by this function -- this is used to incrementally build a
   1365                   bounding rectangle for a string.
   1366     @param  miny  Pointer to minimum Y coord, passed in AND returned.
   1367     @param  maxx  Pointer to maximum X coord, passed in AND returned.
   1368     @param  maxy  Pointer to maximum Y coord, passed in AND returned.
   1369 */
   1370 /**************************************************************************/
   1371 void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y,
   1372                               int16_t *minx, int16_t *miny, int16_t *maxx,
   1373                               int16_t *maxy) {
   1374 
   1375   if (gfxFont) {
   1376 
   1377     if (c == '\n') { // Newline?
   1378       *x = 0;        // Reset x to zero, advance y by one line
   1379       *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   1380     } else if (c != '\r') { // Not a carriage return; is normal char
   1381       uint8_t first = pgm_read_byte(&gfxFont->first),
   1382               last = pgm_read_byte(&gfxFont->last);
   1383       if ((c >= first) && (c <= last)) { // Char present in this font?
   1384         GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
   1385         uint8_t gw = pgm_read_byte(&glyph->width),
   1386                 gh = pgm_read_byte(&glyph->height),
   1387                 xa = pgm_read_byte(&glyph->xAdvance);
   1388         int8_t xo = pgm_read_byte(&glyph->xOffset),
   1389                yo = pgm_read_byte(&glyph->yOffset);
   1390         if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x)) > _width)) {
   1391           *x = 0; // Reset x to zero, advance y by one line
   1392           *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   1393         }
   1394         int16_t tsx = (int16_t)textsize_x, tsy = (int16_t)textsize_y,
   1395                 x1 = *x + xo * tsx, y1 = *y + yo * tsy, x2 = x1 + gw * tsx - 1,
   1396                 y2 = y1 + gh * tsy - 1;
   1397         if (x1 < *minx)
   1398           *minx = x1;
   1399         if (y1 < *miny)
   1400           *miny = y1;
   1401         if (x2 > *maxx)
   1402           *maxx = x2;
   1403         if (y2 > *maxy)
   1404           *maxy = y2;
   1405         *x += xa * tsx;
   1406       }
   1407     }
   1408 
   1409   } else { // Default font
   1410 
   1411     if (c == '\n') {        // Newline?
   1412       *x = 0;               // Reset x to zero,
   1413       *y += textsize_y * 8; // advance y one line
   1414       // min/max x/y unchaged -- that waits for next 'normal' character
   1415     } else if (c != '\r') { // Normal char; ignore carriage returns
   1416       if (wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
   1417         *x = 0;                                       // Reset x to zero,
   1418         *y += textsize_y * 8;                         // advance y one line
   1419       }
   1420       int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
   1421           y2 = *y + textsize_y * 8 - 1;
   1422       if (x2 > *maxx)
   1423         *maxx = x2; // Track max x, y
   1424       if (y2 > *maxy)
   1425         *maxy = y2;
   1426       if (*x < *minx)
   1427         *minx = *x; // Track min x, y
   1428       if (*y < *miny)
   1429         *miny = *y;
   1430       *x += textsize_x * 6; // Advance x one char
   1431     }
   1432   }
   1433 }
   1434 
   1435 /**************************************************************************/
   1436 /*!
   1437     @brief  Helper to determine size of a string with current font/size.
   1438             Pass string and a cursor position, returns UL corner and W,H.
   1439     @param  str  The ASCII string to measure
   1440     @param  x    The current cursor X
   1441     @param  y    The current cursor Y
   1442     @param  x1   The boundary X coordinate, returned by function
   1443     @param  y1   The boundary Y coordinate, returned by function
   1444     @param  w    The boundary width, returned by function
   1445     @param  h    The boundary height, returned by function
   1446 */
   1447 /**************************************************************************/
   1448 void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
   1449                                  int16_t *x1, int16_t *y1, uint16_t *w,
   1450                                  uint16_t *h) {
   1451 
   1452   uint8_t c; // Current character
   1453   int16_t minx = 0x7FFF, miny = 0x7FFF, maxx = -1, maxy = -1; // Bound rect
   1454   // Bound rect is intentionally initialized inverted, so 1st char sets it
   1455 
   1456   *x1 = x; // Initial position is value passed in
   1457   *y1 = y;
   1458   *w = *h = 0; // Initial size is zero
   1459 
   1460   while ((c = *str++)) {
   1461     // charBounds() modifies x/y to advance for each character,
   1462     // and min/max x/y are updated to incrementally build bounding rect.
   1463     charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
   1464   }
   1465 
   1466   if (maxx >= minx) {     // If legit string bounds were found...
   1467     *x1 = minx;           // Update x1 to least X coord,
   1468     *w = maxx - minx + 1; // And w to bound rect width
   1469   }
   1470   if (maxy >= miny) { // Same for height
   1471     *y1 = miny;
   1472     *h = maxy - miny + 1;
   1473   }
   1474 }
   1475 
   1476 /**************************************************************************/
   1477 /*!
   1478     @brief    Helper to determine size of a string with current font/size. Pass
   1479    string and a cursor position, returns UL corner and W,H.
   1480     @param    str    The ascii string to measure (as an arduino String() class)
   1481     @param    x      The current cursor X
   1482     @param    y      The current cursor Y
   1483     @param    x1     The boundary X coordinate, set by function
   1484     @param    y1     The boundary Y coordinate, set by function
   1485     @param    w      The boundary width, set by function
   1486     @param    h      The boundary height, set by function
   1487 */
   1488 /**************************************************************************/
   1489 void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
   1490                                  int16_t *x1, int16_t *y1, uint16_t *w,
   1491                                  uint16_t *h) {
   1492   if (str.length() != 0) {
   1493     getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h);
   1494   }
   1495 }
   1496 
   1497 /**************************************************************************/
   1498 /*!
   1499     @brief    Helper to determine size of a PROGMEM string with current
   1500    font/size. Pass string and a cursor position, returns UL corner and W,H.
   1501     @param    str     The flash-memory ascii string to measure
   1502     @param    x       The current cursor X
   1503     @param    y       The current cursor Y
   1504     @param    x1      The boundary X coordinate, set by function
   1505     @param    y1      The boundary Y coordinate, set by function
   1506     @param    w      The boundary width, set by function
   1507     @param    h      The boundary height, set by function
   1508 */
   1509 /**************************************************************************/
   1510 void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x,
   1511                                  int16_t y, int16_t *x1, int16_t *y1,
   1512                                  uint16_t *w, uint16_t *h) {
   1513   uint8_t *s = (uint8_t *)str, c;
   1514 
   1515   *x1 = x;
   1516   *y1 = y;
   1517   *w = *h = 0;
   1518 
   1519   int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
   1520 
   1521   while ((c = pgm_read_byte(s++)))
   1522     charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
   1523 
   1524   if (maxx >= minx) {
   1525     *x1 = minx;
   1526     *w = maxx - minx + 1;
   1527   }
   1528   if (maxy >= miny) {
   1529     *y1 = miny;
   1530     *h = maxy - miny + 1;
   1531   }
   1532 }
   1533 
   1534 /**************************************************************************/
   1535 /*!
   1536     @brief      Invert the display (ideally using built-in hardware command)
   1537     @param   i  True if you want to invert, false to make 'normal'
   1538 */
   1539 /**************************************************************************/
   1540 void Adafruit_GFX::invertDisplay(bool i) {
   1541   // Do nothing, must be subclassed if supported by hardware
   1542   (void)i; // disable -Wunused-parameter warning
   1543 }
   1544 
   1545 /***************************************************************************/
   1546 
   1547 /**************************************************************************/
   1548 /*!
   1549    @brief    Create a simple drawn button UI element
   1550 */
   1551 /**************************************************************************/
   1552 Adafruit_GFX_Button::Adafruit_GFX_Button(void) { _gfx = 0; }
   1553 
   1554 /**************************************************************************/
   1555 /*!
   1556    @brief    Initialize button with our desired color/size/settings
   1557    @param    gfx     Pointer to our display so we can draw to it!
   1558    @param    x       The X coordinate of the center of the button
   1559    @param    y       The Y coordinate of the center of the button
   1560    @param    w       Width of the buttton
   1561    @param    h       Height of the buttton
   1562    @param    outline  Color of the outline (16-bit 5-6-5 standard)
   1563    @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   1564    @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   1565    @param    label  Ascii string of the text inside the button
   1566    @param    textsize The font magnification of the label text
   1567 */
   1568 /**************************************************************************/
   1569 // Classic initButton() function: pass center & size
   1570 void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
   1571                                      uint16_t w, uint16_t h, uint16_t outline,
   1572                                      uint16_t fill, uint16_t textcolor,
   1573                                      char *label, uint8_t textsize) {
   1574   // Tweak arguments and pass to the newer initButtonUL() function...
   1575   initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor,
   1576                label, textsize);
   1577 }
   1578 
   1579 /**************************************************************************/
   1580 /*!
   1581    @brief    Initialize button with our desired color/size/settings
   1582    @param    gfx     Pointer to our display so we can draw to it!
   1583    @param    x       The X coordinate of the center of the button
   1584    @param    y       The Y coordinate of the center of the button
   1585    @param    w       Width of the buttton
   1586    @param    h       Height of the buttton
   1587    @param    outline  Color of the outline (16-bit 5-6-5 standard)
   1588    @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   1589    @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   1590    @param    label  Ascii string of the text inside the button
   1591    @param    textsize_x The font magnification in X-axis of the label text
   1592    @param    textsize_y The font magnification in Y-axis of the label text
   1593 */
   1594 /**************************************************************************/
   1595 // Classic initButton() function: pass center & size
   1596 void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
   1597                                      uint16_t w, uint16_t h, uint16_t outline,
   1598                                      uint16_t fill, uint16_t textcolor,
   1599                                      char *label, uint8_t textsize_x,
   1600                                      uint8_t textsize_y) {
   1601   // Tweak arguments and pass to the newer initButtonUL() function...
   1602   initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor,
   1603                label, textsize_x, textsize_y);
   1604 }
   1605 
   1606 /**************************************************************************/
   1607 /*!
   1608    @brief    Initialize button with our desired color/size/settings, with
   1609    upper-left coordinates
   1610    @param    gfx     Pointer to our display so we can draw to it!
   1611    @param    x1       The X coordinate of the Upper-Left corner of the button
   1612    @param    y1       The Y coordinate of the Upper-Left corner of the button
   1613    @param    w       Width of the buttton
   1614    @param    h       Height of the buttton
   1615    @param    outline  Color of the outline (16-bit 5-6-5 standard)
   1616    @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   1617    @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   1618    @param    label  Ascii string of the text inside the button
   1619    @param    textsize The font magnification of the label text
   1620 */
   1621 /**************************************************************************/
   1622 void Adafruit_GFX_Button::initButtonUL(Adafruit_GFX *gfx, int16_t x1,
   1623                                        int16_t y1, uint16_t w, uint16_t h,
   1624                                        uint16_t outline, uint16_t fill,
   1625                                        uint16_t textcolor, char *label,
   1626                                        uint8_t textsize) {
   1627   initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize,
   1628                textsize);
   1629 }
   1630 
   1631 /**************************************************************************/
   1632 /*!
   1633    @brief    Initialize button with our desired color/size/settings, with
   1634    upper-left coordinates
   1635    @param    gfx     Pointer to our display so we can draw to it!
   1636    @param    x1       The X coordinate of the Upper-Left corner of the button
   1637    @param    y1       The Y coordinate of the Upper-Left corner of the button
   1638    @param    w       Width of the buttton
   1639    @param    h       Height of the buttton
   1640    @param    outline  Color of the outline (16-bit 5-6-5 standard)
   1641    @param    fill  Color of the button fill (16-bit 5-6-5 standard)
   1642    @param    textcolor  Color of the button label (16-bit 5-6-5 standard)
   1643    @param    label  Ascii string of the text inside the button
   1644    @param    textsize_x The font magnification in X-axis of the label text
   1645    @param    textsize_y The font magnification in Y-axis of the label text
   1646 */
   1647 /**************************************************************************/
   1648 void Adafruit_GFX_Button::initButtonUL(Adafruit_GFX *gfx, int16_t x1,
   1649                                        int16_t y1, uint16_t w, uint16_t h,
   1650                                        uint16_t outline, uint16_t fill,
   1651                                        uint16_t textcolor, char *label,
   1652                                        uint8_t textsize_x, uint8_t textsize_y) {
   1653   _x1 = x1;
   1654   _y1 = y1;
   1655   _w = w;
   1656   _h = h;
   1657   _outlinecolor = outline;
   1658   _fillcolor = fill;
   1659   _textcolor = textcolor;
   1660   _textsize_x = textsize_x;
   1661   _textsize_y = textsize_y;
   1662   _gfx = gfx;
   1663   strncpy(_label, label, 9);
   1664 }
   1665 
   1666 /**************************************************************************/
   1667 /*!
   1668    @brief    Draw the button on the screen
   1669    @param    inverted Whether to draw with fill/text swapped to indicate
   1670    'pressed'
   1671 */
   1672 /**************************************************************************/
   1673 void Adafruit_GFX_Button::drawButton(bool inverted) {
   1674   uint16_t fill, outline, text;
   1675 
   1676   if (!inverted) {
   1677     fill = _fillcolor;
   1678     outline = _outlinecolor;
   1679     text = _textcolor;
   1680   } else {
   1681     fill = _textcolor;
   1682     outline = _outlinecolor;
   1683     text = _fillcolor;
   1684   }
   1685 
   1686   uint8_t r = min(_w, _h) / 4; // Corner radius
   1687   _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
   1688   _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);
   1689 
   1690   _gfx->setCursor(_x1 + (_w / 2) - (strlen(_label) * 3 * _textsize_x),
   1691                   _y1 + (_h / 2) - (4 * _textsize_y));
   1692   _gfx->setTextColor(text);
   1693   _gfx->setTextSize(_textsize_x, _textsize_y);
   1694   _gfx->print(_label);
   1695 }
   1696 
   1697 /**************************************************************************/
   1698 /*!
   1699     @brief    Helper to let us know if a coordinate is within the bounds of the
   1700    button
   1701     @param    x       The X coordinate to check
   1702     @param    y       The Y coordinate to check
   1703     @returns  True if within button graphics outline
   1704 */
   1705 /**************************************************************************/
   1706 bool Adafruit_GFX_Button::contains(int16_t x, int16_t y) {
   1707   return ((x >= _x1) && (x < (int16_t)(_x1 + _w)) && (y >= _y1) &&
   1708           (y < (int16_t)(_y1 + _h)));
   1709 }
   1710 
   1711 /**************************************************************************/
   1712 /*!
   1713    @brief    Query whether the button was pressed since we last checked state
   1714    @returns  True if was not-pressed before, now is.
   1715 */
   1716 /**************************************************************************/
   1717 bool Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }
   1718 
   1719 /**************************************************************************/
   1720 /*!
   1721    @brief    Query whether the button was released since we last checked state
   1722    @returns  True if was pressed before, now is not.
   1723 */
   1724 /**************************************************************************/
   1725 bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
   1726 
   1727 // -------------------------------------------------------------------------
   1728 
   1729 // GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too
   1730 // comfy with the implementation) provide 1-, 8- and 16-bit offscreen
   1731 // canvases, the address of which can be passed to drawBitmap() or
   1732 // pushColors() (the latter appears only in a couple of GFX-subclassed TFT
   1733 // libraries at this time).  This is here mostly to help with the recently-
   1734 // added proportionally-spaced fonts; adds a way to refresh a section of the
   1735 // screen without a massive flickering clear-and-redraw...but maybe you'll
   1736 // find other uses too.  VERY RAM-intensive, since the buffer is in MCU
   1737 // memory and not the display driver...GXFcanvas1 might be minimally useful
   1738 // on an Uno-class board, but this and the others are much more likely to
   1739 // require at least a Mega or various recent ARM-type boards (recommended,
   1740 // as the text+bitmap draw can be pokey).  GFXcanvas1 requires 1 bit per
   1741 // pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte
   1742 // per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no
   1743 // scanline pad).
   1744 // NOT EXTENSIVELY TESTED YET.  MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
   1745 
   1746 #ifdef __AVR__
   1747 // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
   1748 const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
   1749                                                  0x08, 0x04, 0x02, 0x01};
   1750 const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
   1751                                                  0xF7, 0xFB, 0xFD, 0xFE};
   1752 #endif
   1753 
   1754 /**************************************************************************/
   1755 /*!
   1756    @brief    Instatiate a GFX 1-bit canvas context for graphics
   1757    @param    w   Display width, in pixels
   1758    @param    h   Display height, in pixels
   1759 */
   1760 /**************************************************************************/
   1761 GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
   1762   uint16_t bytes = ((w + 7) / 8) * h;
   1763   if ((buffer = (uint8_t *)malloc(bytes))) {
   1764     memset(buffer, 0, bytes);
   1765   }
   1766 }
   1767 
   1768 /**************************************************************************/
   1769 /*!
   1770    @brief    Delete the canvas, free memory
   1771 */
   1772 /**************************************************************************/
   1773 GFXcanvas1::~GFXcanvas1(void) {
   1774   if (buffer)
   1775     free(buffer);
   1776 }
   1777 
   1778 /**************************************************************************/
   1779 /*!
   1780     @brief  Draw a pixel to the canvas framebuffer
   1781     @param  x     x coordinate
   1782     @param  y     y coordinate
   1783     @param  color Binary (on or off) color to fill with
   1784 */
   1785 /**************************************************************************/
   1786 void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
   1787   if (buffer) {
   1788     if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
   1789       return;
   1790 
   1791     int16_t t;
   1792     switch (rotation) {
   1793     case 1:
   1794       t = x;
   1795       x = WIDTH - 1 - y;
   1796       y = t;
   1797       break;
   1798     case 2:
   1799       x = WIDTH - 1 - x;
   1800       y = HEIGHT - 1 - y;
   1801       break;
   1802     case 3:
   1803       t = x;
   1804       x = y;
   1805       y = HEIGHT - 1 - t;
   1806       break;
   1807     }
   1808 
   1809     uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
   1810 #ifdef __AVR__
   1811     if (color)
   1812       *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
   1813     else
   1814       *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
   1815 #else
   1816     if (color)
   1817       *ptr |= 0x80 >> (x & 7);
   1818     else
   1819       *ptr &= ~(0x80 >> (x & 7));
   1820 #endif
   1821   }
   1822 }
   1823 
   1824 /**********************************************************************/
   1825 /*!
   1826         @brief    Get the pixel color value at a given coordinate
   1827         @param    x   x coordinate
   1828         @param    y   y coordinate
   1829         @returns  The desired pixel's binary color value, either 0x1 (on) or 0x0
   1830    (off)
   1831 */
   1832 /**********************************************************************/
   1833 bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
   1834   int16_t t;
   1835   switch (rotation) {
   1836   case 1:
   1837     t = x;
   1838     x = WIDTH - 1 - y;
   1839     y = t;
   1840     break;
   1841   case 2:
   1842     x = WIDTH - 1 - x;
   1843     y = HEIGHT - 1 - y;
   1844     break;
   1845   case 3:
   1846     t = x;
   1847     x = y;
   1848     y = HEIGHT - 1 - t;
   1849     break;
   1850   }
   1851   return getRawPixel(x, y);
   1852 }
   1853 
   1854 /**********************************************************************/
   1855 /*!
   1856         @brief    Get the pixel color value at a given, unrotated coordinate.
   1857               This method is intended for hardware drivers to get pixel value
   1858               in physical coordinates.
   1859         @param    x   x coordinate
   1860         @param    y   y coordinate
   1861         @returns  The desired pixel's binary color value, either 0x1 (on) or 0x0
   1862    (off)
   1863 */
   1864 /**********************************************************************/
   1865 bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
   1866   if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
   1867     return 0;
   1868   if (this->getBuffer()) {
   1869     uint8_t *buffer = this->getBuffer();
   1870     uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
   1871 
   1872 #ifdef __AVR__
   1873     return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
   1874 #else
   1875     return ((*ptr) & (0x80 >> (x & 7))) != 0;
   1876 #endif
   1877   }
   1878   return 0;
   1879 }
   1880 
   1881 /**************************************************************************/
   1882 /*!
   1883     @brief  Fill the framebuffer completely with one color
   1884     @param  color Binary (on or off) color to fill with
   1885 */
   1886 /**************************************************************************/
   1887 void GFXcanvas1::fillScreen(uint16_t color) {
   1888   if (buffer) {
   1889     uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
   1890     memset(buffer, color ? 0xFF : 0x00, bytes);
   1891   }
   1892 }
   1893 
   1894 /**************************************************************************/
   1895 /*!
   1896    @brief  Speed optimized vertical line drawing
   1897    @param  x      Line horizontal start point
   1898    @param  y      Line vertical start point
   1899    @param  h      Length of vertical line to be drawn, including first point
   1900    @param  color  Color to fill with
   1901 */
   1902 /**************************************************************************/
   1903 void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h,
   1904                                uint16_t color) {
   1905 
   1906   if (h < 0) { // Convert negative heights to positive equivalent
   1907     h *= -1;
   1908     y -= h - 1;
   1909     if (y < 0) {
   1910       h += y;
   1911       y = 0;
   1912     }
   1913   }
   1914 
   1915   // Edge rejection (no-draw if totally off canvas)
   1916   if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
   1917     return;
   1918   }
   1919 
   1920   if (y < 0) { // Clip top
   1921     h += y;
   1922     y = 0;
   1923   }
   1924   if (y + h > height()) { // Clip bottom
   1925     h = height() - y;
   1926   }
   1927 
   1928   if (getRotation() == 0) {
   1929     drawFastRawVLine(x, y, h, color);
   1930   } else if (getRotation() == 1) {
   1931     int16_t t = x;
   1932     x = WIDTH - 1 - y;
   1933     y = t;
   1934     x -= h - 1;
   1935     drawFastRawHLine(x, y, h, color);
   1936   } else if (getRotation() == 2) {
   1937     x = WIDTH - 1 - x;
   1938     y = HEIGHT - 1 - y;
   1939 
   1940     y -= h - 1;
   1941     drawFastRawVLine(x, y, h, color);
   1942   } else if (getRotation() == 3) {
   1943     int16_t t = x;
   1944     x = y;
   1945     y = HEIGHT - 1 - t;
   1946     drawFastRawHLine(x, y, h, color);
   1947   }
   1948 }
   1949 
   1950 /**************************************************************************/
   1951 /*!
   1952    @brief  Speed optimized horizontal line drawing
   1953    @param  x      Line horizontal start point
   1954    @param  y      Line vertical start point
   1955    @param  w      Length of horizontal line to be drawn, including first point
   1956    @param  color  Color to fill with
   1957 */
   1958 /**************************************************************************/
   1959 void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w,
   1960                                uint16_t color) {
   1961   if (w < 0) { // Convert negative widths to positive equivalent
   1962     w *= -1;
   1963     x -= w - 1;
   1964     if (x < 0) {
   1965       w += x;
   1966       x = 0;
   1967     }
   1968   }
   1969 
   1970   // Edge rejection (no-draw if totally off canvas)
   1971   if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
   1972     return;
   1973   }
   1974 
   1975   if (x < 0) { // Clip left
   1976     w += x;
   1977     x = 0;
   1978   }
   1979   if (x + w >= width()) { // Clip right
   1980     w = width() - x;
   1981   }
   1982 
   1983   if (getRotation() == 0) {
   1984     drawFastRawHLine(x, y, w, color);
   1985   } else if (getRotation() == 1) {
   1986     int16_t t = x;
   1987     x = WIDTH - 1 - y;
   1988     y = t;
   1989     drawFastRawVLine(x, y, w, color);
   1990   } else if (getRotation() == 2) {
   1991     x = WIDTH - 1 - x;
   1992     y = HEIGHT - 1 - y;
   1993 
   1994     x -= w - 1;
   1995     drawFastRawHLine(x, y, w, color);
   1996   } else if (getRotation() == 3) {
   1997     int16_t t = x;
   1998     x = y;
   1999     y = HEIGHT - 1 - t;
   2000     y -= w - 1;
   2001     drawFastRawVLine(x, y, w, color);
   2002   }
   2003 }
   2004 
   2005 /**************************************************************************/
   2006 /*!
   2007    @brief    Speed optimized vertical line drawing into the raw canvas buffer
   2008    @param    x   Line horizontal start point
   2009    @param    y   Line vertical start point
   2010    @param    h   length of vertical line to be drawn, including first point
   2011    @param    color   Binary (on or off) color to fill with
   2012 */
   2013 /**************************************************************************/
   2014 void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
   2015                                   uint16_t color) {
   2016   // x & y already in raw (rotation 0) coordinates, no need to transform.
   2017   int16_t row_bytes = ((WIDTH + 7) / 8);
   2018   uint8_t *buffer = this->getBuffer();
   2019   uint8_t *ptr = &buffer[(x / 8) + y * row_bytes];
   2020 
   2021   if (color > 0) {
   2022 #ifdef __AVR__
   2023     uint8_t bit_mask = pgm_read_byte(&GFXsetBit[x & 7]);
   2024 #else
   2025     uint8_t bit_mask = (0x80 >> (x & 7));
   2026 #endif
   2027     for (int16_t i = 0; i < h; i++) {
   2028       *ptr |= bit_mask;
   2029       ptr += row_bytes;
   2030     }
   2031   } else {
   2032 #ifdef __AVR__
   2033     uint8_t bit_mask = pgm_read_byte(&GFXclrBit[x & 7]);
   2034 #else
   2035     uint8_t bit_mask = ~(0x80 >> (x & 7));
   2036 #endif
   2037     for (int16_t i = 0; i < h; i++) {
   2038       *ptr &= bit_mask;
   2039       ptr += row_bytes;
   2040     }
   2041   }
   2042 }
   2043 
   2044 /**************************************************************************/
   2045 /*!
   2046    @brief    Speed optimized horizontal line drawing into the raw canvas buffer
   2047    @param    x   Line horizontal start point
   2048    @param    y   Line vertical start point
   2049    @param    w   length of horizontal line to be drawn, including first point
   2050    @param    color   Binary (on or off) color to fill with
   2051 */
   2052 /**************************************************************************/
   2053 void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
   2054                                   uint16_t color) {
   2055   // x & y already in raw (rotation 0) coordinates, no need to transform.
   2056   int16_t rowBytes = ((WIDTH + 7) / 8);
   2057   uint8_t *buffer = this->getBuffer();
   2058   uint8_t *ptr = &buffer[(x / 8) + y * rowBytes];
   2059   size_t remainingWidthBits = w;
   2060 
   2061   // check to see if first byte needs to be partially filled
   2062   if ((x & 7) > 0) {
   2063     // create bit mask for first byte
   2064     uint8_t startByteBitMask = 0x00;
   2065     for (int8_t i = (x & 7); ((i < 8) && (remainingWidthBits > 0)); i++) {
   2066 #ifdef __AVR__
   2067       startByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
   2068 #else
   2069       startByteBitMask |= (0x80 >> i);
   2070 #endif
   2071       remainingWidthBits--;
   2072     }
   2073     if (color > 0) {
   2074       *ptr |= startByteBitMask;
   2075     } else {
   2076       *ptr &= ~startByteBitMask;
   2077     }
   2078 
   2079     ptr++;
   2080   }
   2081 
   2082   // do the next remainingWidthBits bits
   2083   if (remainingWidthBits > 0) {
   2084     size_t remainingWholeBytes = remainingWidthBits / 8;
   2085     size_t lastByteBits = remainingWidthBits % 8;
   2086     uint8_t wholeByteColor = color > 0 ? 0xFF : 0x00;
   2087 
   2088     memset(ptr, wholeByteColor, remainingWholeBytes);
   2089 
   2090     if (lastByteBits > 0) {
   2091       uint8_t lastByteBitMask = 0x00;
   2092       for (size_t i = 0; i < lastByteBits; i++) {
   2093 #ifdef __AVR__
   2094         lastByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
   2095 #else
   2096         lastByteBitMask |= (0x80 >> i);
   2097 #endif
   2098       }
   2099       ptr += remainingWholeBytes;
   2100 
   2101       if (color > 0) {
   2102         *ptr |= lastByteBitMask;
   2103       } else {
   2104         *ptr &= ~lastByteBitMask;
   2105       }
   2106     }
   2107   }
   2108 }
   2109 
   2110 /**************************************************************************/
   2111 /*!
   2112    @brief    Instatiate a GFX 8-bit canvas context for graphics
   2113    @param    w   Display width, in pixels
   2114    @param    h   Display height, in pixels
   2115 */
   2116 /**************************************************************************/
   2117 GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
   2118   uint32_t bytes = w * h;
   2119   if ((buffer = (uint8_t *)malloc(bytes))) {
   2120     memset(buffer, 0, bytes);
   2121   }
   2122 }
   2123 
   2124 /**************************************************************************/
   2125 /*!
   2126    @brief    Delete the canvas, free memory
   2127 */
   2128 /**************************************************************************/
   2129 GFXcanvas8::~GFXcanvas8(void) {
   2130   if (buffer)
   2131     free(buffer);
   2132 }
   2133 
   2134 /**************************************************************************/
   2135 /*!
   2136     @brief  Draw a pixel to the canvas framebuffer
   2137     @param  x   x coordinate
   2138     @param  y   y coordinate
   2139     @param  color 8-bit Color to fill with. Only lower byte of uint16_t is used.
   2140 */
   2141 /**************************************************************************/
   2142 void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
   2143   if (buffer) {
   2144     if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
   2145       return;
   2146 
   2147     int16_t t;
   2148     switch (rotation) {
   2149     case 1:
   2150       t = x;
   2151       x = WIDTH - 1 - y;
   2152       y = t;
   2153       break;
   2154     case 2:
   2155       x = WIDTH - 1 - x;
   2156       y = HEIGHT - 1 - y;
   2157       break;
   2158     case 3:
   2159       t = x;
   2160       x = y;
   2161       y = HEIGHT - 1 - t;
   2162       break;
   2163     }
   2164 
   2165     buffer[x + y * WIDTH] = color;
   2166   }
   2167 }
   2168 
   2169 /**********************************************************************/
   2170 /*!
   2171         @brief    Get the pixel color value at a given coordinate
   2172         @param    x   x coordinate
   2173         @param    y   y coordinate
   2174         @returns  The desired pixel's 8-bit color value
   2175 */
   2176 /**********************************************************************/
   2177 uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
   2178   int16_t t;
   2179   switch (rotation) {
   2180   case 1:
   2181     t = x;
   2182     x = WIDTH - 1 - y;
   2183     y = t;
   2184     break;
   2185   case 2:
   2186     x = WIDTH - 1 - x;
   2187     y = HEIGHT - 1 - y;
   2188     break;
   2189   case 3:
   2190     t = x;
   2191     x = y;
   2192     y = HEIGHT - 1 - t;
   2193     break;
   2194   }
   2195   return getRawPixel(x, y);
   2196 }
   2197 
   2198 /**********************************************************************/
   2199 /*!
   2200         @brief    Get the pixel color value at a given, unrotated coordinate.
   2201               This method is intended for hardware drivers to get pixel value
   2202               in physical coordinates.
   2203         @param    x   x coordinate
   2204         @param    y   y coordinate
   2205         @returns  The desired pixel's 8-bit color value
   2206 */
   2207 /**********************************************************************/
   2208 uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
   2209   if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
   2210     return 0;
   2211   if (buffer) {
   2212     return buffer[x + y * WIDTH];
   2213   }
   2214   return 0;
   2215 }
   2216 
   2217 /**************************************************************************/
   2218 /*!
   2219     @brief  Fill the framebuffer completely with one color
   2220     @param  color 8-bit Color to fill with. Only lower byte of uint16_t is used.
   2221 */
   2222 /**************************************************************************/
   2223 void GFXcanvas8::fillScreen(uint16_t color) {
   2224   if (buffer) {
   2225     memset(buffer, color, WIDTH * HEIGHT);
   2226   }
   2227 }
   2228 
   2229 /**************************************************************************/
   2230 /*!
   2231    @brief  Speed optimized vertical line drawing
   2232    @param  x      Line horizontal start point
   2233    @param  y      Line vertical start point
   2234    @param  h      Length of vertical line to be drawn, including first point
   2235    @param  color  8-bit Color to fill with. Only lower byte of uint16_t is
   2236                   used.
   2237 */
   2238 /**************************************************************************/
   2239 void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h,
   2240                                uint16_t color) {
   2241   if (h < 0) { // Convert negative heights to positive equivalent
   2242     h *= -1;
   2243     y -= h - 1;
   2244     if (y < 0) {
   2245       h += y;
   2246       y = 0;
   2247     }
   2248   }
   2249 
   2250   // Edge rejection (no-draw if totally off canvas)
   2251   if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
   2252     return;
   2253   }
   2254 
   2255   if (y < 0) { // Clip top
   2256     h += y;
   2257     y = 0;
   2258   }
   2259   if (y + h > height()) { // Clip bottom
   2260     h = height() - y;
   2261   }
   2262 
   2263   if (getRotation() == 0) {
   2264     drawFastRawVLine(x, y, h, color);
   2265   } else if (getRotation() == 1) {
   2266     int16_t t = x;
   2267     x = WIDTH - 1 - y;
   2268     y = t;
   2269     x -= h - 1;
   2270     drawFastRawHLine(x, y, h, color);
   2271   } else if (getRotation() == 2) {
   2272     x = WIDTH - 1 - x;
   2273     y = HEIGHT - 1 - y;
   2274 
   2275     y -= h - 1;
   2276     drawFastRawVLine(x, y, h, color);
   2277   } else if (getRotation() == 3) {
   2278     int16_t t = x;
   2279     x = y;
   2280     y = HEIGHT - 1 - t;
   2281     drawFastRawHLine(x, y, h, color);
   2282   }
   2283 }
   2284 
   2285 /**************************************************************************/
   2286 /*!
   2287    @brief  Speed optimized horizontal line drawing
   2288    @param  x      Line horizontal start point
   2289    @param  y      Line vertical start point
   2290    @param  w      Length of horizontal line to be drawn, including 1st point
   2291    @param  color  8-bit Color to fill with. Only lower byte of uint16_t is
   2292                   used.
   2293 */
   2294 /**************************************************************************/
   2295 void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w,
   2296                                uint16_t color) {
   2297 
   2298   if (w < 0) { // Convert negative widths to positive equivalent
   2299     w *= -1;
   2300     x -= w - 1;
   2301     if (x < 0) {
   2302       w += x;
   2303       x = 0;
   2304     }
   2305   }
   2306 
   2307   // Edge rejection (no-draw if totally off canvas)
   2308   if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
   2309     return;
   2310   }
   2311 
   2312   if (x < 0) { // Clip left
   2313     w += x;
   2314     x = 0;
   2315   }
   2316   if (x + w >= width()) { // Clip right
   2317     w = width() - x;
   2318   }
   2319 
   2320   if (getRotation() == 0) {
   2321     drawFastRawHLine(x, y, w, color);
   2322   } else if (getRotation() == 1) {
   2323     int16_t t = x;
   2324     x = WIDTH - 1 - y;
   2325     y = t;
   2326     drawFastRawVLine(x, y, w, color);
   2327   } else if (getRotation() == 2) {
   2328     x = WIDTH - 1 - x;
   2329     y = HEIGHT - 1 - y;
   2330 
   2331     x -= w - 1;
   2332     drawFastRawHLine(x, y, w, color);
   2333   } else if (getRotation() == 3) {
   2334     int16_t t = x;
   2335     x = y;
   2336     y = HEIGHT - 1 - t;
   2337     y -= w - 1;
   2338     drawFastRawVLine(x, y, w, color);
   2339   }
   2340 }
   2341 
   2342 /**************************************************************************/
   2343 /*!
   2344    @brief    Speed optimized vertical line drawing into the raw canvas buffer
   2345    @param    x   Line horizontal start point
   2346    @param    y   Line vertical start point
   2347    @param    h   length of vertical line to be drawn, including first point
   2348    @param    color   8-bit Color to fill with. Only lower byte of uint16_t is
   2349    used.
   2350 */
   2351 /**************************************************************************/
   2352 void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
   2353                                   uint16_t color) {
   2354   // x & y already in raw (rotation 0) coordinates, no need to transform.
   2355   uint8_t *buffer_ptr = buffer + y * WIDTH + x;
   2356   for (int16_t i = 0; i < h; i++) {
   2357     (*buffer_ptr) = color;
   2358     buffer_ptr += WIDTH;
   2359   }
   2360 }
   2361 
   2362 /**************************************************************************/
   2363 /*!
   2364    @brief    Speed optimized horizontal line drawing into the raw canvas buffer
   2365    @param    x   Line horizontal start point
   2366    @param    y   Line vertical start point
   2367    @param    w   length of horizontal line to be drawn, including first point
   2368    @param    color   8-bit Color to fill with. Only lower byte of uint16_t is
   2369    used.
   2370 */
   2371 /**************************************************************************/
   2372 void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
   2373                                   uint16_t color) {
   2374   // x & y already in raw (rotation 0) coordinates, no need to transform.
   2375   memset(buffer + y * WIDTH + x, color, w);
   2376 }
   2377 
   2378 /**************************************************************************/
   2379 /*!
   2380    @brief    Instatiate a GFX 16-bit canvas context for graphics
   2381    @param    w   Display width, in pixels
   2382    @param    h   Display height, in pixels
   2383 */
   2384 /**************************************************************************/
   2385 GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
   2386   uint32_t bytes = w * h * 2;
   2387   if ((buffer = (uint16_t *)malloc(bytes))) {
   2388     memset(buffer, 0, bytes);
   2389   }
   2390 }
   2391 
   2392 /**************************************************************************/
   2393 /*!
   2394    @brief    Delete the canvas, free memory
   2395 */
   2396 /**************************************************************************/
   2397 GFXcanvas16::~GFXcanvas16(void) {
   2398   if (buffer)
   2399     free(buffer);
   2400 }
   2401 
   2402 /**************************************************************************/
   2403 /*!
   2404     @brief  Draw a pixel to the canvas framebuffer
   2405     @param  x   x coordinate
   2406     @param  y   y coordinate
   2407     @param  color 16-bit 5-6-5 Color to fill with
   2408 */
   2409 /**************************************************************************/
   2410 void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
   2411   if (buffer) {
   2412     if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
   2413       return;
   2414 
   2415     int16_t t;
   2416     switch (rotation) {
   2417     case 1:
   2418       t = x;
   2419       x = WIDTH - 1 - y;
   2420       y = t;
   2421       break;
   2422     case 2:
   2423       x = WIDTH - 1 - x;
   2424       y = HEIGHT - 1 - y;
   2425       break;
   2426     case 3:
   2427       t = x;
   2428       x = y;
   2429       y = HEIGHT - 1 - t;
   2430       break;
   2431     }
   2432 
   2433     buffer[x + y * WIDTH] = color;
   2434   }
   2435 }
   2436 
   2437 /**********************************************************************/
   2438 /*!
   2439         @brief    Get the pixel color value at a given coordinate
   2440         @param    x   x coordinate
   2441         @param    y   y coordinate
   2442         @returns  The desired pixel's 16-bit 5-6-5 color value
   2443 */
   2444 /**********************************************************************/
   2445 uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
   2446   int16_t t;
   2447   switch (rotation) {
   2448   case 1:
   2449     t = x;
   2450     x = WIDTH - 1 - y;
   2451     y = t;
   2452     break;
   2453   case 2:
   2454     x = WIDTH - 1 - x;
   2455     y = HEIGHT - 1 - y;
   2456     break;
   2457   case 3:
   2458     t = x;
   2459     x = y;
   2460     y = HEIGHT - 1 - t;
   2461     break;
   2462   }
   2463   return getRawPixel(x, y);
   2464 }
   2465 
   2466 /**********************************************************************/
   2467 /*!
   2468         @brief    Get the pixel color value at a given, unrotated coordinate.
   2469               This method is intended for hardware drivers to get pixel value
   2470               in physical coordinates.
   2471         @param    x   x coordinate
   2472         @param    y   y coordinate
   2473         @returns  The desired pixel's 16-bit 5-6-5 color value
   2474 */
   2475 /**********************************************************************/
   2476 uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
   2477   if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
   2478     return 0;
   2479   if (buffer) {
   2480     return buffer[x + y * WIDTH];
   2481   }
   2482   return 0;
   2483 }
   2484 
   2485 /**************************************************************************/
   2486 /*!
   2487     @brief  Fill the framebuffer completely with one color
   2488     @param  color 16-bit 5-6-5 Color to fill with
   2489 */
   2490 /**************************************************************************/
   2491 void GFXcanvas16::fillScreen(uint16_t color) {
   2492   if (buffer) {
   2493     uint8_t hi = color >> 8, lo = color & 0xFF;
   2494     if (hi == lo) {
   2495       memset(buffer, lo, WIDTH * HEIGHT * 2);
   2496     } else {
   2497       uint32_t i, pixels = WIDTH * HEIGHT;
   2498       for (i = 0; i < pixels; i++)
   2499         buffer[i] = color;
   2500     }
   2501   }
   2502 }
   2503 
   2504 /**************************************************************************/
   2505 /*!
   2506     @brief  Reverses the "endian-ness" of each 16-bit pixel within the
   2507             canvas; little-endian to big-endian, or big-endian to little.
   2508             Most microcontrollers (such as SAMD) are little-endian, while
   2509             most displays tend toward big-endianness. All the drawing
   2510             functions (including RGB bitmap drawing) take care of this
   2511             automatically, but some specialized code (usually involving
   2512             DMA) can benefit from having pixel data already in the
   2513             display-native order. Note that this does NOT convert to a
   2514             SPECIFIC endian-ness, it just flips the bytes within each word.
   2515 */
   2516 /**************************************************************************/
   2517 void GFXcanvas16::byteSwap(void) {
   2518   if (buffer) {
   2519     uint32_t i, pixels = WIDTH * HEIGHT;
   2520     for (i = 0; i < pixels; i++)
   2521       buffer[i] = __builtin_bswap16(buffer[i]);
   2522   }
   2523 }
   2524 
   2525 /**************************************************************************/
   2526 /*!
   2527    @brief    Speed optimized vertical line drawing
   2528    @param    x   Line horizontal start point
   2529    @param    y   Line vertical start point
   2530    @param    h   length of vertical line to be drawn, including first point
   2531    @param    color   color 16-bit 5-6-5 Color to draw line with
   2532 */
   2533 /**************************************************************************/
   2534 void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h,
   2535                                 uint16_t color) {
   2536   if (h < 0) { // Convert negative heights to positive equivalent
   2537     h *= -1;
   2538     y -= h - 1;
   2539     if (y < 0) {
   2540       h += y;
   2541       y = 0;
   2542     }
   2543   }
   2544 
   2545   // Edge rejection (no-draw if totally off canvas)
   2546   if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
   2547     return;
   2548   }
   2549 
   2550   if (y < 0) { // Clip top
   2551     h += y;
   2552     y = 0;
   2553   }
   2554   if (y + h > height()) { // Clip bottom
   2555     h = height() - y;
   2556   }
   2557 
   2558   if (getRotation() == 0) {
   2559     drawFastRawVLine(x, y, h, color);
   2560   } else if (getRotation() == 1) {
   2561     int16_t t = x;
   2562     x = WIDTH - 1 - y;
   2563     y = t;
   2564     x -= h - 1;
   2565     drawFastRawHLine(x, y, h, color);
   2566   } else if (getRotation() == 2) {
   2567     x = WIDTH - 1 - x;
   2568     y = HEIGHT - 1 - y;
   2569 
   2570     y -= h - 1;
   2571     drawFastRawVLine(x, y, h, color);
   2572   } else if (getRotation() == 3) {
   2573     int16_t t = x;
   2574     x = y;
   2575     y = HEIGHT - 1 - t;
   2576     drawFastRawHLine(x, y, h, color);
   2577   }
   2578 }
   2579 
   2580 /**************************************************************************/
   2581 /*!
   2582    @brief  Speed optimized horizontal line drawing
   2583    @param  x      Line horizontal start point
   2584    @param  y      Line vertical start point
   2585    @param  w      Length of horizontal line to be drawn, including 1st point
   2586    @param  color  Color 16-bit 5-6-5 Color to draw line with
   2587 */
   2588 /**************************************************************************/
   2589 void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w,
   2590                                 uint16_t color) {
   2591   if (w < 0) { // Convert negative widths to positive equivalent
   2592     w *= -1;
   2593     x -= w - 1;
   2594     if (x < 0) {
   2595       w += x;
   2596       x = 0;
   2597     }
   2598   }
   2599 
   2600   // Edge rejection (no-draw if totally off canvas)
   2601   if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
   2602     return;
   2603   }
   2604 
   2605   if (x < 0) { // Clip left
   2606     w += x;
   2607     x = 0;
   2608   }
   2609   if (x + w >= width()) { // Clip right
   2610     w = width() - x;
   2611   }
   2612 
   2613   if (getRotation() == 0) {
   2614     drawFastRawHLine(x, y, w, color);
   2615   } else if (getRotation() == 1) {
   2616     int16_t t = x;
   2617     x = WIDTH - 1 - y;
   2618     y = t;
   2619     drawFastRawVLine(x, y, w, color);
   2620   } else if (getRotation() == 2) {
   2621     x = WIDTH - 1 - x;
   2622     y = HEIGHT - 1 - y;
   2623 
   2624     x -= w - 1;
   2625     drawFastRawHLine(x, y, w, color);
   2626   } else if (getRotation() == 3) {
   2627     int16_t t = x;
   2628     x = y;
   2629     y = HEIGHT - 1 - t;
   2630     y -= w - 1;
   2631     drawFastRawVLine(x, y, w, color);
   2632   }
   2633 }
   2634 
   2635 /**************************************************************************/
   2636 /*!
   2637    @brief    Speed optimized vertical line drawing into the raw canvas buffer
   2638    @param    x   Line horizontal start point
   2639    @param    y   Line vertical start point
   2640    @param    h   length of vertical line to be drawn, including first point
   2641    @param    color   color 16-bit 5-6-5 Color to draw line with
   2642 */
   2643 /**************************************************************************/
   2644 void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
   2645                                    uint16_t color) {
   2646   // x & y already in raw (rotation 0) coordinates, no need to transform.
   2647   uint16_t *buffer_ptr = buffer + y * WIDTH + x;
   2648   for (int16_t i = 0; i < h; i++) {
   2649     (*buffer_ptr) = color;
   2650     buffer_ptr += WIDTH;
   2651   }
   2652 }
   2653 
   2654 /**************************************************************************/
   2655 /*!
   2656    @brief    Speed optimized horizontal line drawing into the raw canvas buffer
   2657    @param    x   Line horizontal start point
   2658    @param    y   Line vertical start point
   2659    @param    w   length of horizontal line to be drawn, including first point
   2660    @param    color   color 16-bit 5-6-5 Color to draw line with
   2661 */
   2662 /**************************************************************************/
   2663 void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
   2664                                    uint16_t color) {
   2665   // x & y already in raw (rotation 0) coordinates, no need to transform.
   2666   uint32_t buffer_index = y * WIDTH + x;
   2667   for (uint32_t i = buffer_index; i < buffer_index + w; i++) {
   2668     buffer[i] = color;
   2669   }
   2670 }