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