SSD1306 OLED display driver  1.5.0
This library is developed to control SSD1306/SSD1331 RGB i2c/spi OLED displays and spi PCD8544 LED display
canvas.cpp
1 /*
2  MIT License
3 
4  Copyright (c) 2018, Alexey Dynda
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  copies of the Software, and to permit persons to whom the Software is
11  furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in all
14  copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  SOFTWARE.
23 */
24 
25 #include "canvas.h"
26 #include "lcd/lcd_common.h"
27 #include "ssd1306.h"
28 #include "ssd1331_api.h"
29 
30 #define swap_data(a, b ,type) { type t = a; a = b; b = t; }
31 
32 extern const uint8_t *s_font6x8;
34 
36 //
37 // 8-BIT GRAPHICS
38 //
40 
41 /* We need to use multiply operation, because there are displays on the market *
42  * with resolution different from 2^N (160x128, 96x64, etc.) */
43 #define YADDR8(y) (static_cast<uint16_t>(y) * m_w)
44 
46 {
47  x -= offset.x;
48  y -= offset.y;
49  if ((x >= 0) && (y >= 0) && (x < (lcdint_t)m_w) && (y < (lcdint_t)m_h))
50  {
51  m_buf[YADDR8(y) + x] = m_color;
52  }
53 }
54 
56 {
57  putPixel(p.x, p.y);
58 }
59 
61 {
62  x1 -= offset.x;
63  y1 -= offset.y;
64  y2 -= offset.y;
65  if (y1 > y2)
66  {
67  swap_data(y1, y2, lcdint_t);
68  }
69  if ((x1 < 0) || (x1 >= (lcdint_t)m_w)) return;
70  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
71  y1 = max(y1,0);
72  uint8_t *buf = m_buf + YADDR8(y1) + x1;
73  y2 = min(y2,(lcdint_t)m_h-1) - y1;
74  do
75  {
76  *buf = m_color;
77  buf += m_w;
78  }
79  while (y2--);
80 }
81 
83 {
84  x1 -= offset.x;
85  y1 -= offset.y;
86  x2 -= offset.x;
87  if (x1 > x2)
88  {
89  swap_data(x1, x2, lcdint_t);
90  }
91  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
92  if ((y1 < 0) || (y1 >= (lcdint_t)m_h)) return;
93  x1 = max(x1,0);
94  x2 = min(x2,(lcdint_t)m_w-1);
95  uint8_t *buf = m_buf + YADDR8(y1) + x1;
96  for (lcdint_t x = 0; x <= x2 - x1; x++)
97  {
98  *buf = m_color;
99  buf++;
100  }
101 }
102 
104 {
105  drawHLine(x1,y1,x2);
106  drawHLine(x1,y2,x2);
107  drawVLine(x1,y1,y2);
108  drawVLine(x2,y1,y2);
109 }
110 
112 {
113  drawRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
114 }
115 
117 {
118  if (y1 > y2)
119  {
120  swap_data(y1, y2, lcdint_t);
121  }
122  if (x1 > x2)
123  {
124  swap_data(x1, x2, lcdint_t);
125  }
126  x1 -= offset.x;
127  y1 -= offset.y;
128  x2 -= offset.x;
129  y2 -= offset.y;
130  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
131  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
132  x1 = max(x1,0);
133  x2 = min(x2,(lcdint_t)m_w-1);
134  y1 = max(y1,0);
135  y2 = min(y2,(lcdint_t)m_h-1);
136  uint8_t *buf = m_buf + YADDR8(y1) + x1;
137  for (lcdint_t y = y1; y <= y2; y++)
138  {
139  for (lcdint_t x = x1; x <= x2; x++)
140  {
141  *buf = m_color;
142  buf++;
143  }
144  buf += ((lcdint_t)(m_w) - (x2 - x1 + 1));
145  }
146 }
147 
149 {
150  fillRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
151 }
152 
153 //#include <stdio.h>
154 
155 void NanoCanvas8::drawBitmap1(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
156 {
157  uint8_t offs = 0;
158  /* calculate char rectangle */
159  lcdint_t x1 = xpos - offset.x;
160  lcdint_t y1 = ypos - offset.y;
161  lcdint_t x2 = x1 + (lcdint_t)w - 1;
162  lcdint_t y2 = y1 + (lcdint_t)h - 1;
163  /* clip bitmap */
164  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
165  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
166 
167  if (x1 < 0)
168  {
169  bitmap -= x1;
170  x1 = 0;
171  }
172  if (y1 < 0)
173  {
174  bitmap += ((lcduint_t)(-y1) >> 3) * w;
175  offs = ((-y1) & 0x07);
176  y1 = 0;
177  }
178  if (y2 >= (lcdint_t)m_h)
179  {
180  y2 = (lcdint_t)m_h - 1;
181  }
182  if (x2 >= (lcdint_t)m_w)
183  {
184  x2 = (lcdint_t)m_w - 1;
185  }
186  uint8_t offs2 = 8 - offs;
187  lcdint_t y = y1;
188 // printf("[%d;%d] + [%d;%d], P1[%d;%d], P2[%d;%d]\n", xpos, ypos, offset.x, offset.y, x1,y1,x2,y2);
189 // printf("offset: 1=%d, 2=%d\n", offs, offs2);
190  while ( y <= y2)
191  {
192  for ( lcdint_t x = x1; x <= x2; x++ )
193  {
194  uint8_t data = pgm_read_byte( bitmap );
195  uint16_t addr = YADDR8(y) + x;
196  for (uint8_t n = 0; n < min(y2 - y + 1, 8); n++)
197  {
198  if ( data & (1<<(n + offs)) )
199  m_buf[addr] = m_color;
200  else if (!(m_textMode & CANVAS_MODE_TRANSPARENT))
201  m_buf[addr] = 0x00;
202  addr += (lcduint_t)m_w;
203  }
204  bitmap++;
205  }
206  bitmap += (w - (x2 - x1 + 1));
207  y = y + offs2;
208  offs = 0;
209  offs2 = 8;
210  }
211 }
212 
213 void NanoCanvas8::drawBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
214 {
215  /* calculate char rectangle */
216  lcdint_t x1 = xpos - offset.x;
217  lcdint_t y1 = ypos - offset.y;
218  lcdint_t x2 = x1 + (lcdint_t)w - 1;
219  lcdint_t y2 = y1 + (lcdint_t)h - 1;
220  /* clip bitmap */
221  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
222  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
223 
224  if (x1 < 0)
225  {
226  bitmap -= x1;
227  x1 = 0;
228  }
229  if (y1 < 0)
230  {
231  bitmap += (lcduint_t)(-y1) * w;
232  y1 = 0;
233  }
234  if (y2 >= (lcdint_t)m_h)
235  {
236  y2 = (lcdint_t)m_h - 1;
237  }
238  if (x2 >= (lcdint_t)m_w)
239  {
240  x2 = (lcdint_t)m_w - 1;
241  }
242  lcdint_t y = y1;
243  while ( y <= y2 )
244  {
245  for ( lcdint_t x = x1; x <= x2; x++ )
246  {
247  uint8_t data = pgm_read_byte( bitmap );
248  if ( (data) || (!(m_textMode & CANVAS_MODE_TRANSPARENT)) )
249  {
250  m_buf[YADDR8(y) + x] = data;
251  }
252  bitmap++;
253  }
254  bitmap += (w - (x2 - x1 + 1));
255  y++;
256  }
257 }
258 
259 void NanoCanvas8::printChar(uint8_t c)
260 {
261  c -= s_fixedFont.ascii_offset;
262  drawBitmap1(m_cursorX,
263  m_cursorY,
264  s_fixedFont.width,
265  s_fixedFont.height,
266  &s_fixedFont.data[ c * s_fixedFont.pages * s_fixedFont.width ] );
267 }
268 
269 void NanoCanvas8::write(uint8_t c)
270 {
271  if (c == '\n')
272  {
273  m_cursorY += (lcdint_t)s_fixedFont.height;
274  m_cursorX = 0;
275  }
276  else if (c == '\r')
277  {
278  // skip non-printed char
279  }
280  else
281  {
282  printChar( c );
283  m_cursorX += (lcdint_t)s_fixedFont.width;
284  if ((m_textMode & CANVAS_TEXT_WRAP) && (m_cursorX > ((lcdint_t)s_displayWidth - (lcdint_t)s_fixedFont.width)))
285  {
286  m_cursorY += (lcdint_t)s_fixedFont.height;
287  m_cursorX = 0;
288  }
289  }
290 }
291 
292 void NanoCanvas8::printFixed(lcdint_t xpos, lcdint_t y, const char *ch)
293 {
294  m_cursorX = xpos;
295  m_cursorY = y;
296  while (*ch)
297  {
298  write(*ch);
299  ch++;
300  }
301 }
302 
303 void NanoCanvas8::printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch)
304 {
305  m_cursorX = xpos;
306  m_cursorY = y;
307  for (;;)
308  {
309  char c = pgm_read_byte(ch);
310  if (!c) break;
311  write(c);
312  ch++;
313  }
314 }
315 
317 {
318  uint8_t *buf = m_buf;
319  for(uint16_t n = 0; n < YADDR8(m_h); n++)
320  {
321  *buf = 0;
322  buf++;
323  }
324 }
325 
327 {
328  ssd1331_fastDrawBuffer8( x, y, m_w, m_h, m_buf);
329 }
330 
332 {
333  ssd1331_fastDrawBuffer8( offset.x, offset.y, m_w, m_h, m_buf);
334 // printf("==================================\n");
335 }
336 
338 //
339 // 1-BIT GRAPHICS
340 //
342 
343 #define YADDR1(y) (static_cast<uint16_t>((y) >> 3) << m_p)
344 #define BANK_ADDR1(b) ((b) << m_p)
345 
347 {
348  x -= offset.x;
349  y -= offset.y;
350  if ((x<0) || (y<0)) return;
351  if (( x >= (lcdint_t)m_w ) || ( y >= (lcdint_t)m_h)) return;
352  if (m_color)
353  {
354  m_buf[YADDR1(y) + x] |= (1 << (y & 0x7));
355  }
356  else
357  {
358  m_buf[YADDR1(y) + x] &= ~(1 << (y & 0x7));
359  }
360 }
361 
363 {
364  putPixel(p.x, p.y);
365 }
366 
368 {
369  if (x2 < x1) swap_data(x2, x1, lcdint_t);
370  x1 -= offset.x;
371  x2 -= offset.x;
372  y1 -= offset.y;
373  if ((y1 >= (lcdint_t)m_h) || (y1 < 0)) return;
374  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
375  x1 = max(0, x1);
376  x2 = min(x2, (lcdint_t)(m_w -1));
377  for(lcdint_t x = x1; x<=x2; x++)
378  {
379  if (m_color)
380  {
381  m_buf[YADDR1(y1) + x] |= (1 << (y1 & 0x7));
382  }
383  else
384  {
385  m_buf[YADDR1(y1) + x] &= ~(1 << (y1 & 0x7));
386  }
387  }
388 }
389 
391 {
392  if (y2 < y1) swap_data(y2, y1, lcdint_t);
393  x1 -= offset.x;
394  y1 -= offset.y;
395  y2 -= offset.y;
396  if ((x1 >= (lcdint_t)m_w) || (x1 < 0)) return;
397  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
398  y1 = max(0, y1);
399  y2 = min(y2, (lcdint_t)(m_h -1));
400  for(lcdint_t y = y1; y<=y2; y++)
401  {
402  if (m_color)
403  {
404  m_buf[YADDR1(y) + x1] |= (1 << (y & 0x7));
405  }
406  else
407  {
408  m_buf[YADDR1(y) + x1] &= ~(1 << (y & 0x7));
409  }
410  }
411 };
412 
414 {
415  drawHLine(x1, y1, x2);
416  drawHLine(x1, y2, x2);
417  drawVLine(x1, y1, y2);
418  drawVLine(x2, y1, y2);
419 };
420 
422 {
423  drawRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
424 }
425 
427 {
428  if (x2 < x1) swap_data(x2, x1, lcdint_t);
429  if (y2 < y1) swap_data(y2, y1, lcdint_t);
430  x1 -= offset.x;
431  x2 -= offset.x;
432  y1 -= offset.y;
433  y2 -= offset.y;
434  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
435  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
436  x1 = max(0, x1);
437  x2 = min(x2, (lcdint_t)(m_w - 1));
438  y1 = max(0, y1);
439  y2 = min(y2, (lcdint_t)(m_h - 1));
440  uint8_t bank1 = (y1 >> 3);
441  uint8_t bank2 = (y2 >> 3);
442  for (uint8_t bank = bank1; bank<=bank2; bank++)
443  {
444  uint8_t mask = 0xFF;
445  if (bank1 == bank2)
446  {
447  mask = (mask >> ((y1 & 7) + 7 - (y2 & 7))) << (y1 & 7);
448  }
449  else if (bank1 == bank)
450  {
451  mask = (mask << (y1 & 7));
452  }
453  else if (bank2 == bank)
454  {
455  mask = (mask >> (7 - (y2 & 7)));
456  }
457  for (uint8_t x=x1; x<=x2; x++)
458  {
459  if (m_color)
460  {
461  m_buf[BANK_ADDR1(bank) + x] |= mask;
462  }
463  else
464  {
465  m_buf[BANK_ADDR1(bank) + x] &= ~mask;
466  }
467  }
468  }
469 };
470 
472 {
473  fillRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
474 }
475 
477 {
478  for(uint16_t i=0; i< YADDR1(m_h); i++)
479  {
480  m_buf[i] = 0;
481  }
482 }
483 
484 // TODO: Not so fast implementation. needs to be optimized
485 void NanoCanvas1::drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
486 {
487  x -= offset.x;
488  y -= offset.y;
489  lcduint_t origin_width = w;
490  uint8_t offs = y & 0x07;
491  uint8_t complexFlag = 0;
492  uint8_t mainFlag = 1;
493  if (y + (lcdint_t)h <= 0) return;
494  if (y >= (lcdint_t)m_h) return;
495  if (x + (lcdint_t)w <= 0) return;
496  if (x >= (lcdint_t)m_w) return;
497  if (y < 0)
498  {
499  bitmap += ((lcduint_t)((-y) + 7) >> 3) * w;
500  h += y;
501  y = 0;
502  complexFlag = 1;
503  }
504  if (x < 0)
505  {
506  bitmap += -x;
507  w += x;
508  x = 0;
509  }
510  uint8_t max_pages = (lcduint_t)(h + 15 - offs) >> 3;
511  if ((lcduint_t)(y + (lcdint_t)h) > (lcduint_t)m_h)
512  {
513  h = (lcduint_t)(m_h - (lcduint_t)y);
514  }
515  if ((lcduint_t)(x + (lcdint_t)w) > (lcduint_t)m_w)
516  {
517  w = (lcduint_t)(m_w - (lcduint_t)x);
518  }
519  uint8_t pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
520  uint8_t j;
521  lcduint_t i;
522 
523  for(j=0; j < pages; j++)
524  {
525  uint16_t addr = YADDR1(y + ((uint16_t)j<<3)) + x;
526  if ( j == max_pages - 1 ) mainFlag = !offs;
527  for( i=w; i > 0; i--)
528  {
529  uint8_t data = 0;
530  uint8_t mask = 0;
531  if ( mainFlag ) { data |= (pgm_read_byte(bitmap) << offs); mask |= (0xFF << offs); }
532  if ( complexFlag ) { data |= (pgm_read_byte(bitmap - origin_width) >> (8 - offs)); mask |= (0xFF >> (8 - offs)); }
533  if (CANVAS_MODE_TRANSPARENT != (m_textMode & CANVAS_MODE_TRANSPARENT))
534  {
535  m_buf[addr] &= ~mask;
536  m_buf[addr] |= m_color == BLACK ? ~data: data;
537  }
538  else
539  {
540  if (m_color == BLACK)
541  m_buf[addr] &= ~data;
542  else
543  m_buf[addr] |= data;
544  }
545  bitmap++;
546  addr++;
547  }
548  bitmap += origin_width - w;
549  complexFlag = offs;
550  }
551 }
552 
553 void NanoCanvas1::printChar(uint8_t c)
554 {
555  c -= s_fixedFont.ascii_offset;
556  drawBitmap1(m_cursorX,
557  m_cursorY,
558  s_fixedFont.width,
559  s_fixedFont.height,
560  &s_fixedFont.data[ c * s_fixedFont.pages * s_fixedFont.width ] );
561  /* calculate char rectangle */
562 }
563 
564 void NanoCanvas1::write(uint8_t c)
565 {
566  if (c == '\n')
567  {
568  m_cursorY += (lcdint_t)s_fixedFont.height;
569  m_cursorX = 0;
570  }
571  else if (c == '\r')
572  {
573  // skip non-printed char
574  }
575  else
576  {
577  printChar( c );
578  m_cursorX += (lcdint_t)s_fixedFont.width;
579  if ((m_textMode & CANVAS_TEXT_WRAP) && (m_cursorX > ((lcdint_t)s_displayWidth - (lcdint_t)s_fixedFont.width)))
580  {
581  m_cursorY += (lcdint_t)s_fixedFont.height;
582  m_cursorX = 0;
583  }
584  }
585 }
586 
587 void NanoCanvas1::printFixed(lcdint_t xpos, lcdint_t y, const char *ch)
588 {
589  m_cursorX = xpos;
590  m_cursorY = y;
591  while (*ch)
592  {
593  write(*ch);
594  ch++;
595  }
596 }
597 
598 void NanoCanvas1::printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch)
599 {
600  m_cursorX = xpos;
601  m_cursorY = y;
602  for (;;)
603  {
604  char c = pgm_read_byte(ch);
605  if (!c) break;
606  write(c);
607  ch++;
608  }
609 }
610 
612 {
613  ssd1306_drawBuffer( x, y >> 3, m_w, m_h, m_buf);
614 }
615 
617 {
618  ssd1306_drawBuffer( offset.x, offset.y >> 3, m_w, m_h, m_buf);
619 }
620 
622 //
623 // 16-BIT GRAPHICS
624 //
626 
627 /* We need to use multiply operation, because there are displays on the market *
628  * with resolution different from 2^N (160x128, 96x64, etc.) */
629 #define YADDR16(y) (static_cast<uint16_t>(y) * (m_w << 1))
630 
632 {
633  x -= offset.x;
634  y -= offset.y;
635  if ((x >= 0) && (y >= 0) && (x < (lcdint_t)m_w) && (y < (lcdint_t)m_h))
636  {
637  m_buf[YADDR16(y) + (x<<1)] = m_color >> 8;
638  m_buf[YADDR16(y) + (x<<1) + 1] = m_color & 0xFF;
639  }
640 }
641 
643 {
644  putPixel(p.x, p.y);
645 }
646 
648 {
649  x1 -= offset.x;
650  y1 -= offset.y;
651  y2 -= offset.y;
652  if (y1 > y2)
653  {
654  swap_data(y1, y2, lcdint_t);
655  }
656  if ((x1 < 0) || (x1 >= (lcdint_t)m_w)) return;
657  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
658  y1 = max(y1,0);
659  uint8_t *buf = m_buf + YADDR16(y1) + (x1 << 1);
660  y2 = min(y2,(lcdint_t)m_h-1) - y1;
661  do
662  {
663  buf[0] = m_color >> 8;
664  buf[1] = m_color & 0xFF;
665  buf += (m_w<<1);
666  }
667  while (y2--);
668 }
669 
671 {
672  x1 -= offset.x;
673  y1 -= offset.y;
674  x2 -= offset.x;
675  if (x1 > x2)
676  {
677  swap_data(x1, x2, lcdint_t);
678  }
679  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
680  if ((y1 < 0) || (y1 >= (lcdint_t)m_h)) return;
681  x1 = max(x1,0);
682  x2 = min(x2,(lcdint_t)m_w-1);
683  uint8_t *buf = m_buf + YADDR16(y1) + (x1<<1);
684  for (lcdint_t x = 0; x <= x2 - x1; x++)
685  {
686  buf[0] = m_color >> 8;
687  buf[1] = m_color & 0xFF;
688  buf+=2;
689  }
690 }
691 
693 {
694  drawHLine(x1,y1,x2);
695  drawHLine(x1,y2,x2);
696  drawVLine(x1,y1,y2);
697  drawVLine(x2,y1,y2);
698 }
699 
701 {
702  drawRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
703 }
704 
706 {
707  if (y1 > y2)
708  {
709  swap_data(y1, y2, lcdint_t);
710  }
711  if (x1 > x2)
712  {
713  swap_data(x1, x2, lcdint_t);
714  }
715  x1 -= offset.x;
716  y1 -= offset.y;
717  x2 -= offset.x;
718  y2 -= offset.y;
719  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
720  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
721  x1 = max(x1,0);
722  x2 = min(x2,(lcdint_t)m_w-1);
723  y1 = max(y1,0);
724  y2 = min(y2,(lcdint_t)m_h-1);
725  uint8_t *buf = m_buf + YADDR16(y1) + (x1<<1);
726  for (lcdint_t y = y1; y <= y2; y++)
727  {
728  for (lcdint_t x = x1; x <= x2; x++)
729  {
730  buf[0] = m_color >> 8;
731  buf[1] = m_color & 0xFF;
732  buf+=2;
733  }
734  buf += ( ((lcdint_t)(m_w) - (x2 - x1 + 1)) <<1 );
735  }
736 }
737 
739 {
740  fillRect(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
741 }
742 
743 //#include <stdio.h>
744 
745 void NanoCanvas16::drawBitmap1(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
746 {
747  uint8_t offs = 0;
748  /* calculate char rectangle */
749  lcdint_t x1 = xpos - offset.x;
750  lcdint_t y1 = ypos - offset.y;
751  lcdint_t x2 = x1 + (lcdint_t)w - 1;
752  lcdint_t y2 = y1 + (lcdint_t)h - 1;
753  /* clip bitmap */
754  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
755  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
756 
757  if (x1 < 0)
758  {
759  bitmap -= x1;
760  x1 = 0;
761  }
762  if (y1 < 0)
763  {
764  bitmap += ((lcduint_t)(-y1) >> 3) * w;
765  offs = ((-y1) & 0x07);
766  y1 = 0;
767  }
768  if (y2 >= (lcdint_t)m_h)
769  {
770  y2 = (lcdint_t)m_h - 1;
771  }
772  if (x2 >= (lcdint_t)m_w)
773  {
774  x2 = (lcdint_t)m_w - 1;
775  }
776  uint8_t offs2 = 8 - offs;
777  lcdint_t y = y1;
778 // printf("[%d;%d] + [%d;%d], P1[%d;%d], P2[%d;%d]\n", xpos, ypos, offset.x, offset.y, x1,y1,x2,y2);
779 // printf("offset: 1=%d, 2=%d\n", offs, offs2);
780  while ( y <= y2)
781  {
782  for ( lcdint_t x = x1; x <= x2; x++ )
783  {
784  uint8_t data = pgm_read_byte( bitmap );
785  uint16_t addr = YADDR16(y) + (x<<1);
786  for (uint8_t n = 0; n < min(y2 - y + 1, 8); n++)
787  {
788  if ( data & (1<<(n + offs)) )
789  {
790  m_buf[addr] = m_color >> 8;
791  m_buf[addr+1] = m_color & 0xFF;
792  }
793  else if (!(m_textMode & CANVAS_MODE_TRANSPARENT))
794  {
795  m_buf[addr] = 0x00;
796  m_buf[addr+1] = 0x00;
797  }
798  addr += ((lcduint_t)m_w << 1);
799  }
800  bitmap++;
801  }
802  bitmap += (w - (x2 - x1 + 1));
803  y = y + offs2;
804  offs = 0;
805  offs2 = 8;
806  }
807 }
808 
809 void NanoCanvas16::drawBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
810 {
811  /* calculate char rectangle */
812  lcdint_t x1 = xpos - offset.x;
813  lcdint_t y1 = ypos - offset.y;
814  lcdint_t x2 = x1 + (lcdint_t)w - 1;
815  lcdint_t y2 = y1 + (lcdint_t)h - 1;
816  /* clip bitmap */
817  if ((x2 < 0) || (x1 >= (lcdint_t)m_w)) return;
818  if ((y2 < 0) || (y1 >= (lcdint_t)m_h)) return;
819 
820  if (x1 < 0)
821  {
822  bitmap -= x1;
823  x1 = 0;
824  }
825  if (y1 < 0)
826  {
827  bitmap += (lcduint_t)(-y1) * w;
828  y1 = 0;
829  }
830  if (y2 >= (lcdint_t)m_h)
831  {
832  y2 = (lcdint_t)m_h - 1;
833  }
834  if (x2 >= (lcdint_t)m_w)
835  {
836  x2 = (lcdint_t)m_w - 1;
837  }
838  lcdint_t y = y1;
839  while ( y <= y2 )
840  {
841  for ( lcdint_t x = x1; x <= x2; x++ )
842  {
843  uint8_t data = pgm_read_byte( bitmap );
844  if ( (data) || (!(m_textMode & CANVAS_MODE_TRANSPARENT)) )
845  {
846  uint16_t color = (((uint16_t)data & 0b11100000) << 8) |
847  (((uint16_t)data & 0b00011100) << 6) |
848  (((uint16_t)data & 0b00000011) << 3);
849  m_buf[YADDR16(y) + (x<<1)] = color;
850  }
851  bitmap++;
852  }
853  bitmap += (w - (x2 - x1 + 1));
854  y++;
855  }
856 }
857 
858 void NanoCanvas16::printChar(uint8_t c)
859 {
860  c -= s_fixedFont.ascii_offset;
861  drawBitmap1(m_cursorX,
862  m_cursorY,
863  s_fixedFont.width,
864  s_fixedFont.height,
865  &s_fixedFont.data[ c * s_fixedFont.pages * s_fixedFont.width ] );
866 }
867 
868 void NanoCanvas16::write(uint8_t c)
869 {
870  if (c == '\n')
871  {
872  m_cursorY += (lcdint_t)s_fixedFont.height;
873  m_cursorX = 0;
874  }
875  else if (c == '\r')
876  {
877  // skip non-printed char
878  }
879  else
880  {
881  printChar( c );
882  m_cursorX += (lcdint_t)s_fixedFont.width;
883  if ((m_textMode & CANVAS_TEXT_WRAP) && (m_cursorX > ((lcdint_t)s_displayWidth - (lcdint_t)s_fixedFont.width)))
884  {
885  m_cursorY += (lcdint_t)s_fixedFont.height;
886  m_cursorX = 0;
887  }
888  }
889 }
890 
891 void NanoCanvas16::printFixed(lcdint_t xpos, lcdint_t y, const char *ch)
892 {
893  m_cursorX = xpos;
894  m_cursorY = y;
895  while (*ch)
896  {
897  write(*ch);
898  ch++;
899  }
900 }
901 
902 void NanoCanvas16::printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch)
903 {
904  m_cursorX = xpos;
905  m_cursorY = y;
906  for (;;)
907  {
908  char c = pgm_read_byte(ch);
909  if (!c) break;
910  write(c);
911  ch++;
912  }
913 }
914 
916 {
917  uint8_t *buf = m_buf;
918  for(uint16_t n = 0; n < YADDR16(m_h); n++)
919  {
920  *buf = 0;
921  buf++;
922  }
923 }
924 
926 {
927  ssd1331_fastDrawBuffer16( x, y, m_w, m_h, m_buf);
928 }
929 
931 {
932  ssd1331_fastDrawBuffer16( offset.x, offset.y, m_w, m_h, m_buf);
933 // printf("==================================\n");
934 }
void write(uint8_t c)
Definition: canvas.cpp:564
void drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2)
Definition: canvas.cpp:82
unsigned int lcduint_t
Definition: io.h:42
void printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch)
Definition: canvas.cpp:598
void blt()
Definition: canvas.cpp:616
void drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2)
Definition: canvas.cpp:647
void printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch)
Definition: canvas.cpp:902
uint8_t s_displayWidth
void printFixed(lcdint_t xpos, lcdint_t y, const char *ch)
Definition: canvas.cpp:292
void fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: canvas.cpp:116
void putPixel(lcdint_t x, lcdint_t y)
Definition: canvas.cpp:346
void clear()
Definition: canvas.cpp:476
void putPixel(lcdint_t x, lcdint_t y)
Definition: canvas.cpp:631
NanoPoint p2
Definition: canvas.h:152
void putPixel(lcdint_t x, lcdint_t y)
Definition: canvas.cpp:45
void drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2)
Definition: canvas.cpp:390
void write(uint8_t c)
Definition: canvas.cpp:269
void ssd1331_fastDrawBuffer16(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *data)
Definition: ssd1331_api.c:71
SFixedFontInfo s_fixedFont
Definition: tiler.h:39
lcdint_t y
Definition: canvas.h:48
void blt()
Definition: canvas.cpp:930
void printFixed(lcdint_t xpos, lcdint_t y, const char *ch)
Definition: canvas.cpp:587
void drawRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: canvas.cpp:413
uint8_t ascii_offset
ascii offset
void clear()
Definition: canvas.cpp:316
void fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: canvas.cpp:705
void blt()
Definition: canvas.cpp:331
void printFixed(lcdint_t xpos, lcdint_t y, const char *ch)
Definition: canvas.cpp:891
void fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: canvas.cpp:426
void drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws monochrome bitmap in color buffer using color, specified via setColor() method Draws monochrome...
Definition: canvas.cpp:155
void drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2)
Definition: canvas.cpp:60
void drawBitmap8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws 8-bit color bitmap in color buffer. Draws 8-bit color bitmap in color buffer.
Definition: canvas.cpp:809
void write(uint8_t c)
Definition: canvas.cpp:868
#define max(a, b)
#define min(a, b)
void drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws monochrome bitmap in color buffer using color, specified via setColor() method Draws monochrome...
Definition: canvas.cpp:485
void drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2)
Definition: canvas.cpp:670
int lcdint_t
Definition: io.h:40
uint8_t width
width in pixels
void drawBitmap8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws 8-bit color bitmap in color buffer. Draws 8-bit color bitmap in color buffer.
Definition: canvas.cpp:213
void drawRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: canvas.cpp:103
void printChar(uint8_t c)
Definition: canvas.cpp:553
void drawRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: canvas.cpp:692
void printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch)
Definition: canvas.cpp:303
NanoPoint offset
Definition: canvas.h:280
void printChar(uint8_t c)
Definition: canvas.cpp:858
void clear()
Definition: canvas.cpp:915
Black color.
Definition: canvas.h:516
NanoPoint p1
Definition: canvas.h:149
lcdint_t x
Definition: canvas.h:46
const uint8_t * data
font chars bits
uint8_t pages
height in pages (each page height is 8-pixels)
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
void printChar(uint8_t c)
Definition: canvas.cpp:259
void drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
Draws monochrome bitmap in color buffer using color, specified via setColor() method Draws monochrome...
Definition: canvas.cpp:745
void drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2)
Definition: canvas.cpp:367
uint8_t height
height in pixels
void ssd1331_fastDrawBuffer8(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *data)
Definition: ssd1331_api.c:59