source: asp3_tinet_ecnl_rx/trunk/ntshell/lcd/adafruit_gfx.c@ 364

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

TINETとSocket APIなどを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
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 else {
1120 lcd_drawFont_(lcd, x, y, bitmap_data, FONT_WIDTH, FONT_HEIGHT, color, bg);
1121 }
1122 if (bg != color) { // If opaque, draw vertical line for last column
1123 if (size == 1) lcd_writeFastVLine(lcd, x + FONT_WIDTH, y, FONT_HEIGHT, bg);
1124 else lcd_writeFillRect(lcd, x + FONT_WIDTH * size, y, size, FONT_HEIGHT*size, bg);
1125 }
1126 lcd_endWrite(lcd);
1127
1128 }
1129 else { // Custom font
1130 unsigned char c = *utf8;
1131
1132 // Character is assumed previously filtered by write() to eliminate
1133 // newlines, returns, non-printable characters, etc. Calling
1134 // drawChar() directly with 'bad' characters of font may cause mayhem!
1135
1136 c -= (uint8_t)pgm_read_byte(&lcd->gfxFont->first);
1137 GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&lcd->gfxFont->glyph))[c]);
1138 uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&lcd->gfxFont->bitmap);
1139
1140 uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
1141 uint8_t w = pgm_read_byte(&glyph->width),
1142 h = pgm_read_byte(&glyph->height);
1143 int8_t xo = pgm_read_byte(&glyph->xOffset),
1144 yo = pgm_read_byte(&glyph->yOffset);
1145 uint8_t xx, yy, bits = 0, bit = 0;
1146 int16_t xo16 = 0, yo16 = 0;
1147
1148 if (size > 1) {
1149 xo16 = xo;
1150 yo16 = yo;
1151 }
1152
1153 // Todo: Add character clipping here
1154
1155 // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
1156 // THIS IS ON PURPOSE AND BY DESIGN. The background color feature
1157 // has typically been used with the 'classic' font to overwrite old
1158 // screen contents with new data. This ONLY works because the
1159 // characters are a uniform size; it's not a sensible thing to do with
1160 // proportionally-spaced fonts with glyphs of varying sizes (and that
1161 // may overlap). To replace previously-drawn text when using a custom
1162 // font, use the getTextBounds() function to determine the smallest
1163 // rectangle encompassing a string, erase the area with fillRect(),
1164 // then draw new text. This WILL infortunately 'blink' the text, but
1165 // is unavoidable. Drawing 'background' pixels will NOT fix this,
1166 // only creates a new set of problems. Have an idea to work around
1167 // this (a canvas object type for MCUs that can afford the RAM and
1168 // displays supporting setAddrWindow() and pushColors()), but haven't
1169 // implemented this yet.
1170
1171 lcd_startWrite(lcd);
1172 for (yy = 0; yy < h; yy++) {
1173 for (xx = 0; xx < w; xx++) {
1174 if (!(bit++ & 7)) {
1175 bits = pgm_read_byte(&bitmap[bo++]);
1176 }
1177 if (bits & 0x80) {
1178 if (size == 1) {
1179 lcd_writePixel(lcd, x + xo + xx, y + yo + yy, color);
1180 }
1181 else {
1182 lcd_writeFillRect(lcd, x + (xo16 + xx)*size, y + (yo16 + yy)*size,
1183 size, size, color);
1184 }
1185 }
1186 bits <<= 1;
1187 }
1188 }
1189 lcd_endWrite(lcd);
1190
1191 } // End classic vs custom font
1192}
1193/**************************************************************************/
1194/*!
1195 @brief Print one byte/character of data, used to support print()
1196 @param c The 8-bit ascii character to write
1197*/
1198/**************************************************************************/
1199size_t lcd_write(LCD_Handler_t *lcd, uint8_t c)
1200{
1201 if (!lcd->gfxFont) { // 'Classic' built-in font
1202
1203 if (c == '\n') { // Newline?
1204 lcd->cursor_x = 0; // Reset x to zero,
1205 lcd->cursor_y += lcd->textsize * 8; // advance y one line
1206 }
1207 else if (c != '\r') { // Ignore carriage returns
1208 if (lcd->wrap && ((lcd->cursor_x + lcd->textsize * 6) > lcd->_width)) { // Off right?
1209 lcd->cursor_x = 0; // Reset x to zero,
1210 lcd->cursor_y += lcd->textsize * 8; // advance y one line
1211 }
1212 lcd_drawChar(lcd, lcd->cursor_x, lcd->cursor_y, (char *)&c, lcd->textcolor, lcd->textbgcolor, lcd->textsize);
1213 lcd->cursor_x += lcd->textsize * 6; // Advance x one char
1214 }
1215
1216 }
1217 else { // Custom font
1218
1219 if (c == '\n') {
1220 lcd->cursor_x = 0;
1221 lcd->cursor_y += (int16_t)lcd->textsize *
1222 (uint8_t)pgm_read_byte(&lcd->gfxFont->yAdvance);
1223 }
1224 else if (c != '\r') {
1225 uint8_t first = pgm_read_byte(&lcd->gfxFont->first);
1226 if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&lcd->gfxFont->last))) {
1227 GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(
1228 &lcd->gfxFont->glyph))[c - first]);
1229 uint8_t w = pgm_read_byte(&glyph->width),
1230 h = pgm_read_byte(&glyph->height);
1231 if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
1232 int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
1233 if (lcd->wrap && ((lcd->cursor_x + lcd->textsize * (xo + w)) > lcd->_width)) {
1234 lcd->cursor_x = 0;
1235 lcd->cursor_y += (int16_t)lcd->textsize *
1236 (uint8_t)pgm_read_byte(&lcd->gfxFont->yAdvance);
1237 }
1238 lcd_drawChar(lcd, lcd->cursor_x, lcd->cursor_y, (char *)&c, lcd->textcolor, lcd->textbgcolor, lcd->textsize);
1239 }
1240 lcd->cursor_x += (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)lcd->textsize;
1241 }
1242 }
1243
1244 }
1245 return 1;
1246}
1247
1248void lcd_drawString_(LCD_Handler_t *lcd, int16_t x, int16_t y,
1249 const char *string, uint16_t color, uint16_t bg)
1250{
1251 uint32_t current_top, use_chars, for_3B_hankaku_code;
1252 uint8_t bitmap_data[FONT_WIDTH * FONT_HEIGHT / 8], ctrl_code;
1253 int local_x, local_y, len = strlen(string);
1254 const uint8_t *code = (const uint8_t *)string;
1255
1256 local_x = x;
1257 local_y = y;
1258
1259 current_top = 0;
1260 while (current_top < len) {
1261 memset(bitmap_data, 0x0, FONT_WIDTH * FONT_HEIGHT / 8);
1262 ctrl_code = code[current_top];
1263 get_bitmap_font(&code[current_top], bitmap_data, &use_chars);
1264 if (use_chars == 0)
1265 return;
1266
1267 //3バイトコード半角文字用
1268 if (use_chars == 3) {
1269 for_3B_hankaku_code = 0;
1270 for_3B_hankaku_code = ((code[current_top] << 16) |
1271 (code[current_top + 1] << 8) |
1272 (code[current_top + 2]));
1273 }
1274
1275 current_top += use_chars;
1276
1277 //1バイトコード半角文字
1278 if (use_chars == 1) {
1279 if (ctrl_code == 0x0D) { // CR
1280 local_x = X_LINE_TO_PIX(this, 0);
1281 continue;
1282 }
1283 if (ctrl_code == 0x0A) { // LF
1284 local_y = local_y + FONT_HEIGHT;
1285 continue;
1286 }
1287
1288 if (local_x + FONT_HALF_WIDTH > lcd->_width) {
1289 local_x = X_LINE_HALF_TO_PIX(this, 0);
1290 local_y = local_y + FONT_HEIGHT;
1291 }
1292 lcd_drawFont_(lcd, local_x, local_y, bitmap_data, FONT_HALF_WIDTH, FONT_HEIGHT, color, bg);
1293 local_x += FONT_HALF_WIDTH;
1294 continue;
1295 }
1296
1297 //3バイトコード半角文字
1298 if (use_chars == 3) {
1299 if (((0xEFBDA1 <= for_3B_hankaku_code) && (for_3B_hankaku_code <= 0xEFBDBF)) ||
1300 ((0xEFBE80 <= for_3B_hankaku_code) && (for_3B_hankaku_code <= 0xEFBE9F))) {
1301 //3バイトコード半角文字
1302 if (local_x + FONT_HALF_WIDTH > lcd->_width) {
1303 local_x = X_LINE_HALF_TO_PIX(this, 0);
1304 local_y = local_y + FONT_HEIGHT;
1305 }
1306 lcd_drawFont_(lcd, local_x, local_y, bitmap_data, FONT_HALF_WIDTH, FONT_HEIGHT, color, bg);
1307 local_x += FONT_HALF_WIDTH;
1308 continue;
1309 }
1310 }
1311
1312 //全角文字
1313 if (local_x + FONT_WIDTH > lcd->_width) {
1314 local_x = X_LINE_TO_PIX(this, 0);
1315 local_y = local_y + FONT_HEIGHT;
1316 }
1317 lcd_drawFont_(lcd, local_x, local_y, bitmap_data, FONT_WIDTH, FONT_HEIGHT, color, bg);
1318 local_x += FONT_WIDTH;
1319 }
1320}
1321
1322/**************************************************************************/
1323/*!
1324 @brief Set text cursor location
1325 @param x X coordinate in pixels
1326 @param y Y coordinate in pixels
1327*/
1328/**************************************************************************/
1329void lcd_setCursor(LCD_Handler_t *lcd, int16_t x, int16_t y)
1330{
1331 lcd->cursor_x = x;
1332 lcd->cursor_y = y;
1333}
1334
1335/**************************************************************************/
1336/*!
1337 @brief Get text cursor X location
1338 @returns X coordinate in pixels
1339*/
1340/**************************************************************************/
1341int16_t lcd_getCursorX(LCD_Handler_t *lcd)
1342{
1343 return lcd->cursor_x;
1344}
1345
1346/**************************************************************************/
1347/*!
1348 @brief Get text cursor Y location
1349 @returns Y coordinate in pixels
1350*/
1351/**************************************************************************/
1352int16_t lcd_getCursorY(LCD_Handler_t *lcd)
1353{
1354 return lcd->cursor_y;
1355}
1356
1357/**************************************************************************/
1358/*!
1359 @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
1360 @param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
1361*/
1362/**************************************************************************/
1363void lcd_setTextSize(LCD_Handler_t *lcd, uint8_t s)
1364{
1365 lcd->textsize = (s > 0) ? s : 1;
1366}
1367
1368/**************************************************************************/
1369/*!
1370 @brief Set text font color with transparant background
1371 @param c 16-bit 5-6-5 Color to draw text with
1372*/
1373/**************************************************************************/
1374void lcd_setTextColor(LCD_Handler_t *lcd, uint16_t c)
1375{
1376// For 'transparent' background, we'll set the bg
1377// to the same as fg instead of using a flag
1378 lcd->textcolor = lcd->textbgcolor = c;
1379}
1380
1381/**************************************************************************/
1382/*!
1383 @brief Set text font color with custom background color
1384 @param c 16-bit 5-6-5 Color to draw text with
1385 @param b 16-bit 5-6-5 Color to draw background/fill with
1386*/
1387/**************************************************************************/
1388void lcd_setTextColor2(LCD_Handler_t *lcd, uint16_t c, uint16_t b)
1389{
1390 lcd->textcolor = c;
1391 lcd->textbgcolor = b;
1392}
1393
1394/**************************************************************************/
1395/*!
1396 @brief Whether text that is too long should 'wrap' around to the next line.
1397 @param w Set true for wrapping, false for clipping
1398*/
1399/**************************************************************************/
1400void lcd_setTextWrap(LCD_Handler_t *lcd, bool w)
1401{
1402 lcd->wrap = w;
1403}
1404
1405/**************************************************************************/
1406/*!
1407 @brief Get rotation setting for display
1408 @returns 0 thru 3 corresponding to 4 cardinal rotations
1409*/
1410/**************************************************************************/
1411uint8_t lcd_getRotation(LCD_Handler_t *lcd)
1412{
1413 return lcd->rotation;
1414}
1415
1416/**************************************************************************/
1417/*!
1418 @brief Set rotation setting for display
1419 @param x 0 thru 3 corresponding to 4 cardinal rotations
1420*/
1421/**************************************************************************/
1422void lcd_setRotation(LCD_Handler_t *lcd, uint8_t x)
1423{
1424 lcd->rotation = (x & 3);
1425 switch (lcd->rotation) {
1426 case 0:
1427 case 2:
1428 lcd->_width = lcd_init_width;
1429 lcd->_height = lcd_init_height;
1430 break;
1431 case 1:
1432 case 3:
1433 lcd->_width = lcd_init_height;
1434 lcd->_height = lcd_init_width;
1435 break;
1436 }
1437}
1438
1439/**************************************************************************/
1440/*!
1441 @brief Set the font to display when print()ing, either custom or default
1442 @param f The GFXfont object, if NULL use built in 6x8 font
1443*/
1444/**************************************************************************/
1445void lcd_setFont(LCD_Handler_t *lcd, const GFXfont *f)
1446{
1447 if (f) { // Font struct pointer passed in?
1448 if (!lcd->gfxFont) { // And no current font struct?
1449 // Switching from classic to new font behavior.
1450 // Move cursor pos down 6 pixels so it's on baseline.
1451 lcd->cursor_y += 6;
1452 }
1453 }
1454 else if (lcd->gfxFont) { // NULL passed. Current font struct defined?
1455 // Switching from new to classic font behavior.
1456 // Move cursor pos up 6 pixels so it's at top-left of char.
1457 lcd->cursor_y -= 6;
1458 }
1459 lcd->gfxFont = (GFXfont *)f;
1460}
1461
1462
1463/**************************************************************************/
1464/*!
1465 @brief Helper to determine size of a character with current font/size.
1466 Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
1467 @param c The ascii character in question
1468 @param x Pointer to x location of character
1469 @param y Pointer to y location of character
1470 @param minx Minimum clipping value for X
1471 @param miny Minimum clipping value for Y
1472 @param maxx Maximum clipping value for X
1473 @param maxy Maximum clipping value for Y
1474*/
1475/**************************************************************************/
1476void lcd_charBounds(LCD_Handler_t *lcd, char c, int16_t *x, int16_t *y,
1477 int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy)
1478{
1479
1480 if (lcd->gfxFont) {
1481
1482 if (c == '\n') { // Newline?
1483 *x = 0; // Reset x to zero, advance y by one line
1484 *y += lcd->textsize * (uint8_t)pgm_read_byte(&lcd->gfxFont->yAdvance);
1485 }
1486 else if (c != '\r') { // Not a carriage return; is normal char
1487 uint8_t first = pgm_read_byte(&lcd->gfxFont->first),
1488 last = pgm_read_byte(&lcd->gfxFont->last);
1489 if ((c >= first) && (c <= last)) { // Char present in this font?
1490 GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(
1491 &lcd->gfxFont->glyph))[c - first]);
1492 uint8_t gw = pgm_read_byte(&glyph->width),
1493 gh = pgm_read_byte(&glyph->height),
1494 xa = pgm_read_byte(&glyph->xAdvance);
1495 int8_t xo = pgm_read_byte(&glyph->xOffset),
1496 yo = pgm_read_byte(&glyph->yOffset);
1497 if (lcd->wrap && ((*x + (((int16_t)xo + gw)*lcd->textsize)) > lcd->_width)) {
1498 *x = 0; // Reset x to zero, advance y by one line
1499 *y += lcd->textsize * (uint8_t)pgm_read_byte(&lcd->gfxFont->yAdvance);
1500 }
1501 int16_t ts = (int16_t)lcd->textsize,
1502 x1 = *x + xo * ts,
1503 y1 = *y + yo * ts,
1504 x2 = x1 + gw * ts - 1,
1505 y2 = y1 + gh * ts - 1;
1506 if (x1 < *minx) *minx = x1;
1507 if (y1 < *miny) *miny = y1;
1508 if (x2 > *maxx) *maxx = x2;
1509 if (y2 > *maxy) *maxy = y2;
1510 *x += xa * ts;
1511 }
1512 }
1513
1514 }
1515 else { // Default font
1516
1517 if (c == '\n') { // Newline?
1518 *x = 0; // Reset x to zero,
1519 *y += lcd->textsize * 8; // advance y one line
1520 // min/max x/y unchaged -- that waits for next 'normal' character
1521 }
1522 else if (c != '\r') { // Normal char; ignore carriage returns
1523 if (lcd->wrap && ((*x + lcd->textsize * 6) > lcd->_width)) { // Off right?
1524 *x = 0; // Reset x to zero,
1525 *y += lcd->textsize * 8; // advance y one line
1526 }
1527 int x2 = *x + lcd->textsize * 6 - 1, // Lower-right pixel of char
1528 y2 = *y + lcd->textsize * 8 - 1;
1529 if (x2 > *maxx) *maxx = x2; // Track max x, y
1530 if (y2 > *maxy) *maxy = y2;
1531 if (*x < *minx) *minx = *x; // Track min x, y
1532 if (*y < *miny) *miny = *y;
1533 *x += lcd->textsize * 6; // Advance x one char
1534 }
1535 }
1536}
1537
1538/**************************************************************************/
1539/*!
1540 @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
1541 @param str The ascii string to measure
1542 @param x The current cursor X
1543 @param y The current cursor Y
1544 @param x1 The boundary X coordinate, set by function
1545 @param y1 The boundary Y coordinate, set by function
1546 @param w The boundary width, set by function
1547 @param h The boundary height, set by function
1548*/
1549/**************************************************************************/
1550void lcd_getTextBounds(LCD_Handler_t *lcd, const char *str, int16_t x, int16_t y,
1551 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
1552{
1553 uint8_t c; // Current character
1554
1555 *x1 = x;
1556 *y1 = y;
1557 *w = *h = 0;
1558
1559 int16_t minx = lcd->_width, miny = lcd->_height, maxx = -1, maxy = -1;
1560
1561 while ((c = *str++))
1562 lcd_charBounds(lcd, c, &x, &y, &minx, &miny, &maxx, &maxy);
1563
1564 if (maxx >= minx) {
1565 *x1 = minx;
1566 *w = maxx - minx + 1;
1567 }
1568 if (maxy >= miny) {
1569 *y1 = miny;
1570 *h = maxy - miny + 1;
1571 }
1572}
1573
1574/**************************************************************************/
1575/*!
1576 @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
1577 @param str The ascii string to measure (as an arduino String() class)
1578 @param x The current cursor X
1579 @param y The current cursor Y
1580 @param x1 The boundary X coordinate, set by function
1581 @param y1 The boundary Y coordinate, set by function
1582 @param w The boundary width, set by function
1583 @param h The boundary height, set by function
1584*/
1585/**************************************************************************/
1586void lcd_getTextBounds2(LCD_Handler_t *lcd, const char *str, int16_t x, int16_t y,
1587 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
1588{
1589 if (strlen(str) != 0) {
1590 lcd_getTextBounds(lcd, str, x, y, x1, y1, w, h);
1591 }
1592}
1593
1594
1595/**************************************************************************/
1596/*!
1597 @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.
1598 @param str The flash-memory ascii string to measure
1599 @param x The current cursor X
1600 @param y The current cursor Y
1601 @param x1 The boundary X coordinate, set by function
1602 @param y1 The boundary Y coordinate, set by function
1603 @param w The boundary width, set by function
1604 @param h The boundary height, set by function
1605*/
1606/**************************************************************************/
1607void lcd_getTextBounds3(LCD_Handler_t *lcd, const char *str,
1608 int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
1609{
1610 uint8_t *s = (uint8_t *)str, c;
1611
1612 *x1 = x;
1613 *y1 = y;
1614 *w = *h = 0;
1615
1616 int16_t minx = lcd->_width, miny = lcd->_height, maxx = -1, maxy = -1;
1617
1618 while ((c = pgm_read_byte(s++)))
1619 lcd_charBounds(lcd, c, &x, &y, &minx, &miny, &maxx, &maxy);
1620
1621 if (maxx >= minx) {
1622 *x1 = minx;
1623 *w = maxx - minx + 1;
1624 }
1625 if (maxy >= miny) {
1626 *y1 = miny;
1627 *h = maxy - miny + 1;
1628 }
1629}
1630
1631/**************************************************************************/
1632/*!
1633 @brief Get width of the display, accounting for the current rotation
1634 @returns Width in pixels
1635*/
1636/**************************************************************************/
1637int16_t lcd_width(LCD_Handler_t *lcd)
1638{
1639 return lcd->_width;
1640}
1641
1642/**************************************************************************/
1643/*!
1644 @brief Get height of the display, accounting for the current rotation
1645 @returns Height in pixels
1646*/
1647/**************************************************************************/
1648int16_t lcd_height(LCD_Handler_t *lcd)
1649{
1650 return lcd->_height;
1651}
1652
1653/***************************************************************************/
Note: See TracBrowser for help on using the repository browser.