Adafruit_GFX.cpp 96 KB

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