source: azure_iot_hub/trunk/ntshell/lcd/adafruit_gfx.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

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