Adafruit_GFX.cpp 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962
  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. Adafruit invests time and resources providing this open source code, please
  7. support Adafruit & open-source hardware by purchasing products from Adafruit!
  8. Copyright (c) 2013 Adafruit Industries. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions are met:
  11. - Redistributions of source code must retain the above copyright notice,
  12. this list of conditions and the following disclaimer.
  13. - Redistributions in binary form must reproduce the above copyright notice,
  14. this list of conditions and the following disclaimer in the documentation
  15. and/or other materials provided with the distribution.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  20. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include "Adafruit_GFX.h"
  29. #include "glcdfont.c"
  30. #ifdef __AVR__
  31. #include <avr/pgmspace.h>
  32. #elif defined(ESP8266) || defined(ESP32)
  33. #include <pgmspace.h>
  34. #endif
  35. // Many (but maybe not all) non-AVR board installs define macros
  36. // for compatibility with existing PROGMEM-reading AVR code.
  37. // Do our own checks and defines here for good measure...
  38. #ifndef pgm_read_byte
  39. #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
  40. #endif
  41. #ifndef pgm_read_word
  42. #define pgm_read_word(addr) (*(const unsigned short *)(addr))
  43. #endif
  44. #ifndef pgm_read_dword
  45. #define pgm_read_dword(addr) (*(const unsigned long *)(addr))
  46. #endif
  47. // Pointers are a peculiar case...typically 16-bit on AVR boards,
  48. // 32 bits elsewhere. Try to accommodate both...
  49. #if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
  50. #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
  51. #else
  52. #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
  53. #endif
  54. #ifndef min
  55. #define min(a,b) (((a) < (b)) ? (a) : (b))
  56. #endif
  57. #ifndef _swap_int16_t
  58. #define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
  59. #endif
  60. /**************************************************************************/
  61. /*!
  62. @brief Instatiate a GFX context for graphics! Can only be done by a superclass
  63. @param w Display width, in pixels
  64. @param h Display height, in pixels
  65. */
  66. /**************************************************************************/
  67. Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
  68. WIDTH(w), HEIGHT(h)
  69. {
  70. _width = WIDTH;
  71. _height = HEIGHT;
  72. rotation = 0;
  73. cursor_y = cursor_x = 0;
  74. textsize = 1;
  75. textcolor = textbgcolor = 0xFFFF;
  76. wrap = true;
  77. _cp437 = false;
  78. gfxFont = NULL;
  79. }
  80. /**************************************************************************/
  81. /*!
  82. @brief Write a line. Bresenham's algorithm - thx wikpedia
  83. @param x0 Start point x coordinate
  84. @param y0 Start point y coordinate
  85. @param x1 End point x coordinate
  86. @param y1 End point y coordinate
  87. @param color 16-bit 5-6-5 Color to draw with
  88. */
  89. /**************************************************************************/
  90. void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
  91. uint16_t color) {
  92. int16_t steep = abs(y1 - y0) > abs(x1 - x0);
  93. if (steep) {
  94. _swap_int16_t(x0, y0);
  95. _swap_int16_t(x1, y1);
  96. }
  97. if (x0 > x1) {
  98. _swap_int16_t(x0, x1);
  99. _swap_int16_t(y0, y1);
  100. }
  101. int16_t dx, dy;
  102. dx = x1 - x0;
  103. dy = abs(y1 - y0);
  104. int16_t err = dx / 2;
  105. int16_t ystep;
  106. if (y0 < y1) {
  107. ystep = 1;
  108. } else {
  109. ystep = -1;
  110. }
  111. for (; x0<=x1; x0++) {
  112. if (steep) {
  113. writePixel(y0, x0, color);
  114. } else {
  115. writePixel(x0, y0, color);
  116. }
  117. err -= dy;
  118. if (err < 0) {
  119. y0 += ystep;
  120. err += dx;
  121. }
  122. }
  123. }
  124. /**************************************************************************/
  125. /*!
  126. @brief Start a display-writing routine, overwrite in subclasses.
  127. */
  128. /**************************************************************************/
  129. void Adafruit_GFX::startWrite(){
  130. }
  131. /**************************************************************************/
  132. /*!
  133. @brief Write a pixel, overwrite in subclasses if startWrite is defined!
  134. @param x x coordinate
  135. @param y y coordinate
  136. @param color 16-bit 5-6-5 Color to fill with
  137. */
  138. /**************************************************************************/
  139. void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color){
  140. drawPixel(x, y, color);
  141. }
  142. /**************************************************************************/
  143. /*!
  144. @brief Write a perfectly vertical line, overwrite in subclasses if startWrite is defined!
  145. @param x Top-most x coordinate
  146. @param y Top-most y coordinate
  147. @param h Height in pixels
  148. @param color 16-bit 5-6-5 Color to fill with
  149. */
  150. /**************************************************************************/
  151. void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y,
  152. int16_t h, uint16_t color) {
  153. // Overwrite in subclasses if startWrite is defined!
  154. // Can be just writeLine(x, y, x, y+h-1, color);
  155. // or writeFillRect(x, y, 1, h, color);
  156. drawFastVLine(x, y, h, color);
  157. }
  158. /**************************************************************************/
  159. /*!
  160. @brief Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined!
  161. @param x Left-most x coordinate
  162. @param y Left-most y coordinate
  163. @param w Width in pixels
  164. @param color 16-bit 5-6-5 Color to fill with
  165. */
  166. /**************************************************************************/
  167. void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y,
  168. int16_t w, uint16_t color) {
  169. // Overwrite in subclasses if startWrite is defined!
  170. // Example: writeLine(x, y, x+w-1, y, color);
  171. // or writeFillRect(x, y, w, 1, color);
  172. drawFastHLine(x, y, w, color);
  173. }
  174. /**************************************************************************/
  175. /*!
  176. @brief Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined!
  177. @param x Top left corner x coordinate
  178. @param y Top left corner y coordinate
  179. @param w Width in pixels
  180. @param h Height in pixels
  181. @param color 16-bit 5-6-5 Color to fill with
  182. */
  183. /**************************************************************************/
  184. void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
  185. uint16_t color) {
  186. // Overwrite in subclasses if desired!
  187. fillRect(x,y,w,h,color);
  188. }
  189. /**************************************************************************/
  190. /*!
  191. @brief End a display-writing routine, overwrite in subclasses if startWrite is defined!
  192. */
  193. /**************************************************************************/
  194. void Adafruit_GFX::endWrite(){
  195. }
  196. /**************************************************************************/
  197. /*!
  198. @brief Draw a perfectly vertical line (this is often optimized in a subclass!)
  199. @param x Top-most x coordinate
  200. @param y Top-most y coordinate
  201. @param h Height in pixels
  202. @param color 16-bit 5-6-5 Color to fill with
  203. */
  204. /**************************************************************************/
  205. void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
  206. int16_t h, uint16_t color) {
  207. startWrite();
  208. writeLine(x, y, x, y+h-1, color);
  209. endWrite();
  210. }
  211. /**************************************************************************/
  212. /*!
  213. @brief Draw a perfectly horizontal line (this is often optimized in a subclass!)
  214. @param x Left-most x coordinate
  215. @param y Left-most y coordinate
  216. @param w Width in pixels
  217. @param color 16-bit 5-6-5 Color to fill with
  218. */
  219. /**************************************************************************/
  220. void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
  221. int16_t w, uint16_t color) {
  222. startWrite();
  223. writeLine(x, y, x+w-1, y, color);
  224. endWrite();
  225. }
  226. /**************************************************************************/
  227. /*!
  228. @brief Fill a rectangle completely with one color. Update in subclasses if desired!
  229. @param x Top left corner x coordinate
  230. @param y Top left corner y coordinate
  231. @param w Width in pixels
  232. @param h Height in pixels
  233. @param color 16-bit 5-6-5 Color to fill with
  234. */
  235. /**************************************************************************/
  236. void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
  237. uint16_t color) {
  238. startWrite();
  239. for (int16_t i=x; i<x+w; i++) {
  240. writeFastVLine(i, y, h, color);
  241. }
  242. endWrite();
  243. }
  244. /**************************************************************************/
  245. /*!
  246. @brief Fill the screen completely with one color. Update in subclasses if desired!
  247. @param color 16-bit 5-6-5 Color to fill with
  248. */
  249. /**************************************************************************/
  250. void Adafruit_GFX::fillScreen(uint16_t color) {
  251. fillRect(0, 0, _width, _height, color);
  252. }
  253. /**************************************************************************/
  254. /*!
  255. @brief Draw a line
  256. @param x0 Start point x coordinate
  257. @param y0 Start point y coordinate
  258. @param x1 End point x coordinate
  259. @param y1 End point y coordinate
  260. @param color 16-bit 5-6-5 Color to draw with
  261. */
  262. /**************************************************************************/
  263. void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
  264. uint16_t color) {
  265. // Update in subclasses if desired!
  266. if(x0 == x1){
  267. if(y0 > y1) _swap_int16_t(y0, y1);
  268. drawFastVLine(x0, y0, y1 - y0 + 1, color);
  269. } else if(y0 == y1){
  270. if(x0 > x1) _swap_int16_t(x0, x1);
  271. drawFastHLine(x0, y0, x1 - x0 + 1, color);
  272. } else {
  273. startWrite();
  274. writeLine(x0, y0, x1, y1, color);
  275. endWrite();
  276. }
  277. }
  278. /**************************************************************************/
  279. /*!
  280. @brief Draw a circle outline
  281. @param x0 Center-point x coordinate
  282. @param y0 Center-point y coordinate
  283. @param r Radius of circle
  284. @param color 16-bit 5-6-5 Color to draw with
  285. */
  286. /**************************************************************************/
  287. void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
  288. uint16_t color) {
  289. int16_t f = 1 - r;
  290. int16_t ddF_x = 1;
  291. int16_t ddF_y = -2 * r;
  292. int16_t x = 0;
  293. int16_t y = r;
  294. startWrite();
  295. writePixel(x0 , y0+r, color);
  296. writePixel(x0 , y0-r, color);
  297. writePixel(x0+r, y0 , color);
  298. writePixel(x0-r, y0 , color);
  299. while (x<y) {
  300. if (f >= 0) {
  301. y--;
  302. ddF_y += 2;
  303. f += ddF_y;
  304. }
  305. x++;
  306. ddF_x += 2;
  307. f += ddF_x;
  308. writePixel(x0 + x, y0 + y, color);
  309. writePixel(x0 - x, y0 + y, color);
  310. writePixel(x0 + x, y0 - y, color);
  311. writePixel(x0 - x, y0 - y, color);
  312. writePixel(x0 + y, y0 + x, color);
  313. writePixel(x0 - y, y0 + x, color);
  314. writePixel(x0 + y, y0 - x, color);
  315. writePixel(x0 - y, y0 - x, color);
  316. }
  317. endWrite();
  318. }
  319. /**************************************************************************/
  320. /*!
  321. @brief Quarter-circle drawer, used to do circles and roundrects
  322. @param x0 Center-point x coordinate
  323. @param y0 Center-point y coordinate
  324. @param r Radius of circle
  325. @param cornername Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing
  326. @param color 16-bit 5-6-5 Color to draw with
  327. */
  328. /**************************************************************************/
  329. void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
  330. int16_t r, uint8_t cornername, uint16_t color) {
  331. int16_t f = 1 - r;
  332. int16_t ddF_x = 1;
  333. int16_t ddF_y = -2 * r;
  334. int16_t x = 0;
  335. int16_t y = r;
  336. while (x<y) {
  337. if (f >= 0) {
  338. y--;
  339. ddF_y += 2;
  340. f += ddF_y;
  341. }
  342. x++;
  343. ddF_x += 2;
  344. f += ddF_x;
  345. if (cornername & 0x4) {
  346. writePixel(x0 + x, y0 + y, color);
  347. writePixel(x0 + y, y0 + x, color);
  348. }
  349. if (cornername & 0x2) {
  350. writePixel(x0 + x, y0 - y, color);
  351. writePixel(x0 + y, y0 - x, color);
  352. }
  353. if (cornername & 0x8) {
  354. writePixel(x0 - y, y0 + x, color);
  355. writePixel(x0 - x, y0 + y, color);
  356. }
  357. if (cornername & 0x1) {
  358. writePixel(x0 - y, y0 - x, color);
  359. writePixel(x0 - x, y0 - y, color);
  360. }
  361. }
  362. }
  363. /**************************************************************************/
  364. /*!
  365. @brief Draw a circle with filled color
  366. @param x0 Center-point x coordinate
  367. @param y0 Center-point y coordinate
  368. @param r Radius of circle
  369. @param color 16-bit 5-6-5 Color to fill with
  370. */
  371. /**************************************************************************/
  372. void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
  373. uint16_t color) {
  374. startWrite();
  375. writeFastVLine(x0, y0-r, 2*r+1, color);
  376. fillCircleHelper(x0, y0, r, 3, 0, color);
  377. endWrite();
  378. }
  379. /**************************************************************************/
  380. /*!
  381. @brief Quarter-circle drawer with fill, used to do circles and roundrects
  382. @param x0 Center-point x coordinate
  383. @param y0 Center-point y coordinate
  384. @param r Radius of circle
  385. @param cornername Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing
  386. @param delta Offset from center-point, used for round-rects
  387. @param color 16-bit 5-6-5 Color to fill with
  388. */
  389. /**************************************************************************/
  390. void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
  391. uint8_t cornername, int16_t delta, uint16_t color) {
  392. int16_t f = 1 - r;
  393. int16_t ddF_x = 1;
  394. int16_t ddF_y = -2 * r;
  395. int16_t x = 0;
  396. int16_t y = r;
  397. while (x<y) {
  398. if (f >= 0) {
  399. y--;
  400. ddF_y += 2;
  401. f += ddF_y;
  402. }
  403. x++;
  404. ddF_x += 2;
  405. f += ddF_x;
  406. if (cornername & 0x1) {
  407. writeFastVLine(x0+x, y0-y, 2*y+1+delta, color);
  408. writeFastVLine(x0+y, y0-x, 2*x+1+delta, color);
  409. }
  410. if (cornername & 0x2) {
  411. writeFastVLine(x0-x, y0-y, 2*y+1+delta, color);
  412. writeFastVLine(x0-y, y0-x, 2*x+1+delta, color);
  413. }
  414. }
  415. }
  416. /**************************************************************************/
  417. /*!
  418. @brief Draw a rectangle with no fill color
  419. @param x Top left corner x coordinate
  420. @param y Top left corner y coordinate
  421. @param w Width in pixels
  422. @param h Height in pixels
  423. @param color 16-bit 5-6-5 Color to draw with
  424. */
  425. /**************************************************************************/
  426. void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
  427. uint16_t color) {
  428. startWrite();
  429. writeFastHLine(x, y, w, color);
  430. writeFastHLine(x, y+h-1, w, color);
  431. writeFastVLine(x, y, h, color);
  432. writeFastVLine(x+w-1, y, h, color);
  433. endWrite();
  434. }
  435. /**************************************************************************/
  436. /*!
  437. @brief Draw a rounded rectangle with no fill color
  438. @param x Top left corner x coordinate
  439. @param y Top left corner y coordinate
  440. @param w Width in pixels
  441. @param h Height in pixels
  442. @param r Radius of corner rounding
  443. @param color 16-bit 5-6-5 Color to draw with
  444. */
  445. /**************************************************************************/
  446. void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
  447. int16_t h, int16_t r, uint16_t color) {
  448. // smarter version
  449. startWrite();
  450. writeFastHLine(x+r , y , w-2*r, color); // Top
  451. writeFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
  452. writeFastVLine(x , y+r , h-2*r, color); // Left
  453. writeFastVLine(x+w-1, y+r , h-2*r, color); // Right
  454. // draw four corners
  455. drawCircleHelper(x+r , y+r , r, 1, color);
  456. drawCircleHelper(x+w-r-1, y+r , r, 2, color);
  457. drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
  458. drawCircleHelper(x+r , y+h-r-1, r, 8, color);
  459. endWrite();
  460. }
  461. /**************************************************************************/
  462. /*!
  463. @brief Draw a rounded rectangle with fill color
  464. @param x Top left corner x coordinate
  465. @param y Top left corner y coordinate
  466. @param w Width in pixels
  467. @param h Height in pixels
  468. @param r Radius of corner rounding
  469. @param color 16-bit 5-6-5 Color to draw/fill with
  470. */
  471. /**************************************************************************/
  472. void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
  473. int16_t h, int16_t r, uint16_t color) {
  474. // smarter version
  475. startWrite();
  476. writeFillRect(x+r, y, w-2*r, h, color);
  477. // draw four corners
  478. fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
  479. fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color);
  480. endWrite();
  481. }
  482. /**************************************************************************/
  483. /*!
  484. @brief Draw a triangle with no fill color
  485. @param x0 Vertex #0 x coordinate
  486. @param y0 Vertex #0 y coordinate
  487. @param x1 Vertex #1 x coordinate
  488. @param y1 Vertex #1 y coordinate
  489. @param x2 Vertex #2 x coordinate
  490. @param y2 Vertex #2 y coordinate
  491. @param color 16-bit 5-6-5 Color to draw with
  492. */
  493. /**************************************************************************/
  494. void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
  495. int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
  496. drawLine(x0, y0, x1, y1, color);
  497. drawLine(x1, y1, x2, y2, color);
  498. drawLine(x2, y2, x0, y0, color);
  499. }
  500. /**************************************************************************/
  501. /*!
  502. @brief Draw a triangle with color-fill
  503. @param x0 Vertex #0 x coordinate
  504. @param y0 Vertex #0 y coordinate
  505. @param x1 Vertex #1 x coordinate
  506. @param y1 Vertex #1 y coordinate
  507. @param x2 Vertex #2 x coordinate
  508. @param y2 Vertex #2 y coordinate
  509. @param color 16-bit 5-6-5 Color to fill/draw with
  510. */
  511. /**************************************************************************/
  512. void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
  513. int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
  514. int16_t a, b, y, last;
  515. // Sort coordinates by Y order (y2 >= y1 >= y0)
  516. if (y0 > y1) {
  517. _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
  518. }
  519. if (y1 > y2) {
  520. _swap_int16_t(y2, y1); _swap_int16_t(x2, x1);
  521. }
  522. if (y0 > y1) {
  523. _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
  524. }
  525. startWrite();
  526. if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
  527. a = b = x0;
  528. if(x1 < a) a = x1;
  529. else if(x1 > b) b = x1;
  530. if(x2 < a) a = x2;
  531. else if(x2 > b) b = x2;
  532. writeFastHLine(a, y0, b-a+1, color);
  533. endWrite();
  534. return;
  535. }
  536. int16_t
  537. dx01 = x1 - x0,
  538. dy01 = y1 - y0,
  539. dx02 = x2 - x0,
  540. dy02 = y2 - y0,
  541. dx12 = x2 - x1,
  542. dy12 = y2 - y1;
  543. int32_t
  544. sa = 0,
  545. sb = 0;
  546. // For upper part of triangle, find scanline crossings for segments
  547. // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
  548. // is included here (and second loop will be skipped, avoiding a /0
  549. // error there), otherwise scanline y1 is skipped here and handled
  550. // in the second loop...which also avoids a /0 error here if y0=y1
  551. // (flat-topped triangle).
  552. if(y1 == y2) last = y1; // Include y1 scanline
  553. else last = y1-1; // Skip it
  554. for(y=y0; y<=last; y++) {
  555. a = x0 + sa / dy01;
  556. b = x0 + sb / dy02;
  557. sa += dx01;
  558. sb += dx02;
  559. /* longhand:
  560. a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
  561. b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
  562. */
  563. if(a > b) _swap_int16_t(a,b);
  564. writeFastHLine(a, y, b-a+1, color);
  565. }
  566. // For lower part of triangle, find scanline crossings for segments
  567. // 0-2 and 1-2. This loop is skipped if y1=y2.
  568. sa = dx12 * (y - y1);
  569. sb = dx02 * (y - y0);
  570. for(; y<=y2; y++) {
  571. a = x1 + sa / dy12;
  572. b = x0 + sb / dy02;
  573. sa += dx12;
  574. sb += dx02;
  575. /* longhand:
  576. a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
  577. b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
  578. */
  579. if(a > b) _swap_int16_t(a,b);
  580. writeFastHLine(a, y, b-a+1, color);
  581. }
  582. endWrite();
  583. }
  584. // BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
  585. /**************************************************************************/
  586. /*!
  587. @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
  588. @param x Top left corner x coordinate
  589. @param y Top left corner y coordinate
  590. @param bitmap byte array with monochrome bitmap
  591. @param w Width of bitmap in pixels
  592. @param h Hieght of bitmap in pixels
  593. @param color 16-bit 5-6-5 Color to draw with
  594. */
  595. /**************************************************************************/
  596. void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  597. const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {
  598. int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  599. uint8_t byte = 0;
  600. startWrite();
  601. for(int16_t j=0; j<h; j++, y++) {
  602. for(int16_t i=0; i<w; i++) {
  603. if(i & 7) byte <<= 1;
  604. else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
  605. if(byte & 0x80) writePixel(x+i, y, color);
  606. }
  607. }
  608. endWrite();
  609. }
  610. /**************************************************************************/
  611. /*!
  612. @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.
  613. @param x Top left corner x coordinate
  614. @param y Top left corner y coordinate
  615. @param bitmap byte array with monochrome bitmap
  616. @param w Width of bitmap in pixels
  617. @param h Hieght of bitmap in pixels
  618. @param color 16-bit 5-6-5 Color to draw pixels with
  619. @param bg 16-bit 5-6-5 Color to draw background with
  620. */
  621. /**************************************************************************/
  622. void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  623. const uint8_t bitmap[], int16_t w, int16_t h,
  624. uint16_t color, uint16_t bg) {
  625. int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  626. uint8_t byte = 0;
  627. startWrite();
  628. for(int16_t j=0; j<h; j++, y++) {
  629. for(int16_t i=0; i<w; i++ ) {
  630. if(i & 7) byte <<= 1;
  631. else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
  632. writePixel(x+i, y, (byte & 0x80) ? color : bg);
  633. }
  634. }
  635. endWrite();
  636. }
  637. /**************************************************************************/
  638. /*!
  639. @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
  640. @param x Top left corner x coordinate
  641. @param y Top left corner y coordinate
  642. @param bitmap byte array with monochrome bitmap
  643. @param w Width of bitmap in pixels
  644. @param h Hieght of bitmap in pixels
  645. @param color 16-bit 5-6-5 Color to draw with
  646. */
  647. /**************************************************************************/
  648. void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  649. uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
  650. int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  651. uint8_t byte = 0;
  652. startWrite();
  653. for(int16_t j=0; j<h; j++, y++) {
  654. for(int16_t i=0; i<w; i++ ) {
  655. if(i & 7) byte <<= 1;
  656. else byte = bitmap[j * byteWidth + i / 8];
  657. if(byte & 0x80) writePixel(x+i, y, color);
  658. }
  659. }
  660. endWrite();
  661. }
  662. /**************************************************************************/
  663. /*!
  664. @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.
  665. @param x Top left corner x coordinate
  666. @param y Top left corner y coordinate
  667. @param bitmap byte array with monochrome bitmap
  668. @param w Width of bitmap in pixels
  669. @param h Hieght of bitmap in pixels
  670. @param color 16-bit 5-6-5 Color to draw pixels with
  671. @param bg 16-bit 5-6-5 Color to draw background with
  672. */
  673. /**************************************************************************/
  674. void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
  675. uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
  676. int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  677. uint8_t byte = 0;
  678. startWrite();
  679. for(int16_t j=0; j<h; j++, y++) {
  680. for(int16_t i=0; i<w; i++ ) {
  681. if(i & 7) byte <<= 1;
  682. else byte = bitmap[j * byteWidth + i / 8];
  683. writePixel(x+i, y, (byte & 0x80) ? color : bg);
  684. }
  685. }
  686. endWrite();
  687. }
  688. /**************************************************************************/
  689. /*!
  690. @brief Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP.
  691. Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
  692. C Array can be directly used with this function.
  693. There is no RAM-resident version of this function; if generating bitmaps
  694. in RAM, use the format defined by drawBitmap() and call that instead.
  695. @param x Top left corner x coordinate
  696. @param y Top left corner y coordinate
  697. @param bitmap byte array with monochrome bitmap
  698. @param w Width of bitmap in pixels
  699. @param h Hieght of bitmap in pixels
  700. @param color 16-bit 5-6-5 Color to draw pixels with
  701. */
  702. /**************************************************************************/
  703. void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
  704. const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) {
  705. int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  706. uint8_t byte = 0;
  707. startWrite();
  708. for(int16_t j=0; j<h; j++, y++) {
  709. for(int16_t i=0; i<w; i++ ) {
  710. if(i & 7) byte >>= 1;
  711. else byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
  712. // Nearly identical to drawBitmap(), only the bit order
  713. // is reversed here (left-to-right = LSB to MSB):
  714. if(byte & 0x01) writePixel(x+i, y, color);
  715. }
  716. }
  717. endWrite();
  718. }
  719. /**************************************************************************/
  720. /*!
  721. @brief Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos.
  722. Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
  723. @param x Top left corner x coordinate
  724. @param y Top left corner y coordinate
  725. @param bitmap byte array with grayscale bitmap
  726. @param w Width of bitmap in pixels
  727. @param h Hieght of bitmap in pixels
  728. */
  729. /**************************************************************************/
  730. void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  731. const uint8_t bitmap[], int16_t w, int16_t h) {
  732. startWrite();
  733. for(int16_t j=0; j<h; j++, y++) {
  734. for(int16_t i=0; i<w; i++ ) {
  735. writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
  736. }
  737. }
  738. endWrite();
  739. }
  740. /**************************************************************************/
  741. /*!
  742. @brief Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos.
  743. Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
  744. @param x Top left corner x coordinate
  745. @param y Top left corner y coordinate
  746. @param bitmap byte array with grayscale bitmap
  747. @param w Width of bitmap in pixels
  748. @param h Hieght of bitmap in pixels
  749. */
  750. /**************************************************************************/
  751. void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  752. uint8_t *bitmap, int16_t w, int16_t h) {
  753. startWrite();
  754. for(int16_t j=0; j<h; j++, y++) {
  755. for(int16_t i=0; i<w; i++ ) {
  756. writePixel(x+i, y, bitmap[j * w + i]);
  757. }
  758. }
  759. endWrite();
  760. }
  761. /**************************************************************************/
  762. /*!
  763. @brief Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask
  764. (set bits = opaque, unset bits = clear) at the specified (x,y) position.
  765. BOTH buffers (grayscale and mask) must be PROGMEM-resident.
  766. Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
  767. @param x Top left corner x coordinate
  768. @param y Top left corner y coordinate
  769. @param bitmap byte array with grayscale bitmap
  770. @param mask byte array with mask bitmap
  771. @param w Width of bitmap in pixels
  772. @param h Height of bitmap in pixels
  773. */
  774. /**************************************************************************/
  775. void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  776. const uint8_t bitmap[], const uint8_t mask[],
  777. int16_t w, int16_t h) {
  778. int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
  779. uint8_t byte = 0;
  780. startWrite();
  781. for(int16_t j=0; j<h; j++, y++) {
  782. for(int16_t i=0; i<w; i++ ) {
  783. if(i & 7) byte <<= 1;
  784. else byte = pgm_read_byte(&mask[j * bw + i / 8]);
  785. if(byte & 0x80) {
  786. writePixel(x+i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
  787. }
  788. }
  789. }
  790. endWrite();
  791. }
  792. /**************************************************************************/
  793. /*!
  794. @brief Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask
  795. (set bits = opaque, unset bits = clear) at the specified (x,y) position.
  796. BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match
  797. Specifically for 8-bit display devices such as IS31FL3731; no color reduction/expansion is performed.
  798. @param x Top left corner x coordinate
  799. @param y Top left corner y coordinate
  800. @param bitmap byte array with grayscale bitmap
  801. @param mask byte array with mask bitmap
  802. @param w Width of bitmap in pixels
  803. @param h Height of bitmap in pixels
  804. */
  805. /**************************************************************************/
  806. void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
  807. uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) {
  808. int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
  809. uint8_t byte = 0;
  810. startWrite();
  811. for(int16_t j=0; j<h; j++, y++) {
  812. for(int16_t i=0; i<w; i++ ) {
  813. if(i & 7) byte <<= 1;
  814. else byte = mask[j * bw + i / 8];
  815. if(byte & 0x80) {
  816. writePixel(x+i, y, bitmap[j * w + i]);
  817. }
  818. }
  819. }
  820. endWrite();
  821. }
  822. /**************************************************************************/
  823. /*!
  824. @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
  825. For 16-bit display devices; no color reduction performed.
  826. @param x Top left corner x coordinate
  827. @param y Top left corner y coordinate
  828. @param bitmap byte array with 16-bit color bitmap
  829. @param w Width of bitmap in pixels
  830. @param h Height of bitmap in pixels
  831. */
  832. /**************************************************************************/
  833. void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  834. const uint16_t bitmap[], int16_t w, int16_t h) {
  835. startWrite();
  836. for(int16_t j=0; j<h; j++, y++) {
  837. for(int16_t i=0; i<w; i++ ) {
  838. writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
  839. }
  840. }
  841. endWrite();
  842. }
  843. /**************************************************************************/
  844. /*!
  845. @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
  846. For 16-bit display devices; no color reduction performed.
  847. @param x Top left corner x coordinate
  848. @param y Top left corner y coordinate
  849. @param bitmap byte array with 16-bit color bitmap
  850. @param w Width of bitmap in pixels
  851. @param h Height of bitmap in pixels
  852. */
  853. /**************************************************************************/
  854. void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  855. uint16_t *bitmap, int16_t w, int16_t h) {
  856. startWrite();
  857. for(int16_t j=0; j<h; j++, y++) {
  858. for(int16_t i=0; i<w; i++ ) {
  859. writePixel(x+i, y, bitmap[j * w + i]);
  860. }
  861. }
  862. endWrite();
  863. }
  864. /**************************************************************************/
  865. /*!
  866. @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH buffers (color and mask) must be PROGMEM-resident. For 16-bit display devices; no color reduction performed.
  867. @param x Top left corner x coordinate
  868. @param y Top left corner y coordinate
  869. @param bitmap byte array with 16-bit color bitmap
  870. @param mask byte array with monochrome mask bitmap
  871. @param w Width of bitmap in pixels
  872. @param h Height of bitmap in pixels
  873. */
  874. /**************************************************************************/
  875. void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  876. const uint16_t bitmap[], const uint8_t mask[],
  877. int16_t w, int16_t h) {
  878. int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
  879. uint8_t byte = 0;
  880. startWrite();
  881. for(int16_t j=0; j<h; j++, y++) {
  882. for(int16_t i=0; i<w; i++ ) {
  883. if(i & 7) byte <<= 1;
  884. else byte = pgm_read_byte(&mask[j * bw + i / 8]);
  885. if(byte & 0x80) {
  886. writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
  887. }
  888. }
  889. }
  890. endWrite();
  891. }
  892. /**************************************************************************/
  893. /*!
  894. @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH buffers (color and mask) must be RAM-resident. For 16-bit display devices; no color reduction performed.
  895. @param x Top left corner x coordinate
  896. @param y Top left corner y coordinate
  897. @param bitmap byte array with 16-bit color bitmap
  898. @param mask byte array with monochrome mask bitmap
  899. @param w Width of bitmap in pixels
  900. @param h Height of bitmap in pixels
  901. */
  902. /**************************************************************************/
  903. void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y,
  904. uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h) {
  905. int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
  906. uint8_t byte = 0;
  907. startWrite();
  908. for(int16_t j=0; j<h; j++, y++) {
  909. for(int16_t i=0; i<w; i++ ) {
  910. if(i & 7) byte <<= 1;
  911. else byte = mask[j * bw + i / 8];
  912. if(byte & 0x80) {
  913. writePixel(x+i, y, bitmap[j * w + i]);
  914. }
  915. }
  916. }
  917. endWrite();
  918. }
  919. // TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
  920. // Draw a character
  921. /**************************************************************************/
  922. /*!
  923. @brief Draw a single character
  924. @param x Bottom left corner x coordinate
  925. @param y Bottom left corner y coordinate
  926. @param c The 8-bit font-indexed character (likely ascii)
  927. @param color 16-bit 5-6-5 Color to draw chraracter with
  928. @param bg 16-bit 5-6-5 Color to fill background with (if same as color, no background)
  929. @param size Font magnification level, 1 is 'original' size
  930. */
  931. /**************************************************************************/
  932. void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
  933. uint16_t color, uint16_t bg, uint8_t size) {
  934. if(!gfxFont) { // 'Classic' built-in font
  935. if((x >= _width) || // Clip right
  936. (y >= _height) || // Clip bottom
  937. ((x + 6 * size - 1) < 0) || // Clip left
  938. ((y + 8 * size - 1) < 0)) // Clip top
  939. return;
  940. if(!_cp437 && (c >= 176)) c++; // Handle 'classic' charset behavior
  941. startWrite();
  942. for(int8_t i=0; i<5; i++ ) { // Char bitmap = 5 columns
  943. uint8_t line = pgm_read_byte(&font[c * 5 + i]);
  944. for(int8_t j=0; j<8; j++, line >>= 1) {
  945. if(line & 1) {
  946. if(size == 1)
  947. writePixel(x+i, y+j, color);
  948. else
  949. writeFillRect(x+i*size, y+j*size, size, size, color);
  950. } else if(bg != color) {
  951. if(size == 1)
  952. writePixel(x+i, y+j, bg);
  953. else
  954. writeFillRect(x+i*size, y+j*size, size, size, bg);
  955. }
  956. }
  957. }
  958. if(bg != color) { // If opaque, draw vertical line for last column
  959. if(size == 1) writeFastVLine(x+5, y, 8, bg);
  960. else writeFillRect(x+5*size, y, size, 8*size, bg);
  961. }
  962. endWrite();
  963. } else { // Custom font
  964. // Character is assumed previously filtered by write() to eliminate
  965. // newlines, returns, non-printable characters, etc. Calling
  966. // drawChar() directly with 'bad' characters of font may cause mayhem!
  967. c -= (uint8_t)pgm_read_byte(&gfxFont->first);
  968. GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
  969. uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
  970. uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
  971. uint8_t w = pgm_read_byte(&glyph->width),
  972. h = pgm_read_byte(&glyph->height);
  973. int8_t xo = pgm_read_byte(&glyph->xOffset),
  974. yo = pgm_read_byte(&glyph->yOffset);
  975. uint8_t xx, yy, bits = 0, bit = 0;
  976. int16_t xo16 = 0, yo16 = 0;
  977. if(size > 1) {
  978. xo16 = xo;
  979. yo16 = yo;
  980. }
  981. // Todo: Add character clipping here
  982. // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
  983. // THIS IS ON PURPOSE AND BY DESIGN. The background color feature
  984. // has typically been used with the 'classic' font to overwrite old
  985. // screen contents with new data. This ONLY works because the
  986. // characters are a uniform size; it's not a sensible thing to do with
  987. // proportionally-spaced fonts with glyphs of varying sizes (and that
  988. // may overlap). To replace previously-drawn text when using a custom
  989. // font, use the getTextBounds() function to determine the smallest
  990. // rectangle encompassing a string, erase the area with fillRect(),
  991. // then draw new text. This WILL infortunately 'blink' the text, but
  992. // is unavoidable. Drawing 'background' pixels will NOT fix this,
  993. // only creates a new set of problems. Have an idea to work around
  994. // this (a canvas object type for MCUs that can afford the RAM and
  995. // displays supporting setAddrWindow() and pushColors()), but haven't
  996. // implemented this yet.
  997. startWrite();
  998. for(yy=0; yy<h; yy++) {
  999. for(xx=0; xx<w; xx++) {
  1000. if(!(bit++ & 7)) {
  1001. bits = pgm_read_byte(&bitmap[bo++]);
  1002. }
  1003. if(bits & 0x80) {
  1004. if(size == 1) {
  1005. writePixel(x+xo+xx, y+yo+yy, color);
  1006. } else {
  1007. writeFillRect(x+(xo16+xx)*size, y+(yo16+yy)*size,
  1008. size, size, color);
  1009. }
  1010. }
  1011. bits <<= 1;
  1012. }
  1013. }
  1014. endWrite();
  1015. } // End classic vs custom font
  1016. }
  1017. /**************************************************************************/
  1018. /*!
  1019. @brief Print one byte/character of data, used to support print()
  1020. @param c The 8-bit ascii character to write
  1021. */
  1022. /**************************************************************************/
  1023. size_t Adafruit_GFX::write(uint8_t c) {
  1024. if(!gfxFont) { // 'Classic' built-in font
  1025. if(c == '\n') { // Newline?
  1026. cursor_x = 0; // Reset x to zero,
  1027. cursor_y += textsize * 8; // advance y one line
  1028. } else if(c != '\r') { // Ignore carriage returns
  1029. if(wrap && ((cursor_x + textsize * 6) > _width)) { // Off right?
  1030. cursor_x = 0; // Reset x to zero,
  1031. cursor_y += textsize * 8; // advance y one line
  1032. }
  1033. drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
  1034. cursor_x += textsize * 6; // Advance x one char
  1035. }
  1036. } else { // Custom font
  1037. if(c == '\n') {
  1038. cursor_x = 0;
  1039. cursor_y += (int16_t)textsize *
  1040. (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
  1041. } else if(c != '\r') {
  1042. uint8_t first = pgm_read_byte(&gfxFont->first);
  1043. if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
  1044. GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(
  1045. &gfxFont->glyph))[c - first]);
  1046. uint8_t w = pgm_read_byte(&glyph->width),
  1047. h = pgm_read_byte(&glyph->height);
  1048. if((w > 0) && (h > 0)) { // Is there an associated bitmap?
  1049. int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
  1050. if(wrap && ((cursor_x + textsize * (xo + w)) > _width)) {
  1051. cursor_x = 0;
  1052. cursor_y += (int16_t)textsize *
  1053. (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
  1054. }
  1055. drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
  1056. }
  1057. cursor_x += (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
  1058. }
  1059. }
  1060. }
  1061. return 1;
  1062. }
  1063. /**************************************************************************/
  1064. /*!
  1065. @brief Set text cursor location
  1066. @param x X coordinate in pixels
  1067. @param y Y coordinate in pixels
  1068. */
  1069. /**************************************************************************/
  1070. void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
  1071. cursor_x = x;
  1072. cursor_y = y;
  1073. }
  1074. /**************************************************************************/
  1075. /*!
  1076. @brief Get text cursor X location
  1077. @returns X coordinate in pixels
  1078. */
  1079. /**************************************************************************/
  1080. int16_t Adafruit_GFX::getCursorX(void) const {
  1081. return cursor_x;
  1082. }
  1083. /**************************************************************************/
  1084. /*!
  1085. @brief Get text cursor Y location
  1086. @returns Y coordinate in pixels
  1087. */
  1088. /**************************************************************************/
  1089. int16_t Adafruit_GFX::getCursorY(void) const {
  1090. return cursor_y;
  1091. }
  1092. /**************************************************************************/
  1093. /*!
  1094. @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
  1095. @param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
  1096. */
  1097. /**************************************************************************/
  1098. void Adafruit_GFX::setTextSize(uint8_t s) {
  1099. textsize = (s > 0) ? s : 1;
  1100. }
  1101. /**************************************************************************/
  1102. /*!
  1103. @brief Set text font color with transparant background
  1104. @param c 16-bit 5-6-5 Color to draw text with
  1105. */
  1106. /**************************************************************************/
  1107. void Adafruit_GFX::setTextColor(uint16_t c) {
  1108. // For 'transparent' background, we'll set the bg
  1109. // to the same as fg instead of using a flag
  1110. textcolor = textbgcolor = c;
  1111. }
  1112. /**************************************************************************/
  1113. /*!
  1114. @brief Set text font color with custom background color
  1115. @param c 16-bit 5-6-5 Color to draw text with
  1116. @param b 16-bit 5-6-5 Color to draw background/fill with
  1117. */
  1118. /**************************************************************************/
  1119. void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
  1120. textcolor = c;
  1121. textbgcolor = b;
  1122. }
  1123. /**************************************************************************/
  1124. /*!
  1125. @brief Whether text that is too long should 'wrap' around to the next line.
  1126. @param w Set true for wrapping, false for clipping
  1127. */
  1128. /**************************************************************************/
  1129. void Adafruit_GFX::setTextWrap(boolean w) {
  1130. wrap = w;
  1131. }
  1132. /**************************************************************************/
  1133. /*!
  1134. @brief Get rotation setting for display
  1135. @returns 0 thru 3 corresponding to 4 cardinal rotations
  1136. */
  1137. /**************************************************************************/
  1138. uint8_t Adafruit_GFX::getRotation(void) const {
  1139. return rotation;
  1140. }
  1141. /**************************************************************************/
  1142. /*!
  1143. @brief Set rotation setting for display
  1144. @param x 0 thru 3 corresponding to 4 cardinal rotations
  1145. */
  1146. /**************************************************************************/
  1147. void Adafruit_GFX::setRotation(uint8_t x) {
  1148. rotation = (x & 3);
  1149. switch(rotation) {
  1150. case 0:
  1151. case 2:
  1152. _width = WIDTH;
  1153. _height = HEIGHT;
  1154. break;
  1155. case 1:
  1156. case 3:
  1157. _width = HEIGHT;
  1158. _height = WIDTH;
  1159. break;
  1160. }
  1161. }
  1162. /**************************************************************************/
  1163. /*!
  1164. @brief Enable (or disable) Code Page 437-compatible charset.
  1165. There was an error in glcdfont.c for the longest time -- one character
  1166. (#176, the 'light shade' block) was missing -- this threw off the index
  1167. of every character that followed it. But a TON of code has been written
  1168. with the erroneous character indices. By default, the library uses the
  1169. original 'wrong' behavior and old sketches will still work. Pass 'true'
  1170. to this function to use correct CP437 character values in your code.
  1171. @param x Whether to enable (True) or not (False)
  1172. */
  1173. /**************************************************************************/
  1174. void Adafruit_GFX::cp437(boolean x) {
  1175. _cp437 = x;
  1176. }
  1177. /**************************************************************************/
  1178. /*!
  1179. @brief Set the font to display when print()ing, either custom or default
  1180. @param f The GFXfont object, if NULL use built in 6x8 font
  1181. */
  1182. /**************************************************************************/
  1183. void Adafruit_GFX::setFont(const GFXfont *f) {
  1184. if(f) { // Font struct pointer passed in?
  1185. if(!gfxFont) { // And no current font struct?
  1186. // Switching from classic to new font behavior.
  1187. // Move cursor pos down 6 pixels so it's on baseline.
  1188. cursor_y += 6;
  1189. }
  1190. } else if(gfxFont) { // NULL passed. Current font struct defined?
  1191. // Switching from new to classic font behavior.
  1192. // Move cursor pos up 6 pixels so it's at top-left of char.
  1193. cursor_y -= 6;
  1194. }
  1195. gfxFont = (GFXfont *)f;
  1196. }
  1197. /**************************************************************************/
  1198. /*!
  1199. @brief Helper to determine size of a character with current font/size.
  1200. Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
  1201. @param c The ascii character in question
  1202. @param x Pointer to x location of character
  1203. @param y Pointer to y location of character
  1204. @param minx Minimum clipping value for X
  1205. @param miny Minimum clipping value for Y
  1206. @param maxx Maximum clipping value for X
  1207. @param maxy Maximum clipping value for Y
  1208. */
  1209. /**************************************************************************/
  1210. void Adafruit_GFX::charBounds(char c, int16_t *x, int16_t *y,
  1211. int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) {
  1212. if(gfxFont) {
  1213. if(c == '\n') { // Newline?
  1214. *x = 0; // Reset x to zero, advance y by one line
  1215. *y += textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
  1216. } else if(c != '\r') { // Not a carriage return; is normal char
  1217. uint8_t first = pgm_read_byte(&gfxFont->first),
  1218. last = pgm_read_byte(&gfxFont->last);
  1219. if((c >= first) && (c <= last)) { // Char present in this font?
  1220. GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(
  1221. &gfxFont->glyph))[c - first]);
  1222. uint8_t gw = pgm_read_byte(&glyph->width),
  1223. gh = pgm_read_byte(&glyph->height),
  1224. xa = pgm_read_byte(&glyph->xAdvance);
  1225. int8_t xo = pgm_read_byte(&glyph->xOffset),
  1226. yo = pgm_read_byte(&glyph->yOffset);
  1227. if(wrap && ((*x+(((int16_t)xo+gw)*textsize)) > _width)) {
  1228. *x = 0; // Reset x to zero, advance y by one line
  1229. *y += textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
  1230. }
  1231. int16_t ts = (int16_t)textsize,
  1232. x1 = *x + xo * ts,
  1233. y1 = *y + yo * ts,
  1234. x2 = x1 + gw * ts - 1,
  1235. y2 = y1 + gh * ts - 1;
  1236. if(x1 < *minx) *minx = x1;
  1237. if(y1 < *miny) *miny = y1;
  1238. if(x2 > *maxx) *maxx = x2;
  1239. if(y2 > *maxy) *maxy = y2;
  1240. *x += xa * ts;
  1241. }
  1242. }
  1243. } else { // Default font
  1244. if(c == '\n') { // Newline?
  1245. *x = 0; // Reset x to zero,
  1246. *y += textsize * 8; // advance y one line
  1247. // min/max x/y unchaged -- that waits for next 'normal' character
  1248. } else if(c != '\r') { // Normal char; ignore carriage returns
  1249. if(wrap && ((*x + textsize * 6) > _width)) { // Off right?
  1250. *x = 0; // Reset x to zero,
  1251. *y += textsize * 8; // advance y one line
  1252. }
  1253. int x2 = *x + textsize * 6 - 1, // Lower-right pixel of char
  1254. y2 = *y + textsize * 8 - 1;
  1255. if(x2 > *maxx) *maxx = x2; // Track max x, y
  1256. if(y2 > *maxy) *maxy = y2;
  1257. if(*x < *minx) *minx = *x; // Track min x, y
  1258. if(*y < *miny) *miny = *y;
  1259. *x += textsize * 6; // Advance x one char
  1260. }
  1261. }
  1262. }
  1263. /**************************************************************************/
  1264. /*!
  1265. @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
  1266. @param str The ascii string to measure
  1267. @param x The current cursor X
  1268. @param y The current cursor Y
  1269. @param x1 The boundary X coordinate, set by function
  1270. @param y1 The boundary Y coordinate, set by function
  1271. @param w The boundary width, set by function
  1272. @param h The boundary height, set by function
  1273. */
  1274. /**************************************************************************/
  1275. void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
  1276. int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
  1277. uint8_t c; // Current character
  1278. *x1 = x;
  1279. *y1 = y;
  1280. *w = *h = 0;
  1281. int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
  1282. while((c = *str++))
  1283. charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
  1284. if(maxx >= minx) {
  1285. *x1 = minx;
  1286. *w = maxx - minx + 1;
  1287. }
  1288. if(maxy >= miny) {
  1289. *y1 = miny;
  1290. *h = maxy - miny + 1;
  1291. }
  1292. }
  1293. /**************************************************************************/
  1294. /*!
  1295. @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
  1296. @param str The ascii string to measure (as an arduino String() class)
  1297. @param x The current cursor X
  1298. @param y The current cursor Y
  1299. @param x1 The boundary X coordinate, set by function
  1300. @param y1 The boundary Y coordinate, set by function
  1301. @param w The boundary width, set by function
  1302. @param h The boundary height, set by function
  1303. */
  1304. /**************************************************************************/
  1305. void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
  1306. int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
  1307. if (str.length() != 0) {
  1308. getTextBounds(const_cast<char*>(str.c_str()), x, y, x1, y1, w, h);
  1309. }
  1310. }
  1311. /**************************************************************************/
  1312. /*!
  1313. @brief Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
  1314. @param str The flash-memory ascii string to measure
  1315. @param x The current cursor X
  1316. @param y The current cursor Y
  1317. @param x1 The boundary X coordinate, set by function
  1318. @param y1 The boundary Y coordinate, set by function
  1319. @param w The boundary width, set by function
  1320. @param h The boundary height, set by function
  1321. */
  1322. /**************************************************************************/
  1323. void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str,
  1324. int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
  1325. uint8_t *s = (uint8_t *)str, c;
  1326. *x1 = x;
  1327. *y1 = y;
  1328. *w = *h = 0;
  1329. int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
  1330. while((c = pgm_read_byte(s++)))
  1331. charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
  1332. if(maxx >= minx) {
  1333. *x1 = minx;
  1334. *w = maxx - minx + 1;
  1335. }
  1336. if(maxy >= miny) {
  1337. *y1 = miny;
  1338. *h = maxy - miny + 1;
  1339. }
  1340. }
  1341. /**************************************************************************/
  1342. /*!
  1343. @brief Get width of the display, accounting for the current rotation
  1344. @returns Width in pixels
  1345. */
  1346. /**************************************************************************/
  1347. int16_t Adafruit_GFX::width(void) const {
  1348. return _width;
  1349. }
  1350. /**************************************************************************/
  1351. /*!
  1352. @brief Get height of the display, accounting for the current rotation
  1353. @returns Height in pixels
  1354. */
  1355. /**************************************************************************/
  1356. int16_t Adafruit_GFX::height(void) const {
  1357. return _height;
  1358. }
  1359. /**************************************************************************/
  1360. /*!
  1361. @brief Invert the display (ideally using built-in hardware command)
  1362. @param i True if you want to invert, false to make 'normal'
  1363. */
  1364. /**************************************************************************/
  1365. void Adafruit_GFX::invertDisplay(boolean i) {
  1366. // Do nothing, must be subclassed if supported by hardware
  1367. }
  1368. /***************************************************************************/
  1369. /**************************************************************************/
  1370. /*!
  1371. @brief Create a simple drawn button UI element
  1372. */
  1373. /**************************************************************************/
  1374. Adafruit_GFX_Button::Adafruit_GFX_Button(void) {
  1375. _gfx = 0;
  1376. }
  1377. /**************************************************************************/
  1378. /*!
  1379. @brief Initialize button with our desired color/size/settings
  1380. @param gfx Pointer to our display so we can draw to it!
  1381. @param x The X coordinate of the center of the button
  1382. @param y The Y coordinate of the center of the button
  1383. @param w Width of the buttton
  1384. @param h Height of the buttton
  1385. @param outline Color of the outline (16-bit 5-6-5 standard)
  1386. @param fill Color of the button fill (16-bit 5-6-5 standard)
  1387. @param textcolor Color of the button label (16-bit 5-6-5 standard)
  1388. @param label Ascii string of the text inside the button
  1389. @param textsize The font magnification of the label text
  1390. */
  1391. /**************************************************************************/
  1392. // Classic initButton() function: pass center & size
  1393. void Adafruit_GFX_Button::initButton(
  1394. Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h,
  1395. uint16_t outline, uint16_t fill, uint16_t textcolor,
  1396. char *label, uint8_t textsize)
  1397. {
  1398. // Tweak arguments and pass to the newer initButtonUL() function...
  1399. initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill,
  1400. textcolor, label, textsize);
  1401. }
  1402. /**************************************************************************/
  1403. /*!
  1404. @brief Initialize button with our desired color/size/settings, with upper-left coordinates
  1405. @param gfx Pointer to our display so we can draw to it!
  1406. @param x1 The X coordinate of the Upper-Left corner of the button
  1407. @param y1 The Y coordinate of the Upper-Left corner of the button
  1408. @param w Width of the buttton
  1409. @param h Height of the buttton
  1410. @param outline Color of the outline (16-bit 5-6-5 standard)
  1411. @param fill Color of the button fill (16-bit 5-6-5 standard)
  1412. @param textcolor Color of the button label (16-bit 5-6-5 standard)
  1413. @param label Ascii string of the text inside the button
  1414. @param textsize The font magnification of the label text
  1415. */
  1416. /**************************************************************************/
  1417. void Adafruit_GFX_Button::initButtonUL(
  1418. Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
  1419. uint16_t outline, uint16_t fill, uint16_t textcolor,
  1420. char *label, uint8_t textsize)
  1421. {
  1422. _x1 = x1;
  1423. _y1 = y1;
  1424. _w = w;
  1425. _h = h;
  1426. _outlinecolor = outline;
  1427. _fillcolor = fill;
  1428. _textcolor = textcolor;
  1429. _textsize = textsize;
  1430. _gfx = gfx;
  1431. strncpy(_label, label, 9);
  1432. }
  1433. /**************************************************************************/
  1434. /*!
  1435. @brief Draw the button on the screen
  1436. @param inverted Whether to draw with fill/text swapped to indicate 'pressed'
  1437. */
  1438. /**************************************************************************/
  1439. void Adafruit_GFX_Button::drawButton(boolean inverted) {
  1440. uint16_t fill, outline, text;
  1441. if(!inverted) {
  1442. fill = _fillcolor;
  1443. outline = _outlinecolor;
  1444. text = _textcolor;
  1445. } else {
  1446. fill = _textcolor;
  1447. outline = _outlinecolor;
  1448. text = _fillcolor;
  1449. }
  1450. uint8_t r = min(_w, _h) / 4; // Corner radius
  1451. _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
  1452. _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);
  1453. _gfx->setCursor(_x1 + (_w/2) - (strlen(_label) * 3 * _textsize),
  1454. _y1 + (_h/2) - (4 * _textsize));
  1455. _gfx->setTextColor(text);
  1456. _gfx->setTextSize(_textsize);
  1457. _gfx->print(_label);
  1458. }
  1459. /**************************************************************************/
  1460. /*!
  1461. @brief Helper to let us know if a coordinate is within the bounds of the button
  1462. @param x The X coordinate to check
  1463. @param y The Y coordinate to check
  1464. @returns True if within button graphics outline
  1465. */
  1466. /**************************************************************************/
  1467. boolean Adafruit_GFX_Button::contains(int16_t x, int16_t y) {
  1468. return ((x >= _x1) && (x < (int16_t) (_x1 + _w)) &&
  1469. (y >= _y1) && (y < (int16_t) (_y1 + _h)));
  1470. }
  1471. /**************************************************************************/
  1472. /*!
  1473. @brief Sets the state of the button, should be done by some touch function
  1474. @param p True for pressed, false for not.
  1475. */
  1476. /**************************************************************************/
  1477. void Adafruit_GFX_Button::press(boolean p) {
  1478. laststate = currstate;
  1479. currstate = p;
  1480. }
  1481. /**************************************************************************/
  1482. /*!
  1483. @brief Query whether the button is currently pressed
  1484. @returns True if pressed
  1485. */
  1486. /**************************************************************************/
  1487. boolean Adafruit_GFX_Button::isPressed() { return currstate; }
  1488. /**************************************************************************/
  1489. /*!
  1490. @brief Query whether the button was pressed since we last checked state
  1491. @returns True if was not-pressed before, now is.
  1492. */
  1493. /**************************************************************************/
  1494. boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }
  1495. /**************************************************************************/
  1496. /*!
  1497. @brief Query whether the button was released since we last checked state
  1498. @returns True if was pressed before, now is not.
  1499. */
  1500. /**************************************************************************/
  1501. boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
  1502. // -------------------------------------------------------------------------
  1503. // GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too
  1504. // comfy with the implementation) provide 1-, 8- and 16-bit offscreen
  1505. // canvases, the address of which can be passed to drawBitmap() or
  1506. // pushColors() (the latter appears only in a couple of GFX-subclassed TFT
  1507. // libraries at this time). This is here mostly to help with the recently-
  1508. // added proportionally-spaced fonts; adds a way to refresh a section of the
  1509. // screen without a massive flickering clear-and-redraw...but maybe you'll
  1510. // find other uses too. VERY RAM-intensive, since the buffer is in MCU
  1511. // memory and not the display driver...GXFcanvas1 might be minimally useful
  1512. // on an Uno-class board, but this and the others are much more likely to
  1513. // require at least a Mega or various recent ARM-type boards (recommended,
  1514. // as the text+bitmap draw can be pokey). GFXcanvas1 requires 1 bit per
  1515. // pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte
  1516. // per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no
  1517. // scanline pad).
  1518. // NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
  1519. /**************************************************************************/
  1520. /*!
  1521. @brief Instatiate a GFX 1-bit canvas context for graphics
  1522. @param w Display width, in pixels
  1523. @param h Display height, in pixels
  1524. */
  1525. /**************************************************************************/
  1526. GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
  1527. uint16_t bytes = ((w + 7) / 8) * h;
  1528. if((buffer = (uint8_t *)malloc(bytes))) {
  1529. memset(buffer, 0, bytes);
  1530. }
  1531. }
  1532. /**************************************************************************/
  1533. /*!
  1534. @brief Delete the canvas, free memory
  1535. */
  1536. /**************************************************************************/
  1537. GFXcanvas1::~GFXcanvas1(void) {
  1538. if(buffer) free(buffer);
  1539. }
  1540. /**************************************************************************/
  1541. /*!
  1542. @brief Get a pointer to the internal buffer memory
  1543. @returns A pointer to the allocated buffer
  1544. */
  1545. /**************************************************************************/
  1546. uint8_t* GFXcanvas1::getBuffer(void) {
  1547. return buffer;
  1548. }
  1549. /**************************************************************************/
  1550. /*!
  1551. @brief Draw a pixel to the canvas framebuffer
  1552. @param x x coordinate
  1553. @param y y coordinate
  1554. @param color 16-bit 5-6-5 Color to fill with
  1555. */
  1556. /**************************************************************************/
  1557. void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
  1558. #ifdef __AVR__
  1559. // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
  1560. static const uint8_t PROGMEM
  1561. GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
  1562. GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE };
  1563. #endif
  1564. if(buffer) {
  1565. if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
  1566. int16_t t;
  1567. switch(rotation) {
  1568. case 1:
  1569. t = x;
  1570. x = WIDTH - 1 - y;
  1571. y = t;
  1572. break;
  1573. case 2:
  1574. x = WIDTH - 1 - x;
  1575. y = HEIGHT - 1 - y;
  1576. break;
  1577. case 3:
  1578. t = x;
  1579. x = y;
  1580. y = HEIGHT - 1 - t;
  1581. break;
  1582. }
  1583. uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
  1584. #ifdef __AVR__
  1585. if(color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
  1586. else *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
  1587. #else
  1588. if(color) *ptr |= 0x80 >> (x & 7);
  1589. else *ptr &= ~(0x80 >> (x & 7));
  1590. #endif
  1591. }
  1592. }
  1593. /**************************************************************************/
  1594. /*!
  1595. @brief Fill the framebuffer completely with one color
  1596. @param color 16-bit 5-6-5 Color to fill with
  1597. */
  1598. /**************************************************************************/
  1599. void GFXcanvas1::fillScreen(uint16_t color) {
  1600. if(buffer) {
  1601. uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
  1602. memset(buffer, color ? 0xFF : 0x00, bytes);
  1603. }
  1604. }
  1605. /**************************************************************************/
  1606. /*!
  1607. @brief Instatiate a GFX 8-bit canvas context for graphics
  1608. @param w Display width, in pixels
  1609. @param h Display height, in pixels
  1610. */
  1611. /**************************************************************************/
  1612. GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
  1613. uint32_t bytes = w * h;
  1614. if((buffer = (uint8_t *)malloc(bytes))) {
  1615. memset(buffer, 0, bytes);
  1616. }
  1617. }
  1618. /**************************************************************************/
  1619. /*!
  1620. @brief Delete the canvas, free memory
  1621. */
  1622. /**************************************************************************/
  1623. GFXcanvas8::~GFXcanvas8(void) {
  1624. if(buffer) free(buffer);
  1625. }
  1626. /**************************************************************************/
  1627. /*!
  1628. @brief Get a pointer to the internal buffer memory
  1629. @returns A pointer to the allocated buffer
  1630. */
  1631. /**************************************************************************/
  1632. uint8_t* GFXcanvas8::getBuffer(void) {
  1633. return buffer;
  1634. }
  1635. /**************************************************************************/
  1636. /*!
  1637. @brief Draw a pixel to the canvas framebuffer
  1638. @param x x coordinate
  1639. @param y y coordinate
  1640. @param color 16-bit 5-6-5 Color to fill with
  1641. */
  1642. /**************************************************************************/
  1643. void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
  1644. if(buffer) {
  1645. if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
  1646. int16_t t;
  1647. switch(rotation) {
  1648. case 1:
  1649. t = x;
  1650. x = WIDTH - 1 - y;
  1651. y = t;
  1652. break;
  1653. case 2:
  1654. x = WIDTH - 1 - x;
  1655. y = HEIGHT - 1 - y;
  1656. break;
  1657. case 3:
  1658. t = x;
  1659. x = y;
  1660. y = HEIGHT - 1 - t;
  1661. break;
  1662. }
  1663. buffer[x + y * WIDTH] = color;
  1664. }
  1665. }
  1666. /**************************************************************************/
  1667. /*!
  1668. @brief Fill the framebuffer completely with one color
  1669. @param color 16-bit 5-6-5 Color to fill with
  1670. */
  1671. /**************************************************************************/
  1672. void GFXcanvas8::fillScreen(uint16_t color) {
  1673. if(buffer) {
  1674. memset(buffer, color, WIDTH * HEIGHT);
  1675. }
  1676. }
  1677. void GFXcanvas8::writeFastHLine(int16_t x, int16_t y,
  1678. int16_t w, uint16_t color) {
  1679. if((x >= _width) || (y < 0) || (y >= _height)) return;
  1680. int16_t x2 = x + w - 1;
  1681. if(x2 < 0) return;
  1682. // Clip left/right
  1683. if(x < 0) {
  1684. x = 0;
  1685. w = x2 + 1;
  1686. }
  1687. if(x2 >= _width) w = _width - x;
  1688. int16_t t;
  1689. switch(rotation) {
  1690. case 1:
  1691. t = x;
  1692. x = WIDTH - 1 - y;
  1693. y = t;
  1694. break;
  1695. case 2:
  1696. x = WIDTH - 1 - x;
  1697. y = HEIGHT - 1 - y;
  1698. break;
  1699. case 3:
  1700. t = x;
  1701. x = y;
  1702. y = HEIGHT - 1 - t;
  1703. break;
  1704. }
  1705. memset(buffer + y * WIDTH + x, color, w);
  1706. }
  1707. /**************************************************************************/
  1708. /*!
  1709. @brief Instatiate a GFX 16-bit canvas context for graphics
  1710. @param w Display width, in pixels
  1711. @param h Display height, in pixels
  1712. */
  1713. /**************************************************************************/
  1714. GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
  1715. uint32_t bytes = w * h * 2;
  1716. if((buffer = (uint16_t *)malloc(bytes))) {
  1717. memset(buffer, 0, bytes);
  1718. }
  1719. }
  1720. /**************************************************************************/
  1721. /*!
  1722. @brief Delete the canvas, free memory
  1723. */
  1724. /**************************************************************************/
  1725. GFXcanvas16::~GFXcanvas16(void) {
  1726. if(buffer) free(buffer);
  1727. }
  1728. /**************************************************************************/
  1729. /*!
  1730. @brief Get a pointer to the internal buffer memory
  1731. @returns A pointer to the allocated buffer
  1732. */
  1733. /**************************************************************************/
  1734. uint16_t* GFXcanvas16::getBuffer(void) {
  1735. return buffer;
  1736. }
  1737. /**************************************************************************/
  1738. /*!
  1739. @brief Draw a pixel to the canvas framebuffer
  1740. @param x x coordinate
  1741. @param y y coordinate
  1742. @param color 16-bit 5-6-5 Color to fill with
  1743. */
  1744. /**************************************************************************/
  1745. void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
  1746. if(buffer) {
  1747. if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
  1748. int16_t t;
  1749. switch(rotation) {
  1750. case 1:
  1751. t = x;
  1752. x = WIDTH - 1 - y;
  1753. y = t;
  1754. break;
  1755. case 2:
  1756. x = WIDTH - 1 - x;
  1757. y = HEIGHT - 1 - y;
  1758. break;
  1759. case 3:
  1760. t = x;
  1761. x = y;
  1762. y = HEIGHT - 1 - t;
  1763. break;
  1764. }
  1765. buffer[x + y * WIDTH] = color;
  1766. }
  1767. }
  1768. /**************************************************************************/
  1769. /*!
  1770. @brief Fill the framebuffer completely with one color
  1771. @param color 16-bit 5-6-5 Color to fill with
  1772. */
  1773. /**************************************************************************/
  1774. void GFXcanvas16::fillScreen(uint16_t color) {
  1775. if(buffer) {
  1776. uint8_t hi = color >> 8, lo = color & 0xFF;
  1777. if(hi == lo) {
  1778. memset(buffer, lo, WIDTH * HEIGHT * 2);
  1779. } else {
  1780. uint32_t i, pixels = WIDTH * HEIGHT;
  1781. for(i=0; i<pixels; i++) buffer[i] = color;
  1782. }
  1783. }
  1784. }