A first port of the excellent Adafruit GFX library

Dependents:   Adafruit_GFX

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_GFX.cpp Source File

Adafruit_GFX.cpp

00001 /*
00002 This is the core graphics library for all our displays, providing a common
00003 set of graphics primitives (points, lines, circles, etc.).  It needs to be
00004 paired with a hardware-specific library for each display device we carry
00005 (to handle the lower-level functions).
00006 
00007 Adafruit invests time and resources providing this open source code, please
00008 support Adafruit & open-source hardware by purchasing products from Adafruit!
00009  
00010 Copyright (c) 2013 Adafruit Industries.  All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014 
00015 - Redistributions of source code must retain the above copyright notice,
00016   this list of conditions and the following disclaimer.
00017 - Redistributions in binary form must reproduce the above copyright notice,
00018   this list of conditions and the following disclaimer in the documentation
00019   and/or other materials provided with the distribution.
00020 
00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00022 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00025 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00026 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00027 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00030 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 POSSIBILITY OF SUCH DAMAGE.
00032 */
00033 
00034 #include "mbed.h"
00035 #include "Adafruit_GFX.h"
00036 #include "glcdfont.h"
00037 
00038 Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): WIDTH(w), HEIGHT(h) {
00039  
00040   _width = WIDTH;
00041   _height = HEIGHT;
00042 
00043   rotation = 0;    
00044   cursor_y = cursor_x = 0;
00045   textsize = 1;
00046   textcolor = textbgcolor = 0xFFFF;
00047   wrap = true;
00048 }
00049 
00050 
00051 // draw a circle outline
00052 void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, 
00053                   uint16_t color) {
00054   int16_t f = 1 - r;
00055   int16_t ddF_x = 1;
00056   int16_t ddF_y = -2 * r;
00057   int16_t x = 0;
00058   int16_t y = r;
00059 
00060   drawPixel(x0, y0+r, color);
00061   drawPixel(x0, y0-r, color);
00062   drawPixel(x0+r, y0, color);
00063   drawPixel(x0-r, y0, color);
00064 
00065   while (x<y) {
00066     if (f >= 0) {
00067       y--;
00068       ddF_y += 2;
00069       f += ddF_y;
00070     }
00071     x++;
00072     ddF_x += 2;
00073     f += ddF_x;
00074   
00075     drawPixel(x0 + x, y0 + y, color);
00076     drawPixel(x0 - x, y0 + y, color);
00077     drawPixel(x0 + x, y0 - y, color);
00078     drawPixel(x0 - x, y0 - y, color);
00079     drawPixel(x0 + y, y0 + x, color);
00080     drawPixel(x0 - y, y0 + x, color);
00081     drawPixel(x0 + y, y0 - x, color);
00082     drawPixel(x0 - y, y0 - x, color);
00083     
00084   }
00085 }
00086 
00087 void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
00088                int16_t r, uint8_t cornername, uint16_t color) {
00089   int16_t f     = 1 - r;
00090   int16_t ddF_x = 1;
00091   int16_t ddF_y = -2 * r;
00092   int16_t x     = 0;
00093   int16_t y     = r;
00094 
00095   while (x<y) {
00096     if (f >= 0) {
00097       y--;
00098       ddF_y += 2;
00099       f     += ddF_y;
00100     }
00101     x++;
00102     ddF_x += 2;
00103     f     += ddF_x;
00104     if (cornername & 0x4) {
00105       drawPixel(x0 + x, y0 + y, color);
00106       drawPixel(x0 + y, y0 + x, color);
00107     } 
00108     if (cornername & 0x2) {
00109       drawPixel(x0 + x, y0 - y, color);
00110       drawPixel(x0 + y, y0 - x, color);
00111     }
00112     if (cornername & 0x8) {
00113       drawPixel(x0 - y, y0 + x, color);
00114       drawPixel(x0 - x, y0 + y, color);
00115     }
00116     if (cornername & 0x1) {
00117       drawPixel(x0 - y, y0 - x, color);
00118       drawPixel(x0 - x, y0 - y, color);
00119     }
00120   }
00121 }
00122 
00123 void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, 
00124                   uint16_t color) {
00125   drawFastVLine(x0, y0-r, 2*r+1, color);
00126   fillCircleHelper(x0, y0, r, 3, 0, color);
00127 }
00128 
00129 // used to do circles and roundrects!
00130 void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
00131                     uint8_t cornername, int16_t delta, uint16_t color) {
00132 
00133   int16_t f     = 1 - r;
00134   int16_t ddF_x = 1;
00135   int16_t ddF_y = -2 * r;
00136   int16_t x     = 0;
00137   int16_t y     = r;
00138 
00139   while (x<y) {
00140     if (f >= 0) {
00141       y--;
00142       ddF_y += 2;
00143       f     += ddF_y;
00144     }
00145     x++;
00146     ddF_x += 2;
00147     f     += ddF_x;
00148 
00149     if (cornername & 0x1) {
00150       drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
00151       drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
00152     }
00153     if (cornername & 0x2) {
00154       drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
00155       drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
00156     }
00157   }
00158 }
00159 
00160 // bresenham's algorithm - thx wikpedia
00161 void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, 
00162                 int16_t x1, int16_t y1, 
00163                 uint16_t color) {
00164   int16_t steep = abs(y1 - y0) > abs(x1 - x0);
00165   if (steep) {
00166     aswap(x0, y0);
00167     aswap(x1, y1);
00168   }
00169 
00170   if (x0 > x1) {
00171     aswap(x0, x1);
00172     aswap(y0, y1);
00173   }
00174 
00175   int16_t dx, dy;
00176   dx = x1 - x0;
00177   dy = abs(y1 - y0);
00178 
00179   int16_t err = dx / 2;
00180   int16_t ystep;
00181 
00182   if (y0 < y1) {
00183     ystep = 1;
00184   } else {
00185     ystep = -1;
00186   }
00187 
00188   for (; x0<=x1; x0++) {
00189     if (steep) {
00190       drawPixel(y0, x0, color);
00191     } else {
00192       drawPixel(x0, y0, color);
00193     }
00194     err -= dy;
00195     if (err < 0) {
00196       y0 += ystep;
00197       err += dx;
00198     }
00199   }
00200 }
00201 
00202 
00203 // draw a rectangle
00204 void Adafruit_GFX::drawRect(int16_t x, int16_t y, 
00205                 int16_t w, int16_t h, 
00206                 uint16_t color) {
00207   drawFastHLine(x, y, w, color);
00208   drawFastHLine(x, y+h-1, w, color);
00209   drawFastVLine(x, y, h, color);
00210   drawFastVLine(x+w-1, y, h, color);
00211 }
00212 
00213 void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, 
00214                  int16_t h, uint16_t color) {
00215   // stupidest version - update in subclasses if desired!
00216   drawLine(x, y, x, y+h-1, color);
00217 }
00218 
00219 
00220 void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, 
00221                  int16_t w, uint16_t color) {
00222   // stupidest version - update in subclasses if desired!
00223   drawLine(x, y, x+w-1, y, color);
00224 }
00225 
00226 void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 
00227                 uint16_t color) {
00228   // stupidest version - update in subclasses if desired!
00229   for (int16_t i=x; i<x+w; i++) {
00230     drawFastVLine(i, y, h, color); 
00231   }
00232 }
00233 
00234 
00235 void Adafruit_GFX::fillScreen(uint16_t color) {
00236   fillRect(0, 0, _width, _height, color);
00237 }
00238 
00239 // draw a rounded rectangle!
00240 void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
00241   int16_t h, int16_t r, uint16_t color) {
00242   // smarter version
00243   drawFastHLine(x+r  , y    , w-2*r, color); // Top
00244   drawFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
00245   drawFastVLine(  x    , y+r  , h-2*r, color); // Left
00246   drawFastVLine(  x+w-1, y+r  , h-2*r, color); // Right
00247   // draw four corners
00248   drawCircleHelper(x+r    , y+r    , r, 1, color);
00249   drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
00250   drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
00251   drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
00252 }
00253 
00254 // fill a rounded rectangle!
00255 void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
00256                  int16_t h, int16_t r, uint16_t color) {
00257   // smarter version
00258   fillRect(x+r, y, w-2*r, h, color);
00259 
00260   // draw four corners
00261   fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
00262   fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
00263 }
00264 
00265 // draw a triangle!
00266 void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
00267                 int16_t x1, int16_t y1, 
00268                 int16_t x2, int16_t y2, uint16_t color) {
00269   drawLine(x0, y0, x1, y1, color);
00270   drawLine(x1, y1, x2, y2, color);
00271   drawLine(x2, y2, x0, y0, color);
00272 }
00273 
00274 // fill a triangle!
00275 void Adafruit_GFX::fillTriangle ( int16_t x0, int16_t y0,
00276                   int16_t x1, int16_t y1, 
00277                   int16_t x2, int16_t y2, uint16_t color) {
00278 
00279   int16_t a, b, y, last;
00280 
00281   // Sort coordinates by Y order (y2 >= y1 >= y0)
00282   if (y0 > y1) {
00283     aswap(y0, y1); aswap(x0, x1);
00284   }
00285   if (y1 > y2) {
00286     aswap(y2, y1); aswap(x2, x1);
00287   }
00288   if (y0 > y1) {
00289     aswap(y0, y1); aswap(x0, x1);
00290   }
00291 
00292   if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
00293     a = b = x0;
00294     if(x1 < a)      a = x1;
00295     else if(x1 > b) b = x1;
00296     if(x2 < a)      a = x2;
00297     else if(x2 > b) b = x2;
00298     drawFastHLine(a, y0, b-a+1, color);
00299     return;
00300   }
00301 
00302   int16_t
00303     dx01 = x1 - x0,
00304     dy01 = y1 - y0,
00305     dx02 = x2 - x0,
00306     dy02 = y2 - y0,
00307     dx12 = x2 - x1,
00308     dy12 = y2 - y1,
00309     sa   = 0,
00310     sb   = 0;
00311 
00312   // For upper part of triangle, find scanline crossings for segments
00313   // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
00314   // is included here (and second loop will be skipped, avoiding a /0
00315   // error there), otherwise scanline y1 is skipped here and handled
00316   // in the second loop...which also avoids a /0 error here if y0=y1
00317   // (flat-topped triangle).
00318   if(y1 == y2) last = y1;   // Include y1 scanline
00319   else         last = y1-1; // Skip it
00320 
00321   for(y=y0; y<=last; y++) {
00322     a   = x0 + sa / dy01;
00323     b   = x0 + sb / dy02;
00324     sa += dx01;
00325     sb += dx02;
00326     /* longhand:
00327     a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
00328     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
00329     */
00330     if(a > b) aswap(a,b);
00331     drawFastHLine(a, y, b-a+1, color);
00332   }
00333 
00334   // For lower part of triangle, find scanline crossings for segments
00335   // 0-2 and 1-2.  This loop is skipped if y1=y2.
00336   sa = dx12 * (y - y1);
00337   sb = dx02 * (y - y0);
00338   for(; y<=y2; y++) {
00339     a   = x1 + sa / dy12;
00340     b   = x0 + sb / dy02;
00341     sa += dx12;
00342     sb += dx02;
00343     /* longhand:
00344     a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
00345     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
00346     */
00347     if(a > b) aswap(a,b);
00348     drawFastHLine(a, y, b-a+1, color);
00349   }
00350 }
00351 
00352 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 
00353                   const uint8_t *bitmap, int16_t w, int16_t h,
00354                   uint16_t color) {
00355 
00356   int16_t i, j, byteWidth = (w + 7) / 8;
00357 
00358   for(j=0; j<h; j++) {
00359     for(i=0; i<w; i++ ) {
00360 //      if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
00361       if(bitmap[ j * byteWidth + i / 8] & (128 >> (i & 7))) {
00362     drawPixel(x+i, y+j, color);
00363       }
00364     }
00365   }
00366 }
00367 
00368 int  Adafruit_GFX::_putc(int c) {
00369   if (c == '\n') {
00370     cursor_y += textsize*8;
00371     cursor_x = 0;
00372   } else if (c == '\r') {
00373     // skip em
00374   } else {
00375     drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
00376     cursor_x += textsize*6;
00377     if (wrap && (cursor_x > (_width - textsize*6))) {
00378       cursor_y += textsize*8;
00379       cursor_x = 0;
00380     }
00381   }
00382 
00383   return c;
00384 }
00385 int Adafruit_GFX::_getc() {
00386     return -1;
00387 }
00388 
00389 // draw a character
00390 void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
00391                 uint16_t color, uint16_t bg, uint8_t size) {
00392 
00393   if((x >= _width)            || // Clip right
00394      (y >= _height)           || // Clip bottom
00395      ((x + 6 * size - 1) < 0) || // Clip left
00396      ((y + 8 * size - 1) < 0))   // Clip top
00397     return;
00398 
00399   for (int8_t i=0; i<6; i++ ) {
00400     uint8_t line;
00401     if (i == 5) 
00402       line = 0x0;
00403     else 
00404       line = font[(c*5)+i];
00405     for (int8_t j = 0; j<8; j++) {
00406       if (line & 0x1) {
00407         if (size == 1) // default size
00408           drawPixel(x+i, y+j, color);
00409         else {  // big size
00410           fillRect(x+(i*size), y+(j*size), size, size, color);
00411         } 
00412       } else if (bg != color) {
00413         if (size == 1) // default size
00414           drawPixel(x+i, y+j, bg);
00415         else {  // big size
00416           fillRect(x+i*size, y+j*size, size, size, bg);
00417         }   
00418       }
00419       line >>= 1;
00420     }
00421   }
00422 }
00423 
00424 void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
00425   cursor_x = x;
00426   cursor_y = y;
00427 }
00428 
00429 
00430 void Adafruit_GFX::setTextSize(uint8_t s) {
00431   textsize = (s > 0) ? s : 1;
00432 }
00433 
00434 
00435 void Adafruit_GFX::setTextColor(uint16_t c) {
00436   textcolor = c;
00437   textbgcolor = c; 
00438   // for 'transparent' background, we'll set the bg 
00439   // to the same as fg instead of using a flag
00440 }
00441 
00442  void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
00443    textcolor = c;
00444    textbgcolor = b; 
00445  }
00446 
00447 void Adafruit_GFX::setTextWrap(boolean w) {
00448   wrap = w;
00449 }
00450 
00451 uint8_t Adafruit_GFX::getRotation(void) {
00452   rotation %= 4;
00453   return rotation;
00454 }
00455 
00456 void Adafruit_GFX::setRotation(uint8_t x) {
00457   x %= 4;  // cant be higher than 3
00458   rotation = x;
00459   switch (x) {
00460   case 0:
00461   case 2:
00462     _width = WIDTH;
00463     _height = HEIGHT;
00464     break;
00465   case 1:
00466   case 3:
00467     _width = HEIGHT;
00468     _height = WIDTH;
00469     break;
00470   }
00471 }
00472 
00473 
00474 void Adafruit_GFX::invertDisplay(boolean i) {
00475   // do nothing, can be subclassed
00476 }
00477 
00478 
00479 // return the size of the display which depends on the rotation!
00480 int16_t Adafruit_GFX::width(void) { 
00481   return _width; 
00482 }
00483  
00484 int16_t Adafruit_GFX::height(void) { 
00485   return _height; 
00486 }