Liam Lee / Adafruit_GFX_DOC

Fork of Adafruit_GFX by Andrew Lindsay

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