Adafruit_GFX.cpp 91 KB

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