acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Arduino_TFT.cpp (35127B)

      1 /*
      2  * start rewrite from:
      3  * https://github.com/adafruit/Adafruit-GFX-Library.git
      4  */
      5 #include "Arduino_DataBus.h"
      6 #include "Arduino_GFX.h"
      7 #include "Arduino_TFT.h"
      8 #include "font/glcdfont.h"
      9 
     10 Arduino_TFT::Arduino_TFT(
     11     Arduino_DataBus *bus, int8_t rst, uint8_t r,
     12     bool ips, int16_t w, int16_t h,
     13     uint8_t col_offset1, uint8_t row_offset1, uint8_t col_offset2, uint8_t row_offset2)
     14     : Arduino_GFX(w, h), _bus(bus), _rst(rst), _ips(ips),
     15       COL_OFFSET1(col_offset1), ROW_OFFSET1(row_offset1),
     16       COL_OFFSET2(col_offset2), ROW_OFFSET2(row_offset2)
     17 {
     18   _rotation = r;
     19 }
     20 
     21 bool Arduino_TFT::begin(int32_t speed)
     22 {
     23   if (_override_datamode != GFX_NOT_DEFINED)
     24   {
     25     if (!_bus->begin(speed, _override_datamode))
     26     {
     27       return false;
     28     }
     29   }
     30   else
     31   {
     32     if (!_bus->begin(speed))
     33     {
     34       return false;
     35     }
     36   }
     37 
     38   tftInit();
     39   setRotation(_rotation); // apply the setting rotation to the display
     40   setAddrWindow(0, 0, _width, _height);
     41 
     42   return true;
     43 }
     44 
     45 void Arduino_TFT::startWrite()
     46 {
     47   _bus->beginWrite();
     48 }
     49 
     50 void Arduino_TFT::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
     51 {
     52   writeAddrWindow(x, y, 1, 1);
     53   _bus->write16(color);
     54 }
     55 
     56 void Arduino_TFT::writeRepeat(uint16_t color, uint32_t len)
     57 {
     58   _bus->writeRepeat(color, len);
     59 }
     60 
     61 /*!
     62     @brief  Draw a vertical line on the display. Performs edge clipping and
     63             rejection. Not self-contained; should follow startWrite().
     64             Typically used by higher-level graphics primitives; user code
     65             shouldn't need to call this and is likely to use the self-
     66             contained drawFastVLine() instead.
     67     @param  x      Horizontal position of first point.
     68     @param  y      Vertical position of first point.
     69     @param  h      Line height in pixels (positive = below first point,
     70                    negative = above first point).
     71     @param  color  16-bit line color in '565' RGB format.
     72 */
     73 void Arduino_TFT::writeFastVLine(int16_t x, int16_t y, int16_t h,
     74                                  uint16_t color)
     75 {
     76   if (_ordered_in_range(x, 0, _max_x) && h)
     77   { // X on screen, nonzero height
     78     if (h < 0)
     79     {             // If negative height...
     80       y += h + 1; //   Move Y to top edge
     81       h = -h;     //   Use positive height
     82     }
     83     if (y <= _max_y)
     84     { // Not off bottom
     85       int16_t y2 = y + h - 1;
     86       if (y2 >= 0)
     87       { // Not off top
     88         // Line partly or fully overlaps screen
     89         if (y < 0)
     90         {
     91           y = 0;
     92           h = y2 + 1;
     93         } // Clip top
     94         if (y2 > _max_y)
     95         {
     96           h = _max_y - y + 1;
     97         } // Clip bottom
     98         writeFillRectPreclipped(x, y, 1, h, color);
     99       }
    100     }
    101   }
    102 }
    103 
    104 /*!
    105     @brief  Draw a horizontal line on the display. Performs edge clipping
    106             and rejection. Not self-contained; should follow startWrite().
    107             Typically used by higher-level graphics primitives; user code
    108             shouldn't need to call this and is likely to use the self-
    109             contained drawFastHLine() instead.
    110     @param  x      Horizontal position of first point.
    111     @param  y      Vertical position of first point.
    112     @param  w      Line width in pixels (positive = right of first point,
    113                    negative = point of first corner).
    114     @param  color  16-bit line color in '565' RGB format.
    115 */
    116 void Arduino_TFT::writeFastHLine(int16_t x, int16_t y, int16_t w,
    117                                  uint16_t color)
    118 {
    119   if (_ordered_in_range(y, 0, _max_y) && w)
    120   { // Y on screen, nonzero width
    121     if (w < 0)
    122     {             // If negative width...
    123       x += w + 1; //   Move X to left edge
    124       w = -w;     //   Use positive width
    125     }
    126     if (x <= _max_x)
    127     { // Not off right
    128       int16_t x2 = x + w - 1;
    129       if (x2 >= 0)
    130       { // Not off left
    131         // Line partly or fully overlaps screen
    132         if (x < 0)
    133         {
    134           x = 0;
    135           w = x2 + 1;
    136         } // Clip left
    137         if (x2 > _max_x)
    138         {
    139           w = _max_x - x + 1;
    140         } // Clip right
    141         writeFillRectPreclipped(x, y, w, 1, color);
    142       }
    143     }
    144   }
    145 }
    146 
    147 /*!
    148     @brief  A lower-level version of writeFillRect(). This version requires
    149             all inputs are in-bounds, that width and height are positive,
    150             and no part extends offscreen. NO EDGE CLIPPING OR REJECTION IS
    151             PERFORMED. If higher-level graphics primitives are written to
    152             handle their own clipping earlier in the drawing process, this
    153             can avoid unnecessary function calls and repeated clipping
    154             operations in the lower-level functions.
    155     @param  x      Horizontal position of first corner. MUST BE WITHIN
    156                    SCREEN BOUNDS.
    157     @param  y      Vertical position of first corner. MUST BE WITHIN SCREEN
    158                    BOUNDS.
    159     @param  w      Rectangle width in pixels. MUST BE POSITIVE AND NOT
    160                    EXTEND OFF SCREEN.
    161     @param  h      Rectangle height in pixels. MUST BE POSITIVE AND NOT
    162                    EXTEND OFF SCREEN.
    163     @param  color  16-bit fill color in '565' RGB format.
    164     @note   This is a new function, no graphics primitives besides rects
    165             and horizontal/vertical lines are written to best use this yet.
    166 */
    167 void Arduino_TFT::writeFillRectPreclipped(int16_t x, int16_t y,
    168                                           int16_t w, int16_t h, uint16_t color)
    169 {
    170 #ifdef ESP8266
    171   yield();
    172 #endif
    173   writeAddrWindow(x, y, w, h);
    174   writeRepeat(color, (uint32_t)w * h);
    175 }
    176 
    177 void Arduino_TFT::endWrite()
    178 {
    179   _bus->endWrite();
    180 }
    181 
    182 void Arduino_TFT::setAddrWindow(int16_t x0, int16_t y0, uint16_t w,
    183                                 uint16_t h)
    184 {
    185   startWrite();
    186 
    187   writeAddrWindow(x0, y0, w, h);
    188 
    189   endWrite();
    190 }
    191 
    192 /**************************************************************************/
    193 /*!
    194     @brief      Set rotation setting for display
    195     @param  x   0 thru 3 corresponding to 4 cardinal rotations
    196 */
    197 /**************************************************************************/
    198 void Arduino_TFT::setRotation(uint8_t r)
    199 {
    200   Arduino_GFX::setRotation(r);
    201   switch (_rotation)
    202   {
    203   case 5:
    204   case 3:
    205     _xStart = ROW_OFFSET2;
    206     _yStart = COL_OFFSET1;
    207     break;
    208   case 6:
    209   case 2:
    210     _xStart = COL_OFFSET2;
    211     _yStart = ROW_OFFSET2;
    212     break;
    213   case 7:
    214   case 1:
    215     _xStart = ROW_OFFSET1;
    216     _yStart = COL_OFFSET2;
    217     break;
    218   case 4:
    219   default: // case 0:
    220     _xStart = COL_OFFSET1;
    221     _yStart = ROW_OFFSET1;
    222     break;
    223   }
    224   _currentX = 0xFFFF;
    225   _currentY = 0xFFFF;
    226   _currentW = 0xFFFF;
    227   _currentH = 0xFFFF;
    228 }
    229 
    230 void Arduino_TFT::writeColor(uint16_t color)
    231 {
    232   _bus->write16(color);
    233 }
    234 
    235 // TFT optimization code, too big for ATMEL family
    236 #if !defined(LITTLE_FOOT_PRINT)
    237 
    238 void Arduino_TFT::writeBytes(uint8_t *data, uint32_t len)
    239 {
    240   _bus->writeBytes(data, len);
    241 }
    242 
    243 void Arduino_TFT::writePixels(uint16_t *data, uint32_t len)
    244 {
    245   _bus->writePixels(data, len);
    246 }
    247 
    248 /**************************************************************************/
    249 /*!
    250    @brief    Push a pixel, overwrite in subclasses if startWrite is defined!
    251    @param    color 16-bit 5-6-5 Color to fill with
    252 */
    253 /**************************************************************************/
    254 void Arduino_TFT::pushColor(uint16_t color)
    255 {
    256   _bus->beginWrite();
    257   writeColor(color);
    258   _bus->endWrite();
    259 }
    260 
    261 /**************************************************************************/
    262 /*!
    263    @brief    Write a line.  Bresenham's algorithm - thx wikpedia
    264     @param    x0  Start point x coordinate
    265     @param    y0  Start point y coordinate
    266     @param    x1  End point x coordinate
    267     @param    y1  End point y coordinate
    268     @param    color 16-bit 5-6-5 Color to draw with
    269 */
    270 /**************************************************************************/
    271 void Arduino_TFT::writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
    272                                  uint16_t color)
    273 {
    274   int16_t dx;
    275   int16_t dy;
    276   int16_t err;
    277   int16_t xs;
    278   int16_t step;
    279   int16_t len;
    280 
    281   bool steep = _diff(y1, y0) > _diff(x1, x0);
    282   if (steep)
    283   {
    284     _swap_int16_t(x0, y0);
    285     _swap_int16_t(x1, y1);
    286   }
    287 
    288   if (x0 > x1)
    289   {
    290     _swap_int16_t(x0, x1);
    291     _swap_int16_t(y0, y1);
    292   }
    293 
    294   dx = x1 - x0;
    295   dy = _diff(y1, y0);
    296   err = dx >> 1;
    297   xs = x0;
    298   step = (y0 < y1) ? 1 : -1;
    299   len = 0;
    300 
    301   while (x0 <= x1)
    302   {
    303     x0++;
    304     len++;
    305     err -= dy;
    306     if ((err < 0) || ((x0 > x1) && len))
    307     {
    308       if (steep)
    309       {
    310         writeFillRectPreclipped(y0, xs, 1, len, color);
    311       }
    312       else
    313       {
    314         writeFillRectPreclipped(xs, y0, len, 1, color);
    315       }
    316       err += dx;
    317       y0 += step;
    318       len = 0;
    319       xs = x0;
    320     }
    321   }
    322 }
    323 
    324 // TFT tuned BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
    325 
    326 /**************************************************************************/
    327 /*!
    328     @brief  Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position.
    329     @param  bitmap      byte array of Indexed color bitmap
    330     @param  color_index byte array of 16-bit color index
    331     @param  w           Width of bitmap in pixels
    332     @param  h           Height of bitmap in pixels
    333 */
    334 /**************************************************************************/
    335 void Arduino_TFT::writeIndexedPixels(uint8_t *bitmap, uint16_t *color_index, uint32_t len)
    336 {
    337   _bus->writeIndexedPixels(bitmap, color_index, len);
    338 }
    339 
    340 /**************************************************************************/
    341 /*!
    342     @brief  Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position.
    343     @param  bitmap      byte array of Indexed color bitmap
    344     @param  color_index byte array of 16-bit color index
    345     @param  w           Width of bitmap in pixels
    346     @param  h           Height of bitmap in pixels
    347 */
    348 /**************************************************************************/
    349 void Arduino_TFT::writeIndexedPixelsDouble(uint8_t *bitmap, uint16_t *color_index, uint32_t len)
    350 {
    351   _bus->writeIndexedPixelsDouble(bitmap, color_index, len);
    352 }
    353 
    354 /**************************************************************************/
    355 /*!
    356    @brief      Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
    357     @param    x   Top left corner x coordinate
    358     @param    y   Top left corner y coordinate
    359     @param    bitmap  byte array with monochrome bitmap
    360     @param    w   Width of bitmap in pixels
    361     @param    h   Height of bitmap in pixels
    362     @param    color 16-bit 5-6-5 Color to draw pixels with
    363     @param    bg 16-bit 5-6-5 Color to draw background with
    364 */
    365 /**************************************************************************/
    366 void Arduino_TFT::drawBitmap(int16_t x, int16_t y,
    367                              const uint8_t bitmap[], int16_t w, int16_t h,
    368                              uint16_t color, uint16_t bg)
    369 {
    370   if (
    371       ((x + w - 1) < 0) || // Outside left
    372       ((y + h - 1) < 0) || // Outside top
    373       (x > _max_x) ||      // Outside right
    374       (y > _max_y)         // Outside bottom
    375   )
    376   {
    377     return;
    378   }
    379   else if (
    380       (x < 0) ||                // Clip left
    381       (y < 0) ||                // Clip top
    382       ((x + w - 1) > _max_x) || // Clip right
    383       ((y + h - 1) > _max_y)    // Clip bottom
    384   )
    385   {
    386     Arduino_GFX::drawBitmap(x, y, bitmap, w, h, color, bg);
    387   }
    388   else
    389   {
    390     int32_t pixels = w * h;
    391     uint8_t byte = 0;
    392     uint16_t idx = 0;
    393     startWrite();
    394     writeAddrWindow(x, y, w, h);
    395     for (int32_t i = 0; i < pixels; i++)
    396     {
    397       if (i & 7)
    398       {
    399         byte <<= 1;
    400       }
    401       else
    402       {
    403         byte = pgm_read_byte(&bitmap[idx++]);
    404       }
    405       _bus->write16((byte & 0x80) ? color : bg);
    406     }
    407     endWrite();
    408   }
    409 }
    410 
    411 /**************************************************************************/
    412 /*!
    413    @brief      Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
    414     @param    x   Top left corner x coordinate
    415     @param    y   Top left corner y coordinate
    416     @param    bitmap  byte array with monochrome bitmap
    417     @param    w   Width of bitmap in pixels
    418     @param    h   Height of bitmap in pixels
    419     @param    color 16-bit 5-6-5 Color to draw pixels with
    420     @param    bg 16-bit 5-6-5 Color to draw background with
    421 */
    422 /**************************************************************************/
    423 void Arduino_TFT::drawBitmap(int16_t x, int16_t y,
    424                              uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
    425 {
    426   if (
    427       ((x + w - 1) < 0) || // Outside left
    428       ((y + h - 1) < 0) || // Outside top
    429       (x > _max_x) ||      // Outside right
    430       (y > _max_y)         // Outside bottom
    431   )
    432   {
    433     return;
    434   }
    435   else if (
    436       (x < 0) ||                // Clip left
    437       (y < 0) ||                // Clip top
    438       ((x + w - 1) > _max_x) || // Clip right
    439       ((y + h - 1) > _max_y)    // Clip bottom
    440   )
    441   {
    442     Arduino_GFX::drawBitmap(x, y, bitmap, w, h, color, bg);
    443   }
    444   else
    445   {
    446     int32_t pixels = w * h;
    447     uint8_t byte = 0;
    448     startWrite();
    449     writeAddrWindow(x, y, w, h);
    450     for (int32_t i = 0; i < pixels; i++)
    451     {
    452       if (i & 7)
    453       {
    454         byte <<= 1;
    455       }
    456       else
    457       {
    458         byte = *(bitmap++);
    459       }
    460       _bus->write16((byte & 0x80) ? color : bg);
    461     }
    462     endWrite();
    463   }
    464 }
    465 
    466 /**************************************************************************/
    467 /*!
    468    @brief   Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos.
    469     @param    x   Top left corner x coordinate
    470     @param    y   Top left corner y coordinate
    471     @param    bitmap  byte array with grayscale bitmap
    472     @param    w   Width of bitmap in pixels
    473     @param    h   Height of bitmap in pixels
    474 */
    475 /**************************************************************************/
    476 void Arduino_TFT::drawGrayscaleBitmap(int16_t x, int16_t y,
    477                                       const uint8_t bitmap[], int16_t w, int16_t h)
    478 {
    479   if (
    480       ((x + w - 1) < 0) || // Outside left
    481       ((y + h - 1) < 0) || // Outside top
    482       (x > _max_x) ||      // Outside right
    483       (y > _max_y)         // Outside bottom
    484   )
    485   {
    486     return;
    487   }
    488   else if (
    489       (x < 0) ||                // Clip left
    490       (y < 0) ||                // Clip top
    491       ((x + w - 1) > _max_x) || // Clip right
    492       ((y + h - 1) > _max_y)    // Clip bottom
    493   )
    494   {
    495     Arduino_GFX::drawGrayscaleBitmap(x, y, bitmap, w, h);
    496   }
    497   else
    498   {
    499     uint32_t len = (uint32_t)w * h;
    500     uint8_t v;
    501     startWrite();
    502     writeAddrWindow(x, y, w, h);
    503     for (uint32_t i = 0; i < len; i++)
    504     {
    505       v = (uint8_t)pgm_read_byte(&bitmap[i]);
    506       _bus->write16(color565(v, v, v));
    507     }
    508     endWrite();
    509   }
    510 }
    511 
    512 /**************************************************************************/
    513 /*!
    514    @brief   Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos.
    515     @param    x   Top left corner x coordinate
    516     @param    y   Top left corner y coordinate
    517     @param    bitmap  byte array with grayscale bitmap
    518     @param    w   Width of bitmap in pixels
    519     @param    h   Height of bitmap in pixels
    520 */
    521 /**************************************************************************/
    522 void Arduino_TFT::drawGrayscaleBitmap(int16_t x, int16_t y,
    523                                       uint8_t *bitmap, int16_t w, int16_t h)
    524 {
    525   if (
    526       ((x + w - 1) < 0) || // Outside left
    527       ((y + h - 1) < 0) || // Outside top
    528       (x > _max_x) ||      // Outside right
    529       (y > _max_y)         // Outside bottom
    530   )
    531   {
    532     return;
    533   }
    534   else if (
    535       (x < 0) ||                // Clip left
    536       (y < 0) ||                // Clip top
    537       ((x + w - 1) > _max_x) || // Clip right
    538       ((y + h - 1) > _max_y)    // Clip bottom
    539   )
    540   {
    541     Arduino_GFX::drawGrayscaleBitmap(x, y, bitmap, w, h);
    542   }
    543   else
    544   {
    545     uint32_t len = (uint32_t)w * h;
    546     uint8_t v;
    547     startWrite();
    548     writeAddrWindow(x, y, w, h);
    549     while (len--)
    550     {
    551       v = *(bitmap++);
    552       _bus->write16(color565(v, v, v));
    553     }
    554     endWrite();
    555   }
    556 }
    557 
    558 /**************************************************************************/
    559 /*!
    560     @brief  Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position.
    561     @param  x           Top left corner x coordinate
    562     @param  y           Top left corner y coordinate
    563     @param  bitmap      byte array of Indexed color bitmap
    564     @param  color_index byte array of 16-bit color index
    565     @param  w           Width of bitmap in pixels
    566     @param  h           Height of bitmap in pixels
    567 */
    568 /**************************************************************************/
    569 void Arduino_TFT::drawIndexedBitmap(int16_t x, int16_t y,
    570                                     uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h)
    571 {
    572   if (
    573       ((x + w - 1) < 0) || // Outside left
    574       ((y + h - 1) < 0) || // Outside top
    575       (x > _max_x) ||      // Outside right
    576       (y > _max_y)         // Outside bottom
    577   )
    578   {
    579     return;
    580   }
    581   else if (
    582       (x < 0) ||                // Clip left
    583       (y < 0) ||                // Clip top
    584       ((x + w - 1) > _max_x) || // Clip right
    585       ((y + h - 1) > _max_y)    // Clip bottom
    586   )
    587   {
    588     Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, w, h);
    589   }
    590   else
    591   {
    592     uint32_t len = w * h;
    593     startWrite();
    594     writeAddrWindow(x, y, w, h);
    595     _bus->writeIndexedPixels(bitmap, color_index, len);
    596     endWrite();
    597   }
    598 }
    599 
    600 /**************************************************************************/
    601 /*!
    602     @brief  Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask
    603             (set bits = opaque, unset bits = clear) at the specified (x,y) position.
    604             BOTH buffers (color and mask) must be RAM-resident.
    605     @param  x       Top left corner x coordinate
    606     @param  y       Top left corner y coordinate
    607     @param  bitmap  byte array with 16-bit color bitmap
    608     @param  mask    byte array with monochrome mask bitmap
    609     @param  w       Width of bitmap in pixels
    610     @param  h       Height of bitmap in pixels
    611 */
    612 /**************************************************************************/
    613 void Arduino_TFT::draw16bitRGBBitmap(int16_t x, int16_t y,
    614                                      uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
    615 {
    616   if (
    617       ((x + w - 1) < 0) || // Outside left
    618       ((y + h - 1) < 0) || // Outside top
    619       (x > _max_x) ||      // Outside right
    620       (y > _max_y)         // Outside bottom
    621   )
    622   {
    623     return;
    624   }
    625   else if (
    626       (x < 0) ||                // Clip left
    627       (y < 0) ||                // Clip top
    628       ((x + w - 1) > _max_x) || // Clip right
    629       ((y + h - 1) > _max_y)    // Clip bottom
    630   )
    631   {
    632     Arduino_GFX::draw16bitRGBBitmap(x, y, bitmap, mask, w, h);
    633   }
    634   else
    635   {
    636     int32_t offset = 0, maskIdx = 0, len = 0;
    637     uint8_t byte = 0;
    638     startWrite();
    639     for (int16_t j = 0; j < h; j++, y++)
    640     {
    641       for (int16_t i = 0; i < w; i++)
    642       {
    643         if (i & 7)
    644         {
    645           byte <<= 1;
    646         }
    647         else
    648         {
    649           byte = mask[maskIdx++];
    650         }
    651         if (byte & 0x80)
    652         {
    653           len++;
    654         }
    655         else
    656         {
    657           if (len)
    658           {
    659             writeAddrWindow(x + i - len, y, len, 1);
    660             _bus->writePixels(&bitmap[offset - len], len);
    661             len = 0;
    662           }
    663         }
    664         offset++;
    665       }
    666       if (len)
    667       {
    668         writeAddrWindow(x + w - 1 - len, y, len, 1);
    669         _bus->writePixels(&bitmap[offset - len], len);
    670         len = 0;
    671       }
    672     }
    673     endWrite();
    674   }
    675 }
    676 
    677 /**************************************************************************/
    678 /*!
    679    @brief   Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
    680    For 16-bit display devices; no color reduction performed.
    681     @param    x   Top left corner x coordinate
    682     @param    y   Top left corner y coordinate
    683     @param    bitmap  byte array with 16-bit color bitmap
    684     @param    w   Width of bitmap in pixels
    685     @param    h   Height of bitmap in pixels
    686 */
    687 /**************************************************************************/
    688 void Arduino_TFT::draw16bitRGBBitmap(int16_t x, int16_t y,
    689                                      const uint16_t bitmap[], int16_t w, int16_t h)
    690 {
    691   if (
    692       ((x + w - 1) < 0) || // Outside left
    693       ((y + h - 1) < 0) || // Outside top
    694       (x > _max_x) ||      // Outside right
    695       (y > _max_y)         // Outside bottom
    696   )
    697   {
    698     return;
    699   }
    700   else if (
    701       (x < 0) ||                // Clip left
    702       (y < 0) ||                // Clip top
    703       ((x + w - 1) > _max_x) || // Clip right
    704       ((y + h - 1) > _max_y)    // Clip bottom
    705   )
    706   {
    707     Arduino_GFX::draw16bitRGBBitmap(x, y, bitmap, w, h);
    708   }
    709   else
    710   {
    711     uint32_t len = (uint32_t)w * h;
    712     startWrite();
    713     writeAddrWindow(x, y, w, h);
    714     for (uint32_t i = 0; i < len; i++)
    715     {
    716       _bus->write16(pgm_read_word(&bitmap[i]));
    717     }
    718     endWrite();
    719   }
    720 }
    721 
    722 /**************************************************************************/
    723 /*!
    724    @brief   Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
    725    For 16-bit display devices; no color reduction performed.
    726     @param    x   Top left corner x coordinate
    727     @param    y   Top left corner y coordinate
    728     @param    bitmap  byte array with 16-bit color bitmap
    729     @param    w   Width of bitmap in pixels
    730     @param    h   Height of bitmap in pixels
    731 */
    732 /**************************************************************************/
    733 void Arduino_TFT::draw16bitRGBBitmap(int16_t x, int16_t y,
    734                                      uint16_t *bitmap, int16_t w, int16_t h)
    735 {
    736   if (
    737       ((x + w - 1) < 0) || // Outside left
    738       ((y + h - 1) < 0) || // Outside top
    739       (x > _max_x) ||      // Outside right
    740       (y > _max_y)         // Outside bottom
    741   )
    742   {
    743     return;
    744   }
    745   else if (
    746       (x < 0) ||                // Clip left
    747       (y < 0) ||                // Clip top
    748       ((x + w - 1) > _max_x) || // Clip right
    749       ((y + h - 1) > _max_y)    // Clip bottom
    750   )
    751   {
    752     Arduino_GFX::draw16bitRGBBitmap(x, y, bitmap, w, h);
    753   }
    754   else
    755   {
    756     startWrite();
    757     writeAddrWindow(x, y, w, h);
    758     _bus->writePixels(bitmap, (uint32_t)w * h);
    759     endWrite();
    760   }
    761 }
    762 
    763 /**************************************************************************/
    764 /*!
    765    @brief   Draw a RAM-resident 16-bit Big Endian image (RGB 5/6/5) at the specified (x,y) position.
    766    For 16-bit display devices; no color reduction performed.
    767     @param    x   Top left corner x coordinate
    768     @param    y   Top left corner y coordinate
    769     @param    bitmap  byte array with 16-bit color bitmap
    770     @param    w   Width of bitmap in pixels
    771     @param    h   Height of bitmap in pixels
    772 */
    773 /**************************************************************************/
    774 void Arduino_TFT::draw16bitBeRGBBitmap(int16_t x, int16_t y,
    775                                        uint16_t *bitmap, int16_t w, int16_t h)
    776 {
    777   if (
    778       ((x + w - 1) < 0) || // Outside left
    779       ((y + h - 1) < 0) || // Outside top
    780       (x > _max_x) ||      // Outside right
    781       (y > _max_y)         // Outside bottom
    782   )
    783   {
    784     return;
    785   }
    786   else if (
    787       (x < 0) ||                // Clip left
    788       (y < 0) ||                // Clip top
    789       ((x + w - 1) > _max_x) || // Clip right
    790       ((y + h - 1) > _max_y)    // Clip bottom
    791   )
    792   {
    793     Arduino_GFX::draw16bitBeRGBBitmap(x, y, bitmap, w, h);
    794   }
    795   else
    796   {
    797     startWrite();
    798     writeAddrWindow(x, y, w, h);
    799     _bus->writeBytes((uint8_t *)bitmap, (uint32_t)w * h * 2);
    800     endWrite();
    801   }
    802 }
    803 
    804 /**************************************************************************/
    805 /*!
    806    @brief   Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position.
    807     @param    x   Top left corner x coordinate
    808     @param    y   Top left corner y coordinate
    809     @param    bitmap  byte array with 16-bit color bitmap
    810     @param    w   Width of bitmap in pixels
    811     @param    h   Height of bitmap in pixels
    812 */
    813 /**************************************************************************/
    814 void Arduino_TFT::draw24bitRGBBitmap(int16_t x, int16_t y,
    815                                      const uint8_t bitmap[], int16_t w, int16_t h)
    816 {
    817   if (
    818       ((x + w - 1) < 0) || // Outside left
    819       ((y + h - 1) < 0) || // Outside top
    820       (x > _max_x) ||      // Outside right
    821       (y > _max_y)         // Outside bottom
    822   )
    823   {
    824     return;
    825   }
    826   else if (
    827       (x < 0) ||                // Clip left
    828       (y < 0) ||                // Clip top
    829       ((x + w - 1) > _max_x) || // Clip right
    830       ((y + h - 1) > _max_y)    // Clip bottom
    831   )
    832   {
    833     Arduino_GFX::draw24bitRGBBitmap(x, y, bitmap, w, h);
    834   }
    835   else
    836   {
    837     uint32_t len = (uint32_t)w * h;
    838     uint32_t offset = 0;
    839     startWrite();
    840     writeAddrWindow(x, y, w, h);
    841     while (len--)
    842     {
    843       _bus->write16(color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2])));
    844       offset += 3;
    845     }
    846     endWrite();
    847   }
    848 }
    849 
    850 /**************************************************************************/
    851 /*!
    852    @brief   Draw a RAM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position.
    853     @param    x   Top left corner x coordinate
    854     @param    y   Top left corner y coordinate
    855     @param    bitmap  byte array with 16-bit color bitmap
    856     @param    w   Width of bitmap in pixels
    857     @param    h   Height of bitmap in pixels
    858 */
    859 /**************************************************************************/
    860 void Arduino_TFT::draw24bitRGBBitmap(int16_t x, int16_t y,
    861                                      uint8_t *bitmap, int16_t w, int16_t h)
    862 {
    863   if (
    864       ((x + w - 1) < 0) || // Outside left
    865       ((y + h - 1) < 0) || // Outside top
    866       (x > _max_x) ||      // Outside right
    867       (y > _max_y)         // Outside bottom
    868   )
    869   {
    870     return;
    871   }
    872   else if (
    873       (x < 0) ||                // Clip left
    874       (y < 0) ||                // Clip top
    875       ((x + w - 1) > _max_x) || // Clip right
    876       ((y + h - 1) > _max_y)    // Clip bottom
    877   )
    878   {
    879     Arduino_GFX::draw24bitRGBBitmap(x, y, bitmap, w, h);
    880   }
    881   else
    882   {
    883     uint32_t len = (uint32_t)w * h;
    884     uint32_t offset = 0;
    885     startWrite();
    886     writeAddrWindow(x, y, w, h);
    887     while (len--)
    888     {
    889       _bus->write16(color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2]));
    890       offset += 3;
    891     }
    892     endWrite();
    893   }
    894 }
    895 
    896 // Draw a character
    897 /**************************************************************************/
    898 /*!
    899    @brief   Draw a single character
    900     @param    x   Bottom left corner x coordinate
    901     @param    y   Bottom left corner y coordinate
    902     @param    c   The 8-bit font-indexed character (likely ascii)
    903     @param    color 16-bit 5-6-5 Color to draw chraracter with
    904     @param    bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
    905 */
    906 /**************************************************************************/
    907 void Arduino_TFT::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg)
    908 {
    909   uint16_t block_w;
    910   uint16_t block_h;
    911 
    912 #if !defined(ATTINY_CORE)
    913   if (gfxFont) // custom font
    914   {
    915     // Character is assumed previously filtered by write() to eliminate
    916     // newlines, returns, non-printable characters, etc.  Calling
    917     // drawChar() directly with 'bad' characters of font may cause mayhem!
    918     uint8_t first = pgm_read_byte(&gfxFont->first);
    919     GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
    920     uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
    921 
    922     uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
    923     uint8_t w = pgm_read_byte(&glyph->width),
    924             h = pgm_read_byte(&glyph->height),
    925             xAdvance = pgm_read_byte(&glyph->xAdvance),
    926             yAdvance = pgm_read_byte(&gfxFont->yAdvance),
    927             baseline = yAdvance * 2 / 3; // TODO: baseline is an arbitrary currently, may be define in font file
    928     int8_t xo = pgm_read_byte(&glyph->xOffset),
    929            yo = pgm_read_byte(&glyph->yOffset);
    930     // urgly workaround for the character not fit in the box
    931     if ((bg != color)             // have background color
    932         && ((xo + w) > xAdvance)) // if character draw outside the box
    933     {
    934       xo = xAdvance - w; // pad inside the box
    935     }
    936 
    937     uint8_t xx, yy, bits = 0, bit = 0;
    938     int16_t xo16 = xo, yo16 = yo;
    939 
    940     if (xAdvance < w)
    941     {
    942       xAdvance = w; // Don't know why it exists
    943     }
    944 
    945     block_w = xAdvance * textsize_x;
    946     block_h = yAdvance * textsize_y;
    947     int16_t x1 = (xo < 0) ? (x + xo) : x;
    948     if (
    949         (x1 < 0) ||                             // Clip left
    950         ((y - baseline) < 0) ||                 // Clip top
    951         ((x1 + block_w - 1) > _max_x) ||        // Clip right
    952         ((y - baseline + block_h - 1) > _max_y) // Clip bottom
    953     )
    954     {
    955       // partial draw char by parent class
    956       Arduino_GFX::drawChar(x, y, c, color, bg);
    957     }
    958     else
    959     {
    960       // NOTE: Different from Adafruit_GFX design, Adruino_GFX also cater background.
    961       // Since it may introduce many ugly output, it should limited using on mono font only.
    962       if (xo < 0) // padding X offset to >= 0
    963       {
    964         x += xo;
    965         xo = 0;
    966       }
    967 
    968       startWrite();
    969       if (bg != color) // have background color
    970       {
    971         writeAddrWindow(x, y - (baseline * textsize_y), block_w, block_h);
    972 
    973         uint16_t line_buf[block_w];
    974         int8_t i;
    975         bool draw_dot;
    976         for (yy = 0; yy < yAdvance; yy++)
    977         {
    978           if ((yy < (baseline + yo)) || (yy > (baseline + yo + h - 1)))
    979           {
    980             writeRepeat(bg, block_w * textsize_y);
    981           }
    982           else
    983           {
    984             i = 0;
    985             for (xx = 0; xx < xAdvance; xx++)
    986             {
    987               if ((xx < xo) || (xx > (xo + w - 1)))
    988               {
    989                 draw_dot = false;
    990               }
    991               else
    992               {
    993                 if (!(bit++ & 7))
    994                 {
    995                   bits = pgm_read_byte(&bitmap[bo++]);
    996                 }
    997                 draw_dot = bits & 0x80;
    998                 bits <<= 1;
    999               }
   1000 
   1001               if (textsize_x == 1)
   1002               {
   1003                 line_buf[i++] = draw_dot ? color : bg;
   1004               }
   1005               else
   1006               {
   1007                 if (draw_dot)
   1008                 {
   1009                   for (int8_t k = 0; k < textsize_x; k++)
   1010                   {
   1011                     line_buf[i++] = (k < (textsize_x - text_pixel_margin)) ? color : bg;
   1012                   }
   1013                 }
   1014                 else
   1015                 {
   1016                   for (int8_t k = 0; k < textsize_x; k++)
   1017                   {
   1018                     line_buf[i++] = bg;
   1019                   }
   1020                 }
   1021               }
   1022             }
   1023             if (textsize_y == 1)
   1024             {
   1025               writePixels(line_buf, block_w);
   1026             }
   1027             else
   1028             {
   1029               for (int8_t l = 0; l < textsize_y; l++)
   1030               {
   1031                 if (l < (textsize_y - text_pixel_margin))
   1032                 {
   1033                   writePixels(line_buf, block_w);
   1034                 }
   1035                 else
   1036                 {
   1037                   writeRepeat(bg, block_w);
   1038                 }
   1039               }
   1040             }
   1041           }
   1042         }
   1043       }
   1044       else // (bg == color), no background color
   1045       {
   1046         for (yy = 0; yy < h; yy++)
   1047         {
   1048           for (xx = 0; xx < w; xx++)
   1049           {
   1050             if (!(bit++ & 7))
   1051             {
   1052               bits = pgm_read_byte(&bitmap[bo++]);
   1053             }
   1054             if (bits & 0x80)
   1055             {
   1056               if (textsize_x == 1 && textsize_y == 1)
   1057               {
   1058                 writePixelPreclipped(x + xo + xx, y + yo + yy, color);
   1059               }
   1060               else
   1061               {
   1062                 writeFillRectPreclipped(x + (xo16 + xx) * textsize_x, y + (yo16 + yy) * textsize_y,
   1063                                         textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
   1064               }
   1065             }
   1066             bits <<= 1;
   1067           }
   1068         }
   1069       }
   1070       endWrite();
   1071     }
   1072   }
   1073   else // not gfxFont
   1074 #endif // !defined(ATTINY_CORE)
   1075 #if defined(U8G2_FONT_SUPPORT)
   1076       if (u8g2Font)
   1077   {
   1078     Arduino_GFX::drawChar(x, y, c, color, bg);
   1079   }
   1080   else // not u8g2Font
   1081 #endif // defined(U8G2_FONT_SUPPORT)
   1082   {
   1083     block_w = 6 * textsize_x;
   1084     block_h = 8 * textsize_y;
   1085     if (
   1086         (x < 0) ||                      // Clip left
   1087         (y < 0) ||                      // Clip top
   1088         ((x + block_w - 1) > _max_x) || // Clip right
   1089         ((y + block_h - 1) > _max_y)    // Clip bottom
   1090     )
   1091     {
   1092       // partial draw char by parent class
   1093       Arduino_GFX::drawChar(x, y, c, color, bg);
   1094     }
   1095     else
   1096     {
   1097       uint8_t col[5];
   1098       for (int8_t i = 0; i < 5; i++)
   1099       {
   1100         col[i] = pgm_read_byte(&font[c * 5 + i]);
   1101       }
   1102 
   1103       startWrite();
   1104       if (bg != color) // have background color
   1105       {
   1106         writeAddrWindow(x, y, block_w, block_h);
   1107 
   1108         uint16_t line_buf[block_w];
   1109         if (textsize_x == 1)
   1110         {
   1111           line_buf[5] = bg; // last column always bg
   1112         }
   1113         else
   1114         {
   1115           for (int8_t k = 0; k < textsize_x; k++)
   1116           {
   1117             line_buf[5 * textsize_x + k] = bg;
   1118           }
   1119         }
   1120         uint8_t bit = 1;
   1121         bool draw_dot;
   1122 
   1123         while (bit)
   1124         {
   1125           for (int8_t i = 0; i < 5; i++)
   1126           {
   1127             draw_dot = col[i] & bit;
   1128             if (textsize_x == 1)
   1129             {
   1130               line_buf[i] = (draw_dot) ? color : bg;
   1131             }
   1132             else
   1133             {
   1134               if (draw_dot)
   1135               {
   1136                 for (int8_t k = 0; k < textsize_x; k++)
   1137                 {
   1138                   line_buf[i * textsize_x + k] = (k < (textsize_x - text_pixel_margin)) ? color : bg;
   1139                 }
   1140               }
   1141               else
   1142               {
   1143                 for (int8_t k = 0; k < textsize_x; k++)
   1144                 {
   1145                   line_buf[i * textsize_x + k] = bg;
   1146                 }
   1147               }
   1148             }
   1149           }
   1150           if (textsize_y == 1)
   1151           {
   1152             writePixels(line_buf, block_w);
   1153           }
   1154           else
   1155           {
   1156             for (int8_t l = 0; l < textsize_y; l++)
   1157             {
   1158               if (l < (textsize_y - text_pixel_margin))
   1159               {
   1160                 writePixels(line_buf, block_w);
   1161               }
   1162               else
   1163               {
   1164                 writeRepeat(bg, block_w);
   1165               }
   1166             }
   1167           }
   1168           bit <<= 1;
   1169         }
   1170       }
   1171       else // (bg == color), no background color
   1172       {
   1173         for (int8_t i = 0; i < 5; i++)
   1174         { // Char bitmap = 5 columns
   1175           uint8_t line = col[i];
   1176           for (int8_t j = 0; j < 8; j++, line >>= 1)
   1177           {
   1178             if (line & 1)
   1179             {
   1180               if (textsize_x == 1 && textsize_y == 1)
   1181               {
   1182                 writePixelPreclipped(x + i, y + j, color);
   1183               }
   1184               else
   1185               {
   1186                 writeFillRectPreclipped(x + i * textsize_x, y + j * textsize_y, textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
   1187               }
   1188             }
   1189           }
   1190         }
   1191       }
   1192       endWrite();
   1193     }
   1194   }
   1195 }
   1196 
   1197 #endif // !defined(LITTLE_FOOT_PRINT)