COSA
An Object-Oriented Platform for Arduino Programming
Canvas.cpp
Go to the documentation of this file.
1 
21 #include "Font.hh"
22 #include "System5x7.hh"
23 #include "Canvas.hh"
24 
26 
28 Canvas::shade(color16_t color, uint8_t scale)
29 {
30  color16_t res;
31  if (UNLIKELY(scale > 100)) scale = 100;
32  res.red = (scale * color.red) / 100;
33  res.green = (scale * color.green) / 100;
34  res.blue = (scale * color.blue) / 100;
35  return (res);
36 }
37 
40 {
41  color16_t res;
42  res.red = (c1.red + c2.red) / 2;
43  res.green = (c1.green + c2.green) / 2;
44  res.blue = (c1.blue + c2.blue) / 2;
45  return (res);
46 }
47 
48 uint8_t
50 {
51  return (m_direction);
52 }
53 
54 uint8_t
55 Canvas::set_orientation(uint8_t direction)
56 {
57  uint8_t previous = m_direction;
58  m_direction = (direction & 1);
59  return (previous);
60 }
61 
62 void
63 Canvas::draw_pixel(uint16_t x, uint16_t y)
64 {
65  fill_rect(x, y, 1, 1);
66 }
67 
68 void
69 Canvas::draw_bitmap(uint16_t x, uint16_t y, const uint8_t* bp,
70  uint16_t width, uint16_t height,
71  uint8_t scale)
72 {
73  if (scale == 1) {
74  for (uint16_t i = 0; i < height; i += 8) {
75  for (uint16_t j = 0; j < width; j++) {
76  uint8_t bits = pgm_read_byte(bp++);
77  if (bits == 0xff) {
78  draw_vertical_line(x + j, y + i, CHARBITS);
79  }
80  else {
81  for (uint8_t k = 0; k < 8; k++) {
82  if (bits == 0) break;
83  if (bits & 1) draw_pixel(x + j, y + k + i);
84  bits >>= 1;
85  }
86  }
87  }
88  }
89  }
90  else {
91  for (uint16_t i = 0; i < height; i += 8) {
92  for (uint16_t j = 0; j < width; j++) {
93  uint8_t bits = pgm_read_byte(bp++);
94  for (uint8_t k = 0; k < 8; k++) {
95  if (bits == 0) break;
96  if (bits & 1) fill_rect(x + j*scale, y + (k+i)*scale, scale, scale);
97  bits >>= 1;
98  }
99  }
100  }
101  }
102 }
103 
104 void
105 Canvas::draw_icon(uint16_t x, uint16_t y, const uint8_t* bp,
106  uint16_t width, uint16_t height,
107  uint8_t scale)
108 {
109  draw_bitmap(x, y, bp, width, height, scale);
110 }
111 
112 void
113 Canvas::draw_icon(uint16_t x, uint16_t y, const uint8_t* bp, uint8_t scale)
114 {
115  uint16_t width = pgm_read_byte(bp++);
116  uint16_t height = pgm_read_byte(bp++);
117  draw_icon(x, y, bp, width, height, scale);
118 }
119 
120 void
121 Canvas::draw_image(uint16_t x, uint16_t y, Image* image)
122 {
123  color16_t saved = set_pen_color(0);
124  uint16_t width = image->WIDTH;
125  uint16_t height = image->HEIGHT;
126  for (uint16_t i = 0; i < height; i++) {
128  size_t count;
129  for (uint16_t j = 0; j < width; j += count) {
130  count = (width - j > Image::BUFFER_MAX) ? Image::BUFFER_MAX : width - j;
131  image->read(buf, Image::BUFFER_MAX);
132  for (uint8_t k = 0; k < count; k++) {
133  set_pen_color(buf[k]);
134  draw_pixel(x + j, y + i);
135  }
136  }
137  }
138  set_pen_color(saved);
139 }
140 
141 void
142 Canvas::draw_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
143 {
144  draw_horizontal_line(x, y, width);
145  draw_vertical_line(x + width, y, height);
146  draw_vertical_line(x, y, height);
147  draw_horizontal_line(x, y + height, width);
148 }
149 
150 void
151 Canvas::fill_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
152 {
153  if (width > height) {
154  for (uint16_t h = 0; h < height; h++)
155  draw_horizontal_line(x, y + h, width);
156  }
157  else {
158  for (uint16_t w = 0; w < width; w++)
159  draw_vertical_line(x + w, y, height);
160  }
161 }
162 
163 #define dist(x, y) ((x > y) ? (x - y) : (y - x))
164 #define swap(a, b) { uint16_t t = a; a = b; b = t; }
165 
166 void
167 Canvas::draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
168 {
169  bool steep = (dist(y0, y1) > dist(x0, x1));
170  if (steep) {
171  swap(x0, y0);
172  swap(x1, y1);
173  }
174  if (x0 > x1) {
175  swap(x0, x1);
176  swap(y0, y1);
177  }
178  uint16_t dx, dy;
179  dx = x1 - x0;
180  dy = dist(y0, y1);
181  int16_t err = dx / 2;
182  int8_t ystep = (y0 < y1) ? 1 : -1;
183  for (; x0 <= x1; x0++) {
184  if (steep) {
185  draw_pixel(y0, x0);
186  } else {
187  draw_pixel(x0, y0);
188  }
189  err -= dy;
190  if (err < 0) {
191  y0 += ystep;
192  err += dx;
193  }
194  }
195 }
196 
197 void
198 Canvas::draw_vertical_line(uint16_t x, uint16_t y, uint16_t length)
199 {
200  draw_line(x, y, x, y + length);
201 }
202 
203 void
204 Canvas::draw_horizontal_line(uint16_t x, uint16_t y, uint16_t length)
205 {
206  draw_line(x, y, x + length, y);
207 }
208 
209 void
210 Canvas::draw_poly_P(const int8_t* poly, uint8_t scale)
211 {
212  if (UNLIKELY(scale == 0)) return;
213  for (;;) {
214  int8_t dx = pgm_read_byte(poly++);
215  int8_t dy = pgm_read_byte(poly++);
216  if (UNLIKELY(dx == 0 && dy == 0)) return;
217  uint16_t x, y;
218  get_cursor(x, y);
219  x += dx*scale;
220  y += dy*scale;
221  draw_line(x, y);
222  }
223 }
224 
225 void
226 Canvas::draw_stroke_P(const int8_t* stroke, uint8_t scale)
227 {
228  if (UNLIKELY(scale == 0)) return;
229  for (;;) {
230  int8_t dx = pgm_read_byte(stroke++);
231  int8_t dy = pgm_read_byte(stroke++);
232  if (UNLIKELY(dx == 0 && dy == 0)) return;
233  if (dx <= 0 && dy <= 0) {
234  move_cursor(dx*scale, dy*scale);
235  }
236  else {
237  uint16_t x, y;
238  get_cursor(x, y);
239  x += dx*scale;
240  y += dy*scale;
241  draw_line(x, y);
242  }
243  }
244 }
245 
246 void
247 Canvas::draw_circle(uint16_t x, uint16_t y, uint16_t radius)
248 {
249  int16_t f = 1 - radius;
250  int16_t dx = 1;
251  int16_t dy = -2 * radius;
252  int8_t rx = 0;
253  int8_t ry = radius;
254 
255  draw_pixel(x, y + radius);
256  draw_pixel(x, y - radius);
257  draw_pixel(x + radius, y);
258  draw_pixel(x - radius, y);
259  while (rx < ry) {
260  if (f >= 0) {
261  ry--;
262  dy += 2;
263  f += dy;
264  }
265  rx++;
266  dx += 2;
267  f += dx;
268  draw_pixel(x + rx, y + ry);
269  draw_pixel(x - rx, y + ry);
270  draw_pixel(x + rx, y - ry);
271  draw_pixel(x - rx, y - ry);
272  draw_pixel(x + ry, y + rx);
273  draw_pixel(x - ry, y + rx);
274  draw_pixel(x + ry, y - rx);
275  draw_pixel(x - ry, y - rx);
276  }
277 }
278 
279 void
280 Canvas::fill_circle(uint16_t x, uint16_t y, uint16_t radius)
281 {
282  int16_t dx = 0, dy = radius;
283  int16_t p = 1 - radius;
284 
285  while (dx <= dy) {
286  draw_vertical_line(x + dx, y - dy, dy + dy);
287  draw_vertical_line(x - dx, y - dy, dy + dy);
288  draw_vertical_line(x + dy, y - dx, dx + dx);
289  draw_vertical_line(x - dy, y - dx, dx + dx);
290  dx++;
291  if (p < 0)
292  p = p + (dx << 1) + 1;
293  else {
294  dy--;
295  p = p + ((dx - dy) << 1) + 1;
296  }
297  }
298 }
299 
300 void
301 Canvas::draw_roundrect(uint16_t x, uint16_t y,
302  uint16_t width, uint16_t height,
303  uint16_t radius)
304 {
305  uint16_t diameter = 2 * radius;
306  int16_t f = 1 - radius;
307  int16_t dx = 1;
308  int16_t dy = -diameter;
309  int8_t rx = 0;
310  int8_t ry = radius;
311 
312  // Adjust position, width and height
313  x += radius;
314  y += radius;
315  width -= diameter;
316  height -= diameter;
317 
318  // Draw the boundary rectangle
319  draw_horizontal_line(x, y - radius, width + 1);
320  draw_vertical_line(x + width + radius, y, height + 1);
321  draw_vertical_line(x - radius, y, height + 1);
322  draw_horizontal_line(x, y + height + radius, width + 1);
323 
324  // Draw the round corners
325  while (rx < ry) {
326  if (f >= 0) {
327  ry--;
328  dy += 2;
329  f += dy;
330  }
331  rx++;
332  dx += 2;
333  f += dx;
334  draw_pixel(x + rx + width, y - ry);
335  draw_pixel(x + ry + width, y - rx);
336  draw_pixel(x + rx + width, y + ry + height);
337  draw_pixel(x + ry + width, y + rx + height);
338  draw_pixel(x - rx, y + ry + height);
339  draw_pixel(x - ry, y + rx + height);
340  draw_pixel(x - rx, y - ry);
341  draw_pixel(x - ry, y - rx);
342  }
343 }
344 
345 void
346 Canvas::fill_roundrect(uint16_t x, uint16_t y,
347  uint16_t width, uint16_t height,
348  uint16_t radius)
349 {
350  int16_t dx = 0, dy = radius;
351  int16_t p = 1 - radius;
352  uint16_t diameter = 2 * radius;
353 
354  // Adjust the position and fill the inner rectangle
355  x += radius;
356  width -= diameter;
357  fill_rect(x, y, width, height + 1);
358  height -= diameter;
359  y += radius;
360 
361  // Draw the outer rectangle and corners
362  while (dx <= dy) {
363  draw_vertical_line(x + dx + width, y - dy, dy + dy + height);
364  draw_vertical_line(x - dx, y - dy, dy + dy + height);
365  draw_vertical_line(x + dy + width, y - dx, dx + dx + height);
366  draw_vertical_line(x - dy, y - dx, dx + dx + height);
367  dx++;
368  if (p < 0)
369  p = p + (dx << 1) + 1;
370  else {
371  dy--;
372  p = p + ((dx - dy) << 1) + 1;
373  }
374  }
375 }
376 
377 void
378 Canvas::draw_char(uint16_t x, uint16_t y, char c)
379 {
380  uint8_t scale = get_text_scale();
382  Font* font = get_text_font();
383  font->draw(this, c, x, y, scale);
384  set_cursor(x + scale * (font->WIDTH + font->SPACING), y);
385  set_pen_color(saved);
386 }
387 
388 void
390 {
391  char c;
392  while ((c = *s++) != 0)
393  draw_char(c);
394 }
395 
396 void
398 {
399  const char* sp = (const char*) s;
400  char c;
401  while ((c = pgm_read_byte(sp++)) != 0)
402  draw_char(c);
403 }
404 
405 void
407 {
409  fill_rect(0, 0, WIDTH, HEIGHT);
410  set_pen_color(saved);
411 }
412 
413 void
414 Canvas::run(uint8_t ix, const void_P* tab, uint8_t max)
415 {
416  if (UNLIKELY(ix >= max)) return;
417  const uint8_t* ip = (const uint8_t*) pgm_read_word(tab + ix);
418  uint8_t x, y, r, g, b, w, h, s;
419  int8_t dx, dy;
420  char c;
421  while (1) {
422  switch (pgm_read_byte(ip++)) {
423  case END_SCRIPT:
424  return;
425  case CALL_SCRIPT:
426  ix = pgm_read_byte(ip++);
427  if (UNLIKELY(ix >= max)) return;
428  run(ix, tab, max);
429  break;
430  case SET_CANVAS_COLOR:
431  r = pgm_read_byte(ip++);
432  g = pgm_read_byte(ip++);
433  b = pgm_read_byte(ip++);
434  set_canvas_color(color(r, b, g));
435  break;
436  case SET_PEN_COLOR:
437  r = pgm_read_byte(ip++);
438  g = pgm_read_byte(ip++);
439  b = pgm_read_byte(ip++);
440  set_pen_color(color(r, g, b));
441  break;
442  case SET_TEXT_COLOR:
443  r = pgm_read_byte(ip++);
444  g = pgm_read_byte(ip++);
445  b = pgm_read_byte(ip++);
446  set_text_color(color(r, g, b));
447  break;
448  case SET_TEXT_SCALE:
449  set_text_scale(pgm_read_byte(ip++));
450  break;
451  case SET_TEXT_FONT:
452  ix = pgm_read_byte(ip++);
453  if (UNLIKELY(ix >= max)) return;
454  set_text_font((Font*) pgm_read_word(tab + ix));
455  break;
456  case SET_CURSOR:
457  x = pgm_read_byte(ip++);
458  y = pgm_read_byte(ip++);
459  set_cursor(x, y);
460  break;
461  case MOVE_CURSOR:
462  dx = pgm_read_byte(ip++);
463  dy = pgm_read_byte(ip++);
464  move_cursor(dx, dy);
465  break;
466  case DRAW_BITMAP:
467  ix = pgm_read_byte(ip++);
468  if (UNLIKELY(ix >= max)) return;
469  w = pgm_read_byte(ip++);
470  h = pgm_read_byte(ip++);
471  s = pgm_read_byte(ip++);
472  draw_bitmap((const uint8_t*) pgm_read_word(tab + ix), w, h, s);
473  break;
474  case DRAW_ICON:
475  ix = pgm_read_byte(ip++);
476  if (UNLIKELY(ix >= max)) return;
477  s = pgm_read_byte(ip++);
478  draw_icon((const uint8_t*) pgm_read_word(tab + ix), s);
479  break;
480  case DRAW_PIXEL:
481  draw_pixel();
482  break;
483  case DRAW_LINE:
484  x = pgm_read_byte(ip++);
485  y = pgm_read_byte(ip++);
486  draw_line(x, y);
487  break;
488  case DRAW_POLY:
489  ix = pgm_read_byte(ip++);
490  if (UNLIKELY(ix >= max)) return;
491  s = pgm_read_byte(ip++);
492  draw_poly_P((const int8_t*) pgm_read_word(tab + ix), s);
493  break;
494  case DRAW_STROKE:
495  ix = pgm_read_byte(ip++);
496  if (UNLIKELY(ix >= max)) return;
497  s = pgm_read_byte(ip++);
498  draw_stroke_P((const int8_t*) pgm_read_word(tab + ix), s);
499  break;
500  case DRAW_RECT:
501  w = pgm_read_byte(ip++);
502  h = pgm_read_byte(ip++);
503  draw_rect(w, h);
504  break;
505  case FILL_RECT:
506  w = pgm_read_byte(ip++);
507  h = pgm_read_byte(ip++);
508  fill_rect(w, h);
509  break;
510  case DRAW_ROUNDRECT:
511  w = pgm_read_byte(ip++);
512  h = pgm_read_byte(ip++);
513  r = pgm_read_byte(ip++);
514  draw_roundrect(w, h, r);
515  break;
516  case FILL_ROUNDRECT:
517  w = pgm_read_byte(ip++);
518  h = pgm_read_byte(ip++);
519  r = pgm_read_byte(ip++);
520  fill_roundrect(w, h, r);
521  break;
522  case DRAW_CIRCLE:
523  r = pgm_read_byte(ip++);
524  draw_circle(r);
525  break;
526  case FILL_CIRCLE:
527  r = pgm_read_byte(ip++);
528  fill_circle(r);
529  break;
530  case DRAW_CHAR:
531  c = pgm_read_byte(ip++);
532  draw_char(c);
533  break;
534  case DRAW_STRING:
535  ix = pgm_read_byte(ip++);
536  if (UNLIKELY(ix >= max)) return;
537  draw_string((str_P) pgm_read_word(tab + ix));
538  break;
539  case FILL_SCREEN:
540  fill_screen();
541  break;
542  default:
543  return;
544  }
545  }
546 }
547 
color16_t set_text_color(color16_t color)
Definition: Canvas.hh:470
virtual uint8_t set_orientation(uint8_t direction)
Definition: Canvas.cpp:55
Definition: Font.hh:30
void set_cursor(uint16_t x, uint16_t y)
Definition: Canvas.hh:527
virtual uint8_t get_orientation()
Definition: Canvas.cpp:49
virtual void draw_char(uint16_t x, uint16_t y, char c)
Definition: Canvas.cpp:378
unsigned int green
Definition: Canvas.hh:53
static const size_t BUFFER_MAX
Definition: Canvas.hh:363
#define dist(x, y)
Definition: Canvas.cpp:163
virtual void draw_circle(uint16_t x, uint16_t y, uint16_t radius)
Definition: Canvas.cpp:247
virtual void draw_image(uint16_t x, uint16_t y, Image *image)
Definition: Canvas.cpp:121
color16_t color(uint8_t red, uint8_t green, uint8_t blue)
Definition: Canvas.hh:549
color16_t set_pen_color(color16_t color)
Definition: Canvas.hh:451
IOStream & tab(IOStream &outs)
Definition: IOStream.hh:805
color16_t set_canvas_color(color16_t color)
Definition: Canvas.hh:432
color16_t get_canvas_color() const
Definition: Canvas.hh:422
const uint8_t SPACING
Definition: Font.hh:37
virtual void draw_icon(uint16_t x, uint16_t y, const uint8_t *bp, uint16_t width, uint16_t height, uint8_t scale=1)
Definition: Canvas.cpp:105
void run(uint8_t ix, const void_P *tab, uint8_t max)
Definition: Canvas.cpp:414
Font * set_text_font(Font *font)
Definition: Canvas.hh:488
const uint8_t WIDTH
Definition: Font.hh:35
uint8_t get_text_scale() const
Definition: Canvas.hh:497
uint8_t set_text_scale(uint8_t scale)
Definition: Canvas.hh:507
void move_cursor(int16_t dx, int16_t dy)
Definition: Canvas.hh:537
unsigned int blue
Definition: Canvas.hh:52
virtual void fill_circle(uint16_t x, uint16_t y, uint16_t radius)
Definition: Canvas.cpp:280
virtual void fill_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
Definition: Canvas.cpp:151
color16_t get_text_color() const
Definition: Canvas.hh:460
#define CHARBITS
Definition: Types.h:57
const class prog_str * str_P
Definition: Types.h:187
uint16_t HEIGHT
Definition: Canvas.hh:340
void get_cursor(uint16_t &x, uint16_t &y) const
Definition: Canvas.hh:517
#define swap(a, b)
Definition: Canvas.cpp:164
Font * get_text_font() const
Definition: Canvas.hh:478
virtual void fill_roundrect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius)
Definition: Canvas.cpp:346
virtual void fill_screen()
Definition: Canvas.cpp:406
virtual void draw_string(char *s)
Definition: Canvas.cpp:389
static Context context
Definition: Canvas.hh:1009
uint16_t WIDTH
Definition: Canvas.hh:337
static color16_t shade(color16_t color, uint8_t scale)
Definition: Canvas.cpp:28
virtual bool read(color16_t *buf, size_t count)=0
virtual void draw_poly_P(const int8_t *poly, uint8_t scale=1)
Definition: Canvas.cpp:210
virtual void draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
Definition: Canvas.cpp:167
virtual void draw_vertical_line(uint16_t x, uint16_t y, uint16_t length)
Definition: Canvas.cpp:198
const void * void_P
Definition: Types.h:260
uint16_t HEIGHT
Definition: Canvas.hh:370
virtual void draw_roundrect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius)
Definition: Canvas.cpp:301
virtual void draw(Canvas *canvas, char c, uint16_t x, uint16_t y, uint8_t scale)
Definition: Font.cpp:24
unsigned int red
Definition: Canvas.hh:54
virtual void draw_bitmap(uint16_t x, uint16_t y, const uint8_t *bp, uint16_t width, uint16_t height, uint8_t scale=1)
Definition: Canvas.cpp:69
#define UNLIKELY(x)
Definition: Types.h:153
void draw_pixel()
Definition: Canvas.hh:596
virtual void draw_stroke_P(const int8_t *stroke, uint8_t scale=1)
Definition: Canvas.cpp:226
uint16_t WIDTH
Definition: Canvas.hh:369
virtual void draw_horizontal_line(uint16_t x, uint16_t y, uint16_t length)
Definition: Canvas.cpp:204
uint8_t m_direction
Definition: Canvas.hh:1015
static color16_t blend(color16_t c1, color16_t c2)
Definition: Canvas.cpp:39
virtual void draw_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
Definition: Canvas.cpp:142