libDaisy
Hardware Library for Daisy
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
display.h
Go to the documentation of this file.
1#pragma once
2#ifndef DSY_DISPLAY_H
3#define DSY_DISPLAY_H
4#include <cmath>
5#include "util/oled_fonts.h"
6#include "daisy_core.h"
7#include "graphics_common.h"
8
9#ifndef deg2rad
10#define deg2rad(deg) ((deg)*3.141592 / 180.0)
11#endif
12
13namespace daisy
14{
20{
21 public:
24
25 virtual uint16_t Height() const = 0;
26 virtual uint16_t Width() const = 0;
27
29 {
30 return Rectangle(int16_t(Width()), int16_t(Height()));
31 }
32
33
34 size_t CurrentX() { return currentX_; };
35 size_t CurrentY() { return currentY_; };
36
41 virtual void Fill(bool on) = 0;
42
49 virtual void DrawPixel(uint_fast8_t x, uint_fast8_t y, bool on) = 0;
50
59 virtual void DrawLine(uint_fast8_t x1,
60 uint_fast8_t y1,
61 uint_fast8_t x2,
62 uint_fast8_t y2,
63 bool on)
64 = 0;
65
75 virtual void DrawRect(uint_fast8_t x1,
76 uint_fast8_t y1,
77 uint_fast8_t x2,
78 uint_fast8_t y2,
79 bool on,
80 bool fill = false)
81 = 0;
82
89 void DrawRect(const Rectangle& rect, bool on, bool fill = false)
90 {
91 DrawRect(rect.GetX(),
92 rect.GetY(),
93 rect.GetRight(),
94 rect.GetBottom(),
95 on,
96 fill);
97 }
98
108 virtual void DrawArc(uint_fast8_t x,
109 uint_fast8_t y,
110 uint_fast8_t radius,
111 int_fast16_t start_angle,
112 int_fast16_t sweep,
113 bool on)
114 = 0;
115
123 void
124 DrawCircle(uint_fast8_t x, uint_fast8_t y, uint_fast8_t radius, bool on)
125 {
126 DrawArc(x, y, radius, 0, 360, on);
127 };
128
137 virtual char WriteChar(char ch, FontDef font, bool on) = 0;
138
148 virtual char WriteString(const char* str, FontDef font, bool on) = 0;
149
159 virtual Rectangle WriteStringAligned(const char* str,
160 const FontDef& font,
161 Rectangle boundingBox,
162 Alignment alignment,
163 bool on)
164 = 0;
165
171 void SetCursor(uint16_t x, uint16_t y)
172 {
173 currentX_ = (x >= Width()) ? Width() - 1 : x;
174 currentY_ = (y >= Height()) ? Height() - 1 : y;
175 }
176
181 virtual void Update() = 0;
182
186 virtual bool UpdateFinished() = 0;
187
188 protected:
189 uint16_t currentX_;
190 uint16_t currentY_;
191};
192
219template <class ChildType>
221{
222 public:
225
226 void DrawLine(uint_fast8_t x1,
227 uint_fast8_t y1,
228 uint_fast8_t x2,
229 uint_fast8_t y2,
230 bool on) override
231 {
232 int_fast16_t deltaX = abs((int_fast16_t)x2 - (int_fast16_t)x1);
233 int_fast16_t deltaY = abs((int_fast16_t)y2 - (int_fast16_t)y1);
234 int_fast16_t signX = ((x1 < x2) ? 1 : -1);
235 int_fast16_t signY = ((y1 < y2) ? 1 : -1);
236 int_fast16_t error = deltaX - deltaY;
237 int_fast16_t error2;
238
239 // If we write "ChildType::DrawPixel(x2, y2, on);", we end up with
240 // all sorts of weird compiler errors when the Child class is a template
241 // class. The only way around this is to use this very verbose syntax:
242 ((ChildType*)(this))->ChildType::DrawPixel(x2, y2, on);
243
244 while((x1 != x2) || (y1 != y2))
245 {
246 ((ChildType*)(this))->ChildType::DrawPixel(x1, y1, on);
247 error2 = error * 2;
248 if(error2 > -deltaY)
249 {
250 error -= deltaY;
251 x1 += signX;
252 }
253
254 if(error2 < deltaX)
255 {
256 error += deltaX;
257 y1 += signY;
258 }
259 }
260 }
261
262 void DrawRect(uint_fast8_t x1,
263 uint_fast8_t y1,
264 uint_fast8_t x2,
265 uint_fast8_t y2,
266 bool on,
267 bool fill = false) override
268 {
269 if(fill)
270 {
271 for(uint_fast8_t x = x1; x <= x2; x++)
272 {
273 for(uint_fast8_t y = y1; y <= y2; y++)
274 {
275 ((ChildType*)(this))->ChildType::DrawPixel(x, y, on);
276 }
277 }
278 }
279 else
280 {
281 ((ChildType*)(this))->ChildType::DrawLine(x1, y1, x2, y1, on);
282 ((ChildType*)(this))->ChildType::DrawLine(x2, y1, x2, y2, on);
283 ((ChildType*)(this))->ChildType::DrawLine(x2, y2, x1, y2, on);
284 ((ChildType*)(this))->ChildType::DrawLine(x1, y2, x1, y1, on);
285 }
286 }
287
288 void DrawArc(uint_fast8_t x,
289 uint_fast8_t y,
290 uint_fast8_t radius,
291 int_fast16_t start_angle,
292 int_fast16_t sweep,
293 bool on) override
294 {
295 // Values to calculate the circle
296 int_fast16_t t_x, t_y, err, e2;
297
298 // Temporary values to speed up comparisons
299 float t_sxy, t_syx, t_sxny, t_synx;
300 float t_exy, t_eyx, t_exny, t_eynx;
301
302 float start_angle_rad, end_angle_rad;
303 float start_x, start_y, end_x, end_y;
304
305 bool d1, d2, d3, d4;
306
307 d1 = d2 = d3 = d4 = true;
308
309 bool circle = false;
310
311 if(sweep < 0)
312 {
313 start_angle += sweep;
314 sweep = -sweep;
315 }
316
317 start_angle_rad = deg2rad(start_angle);
318 end_angle_rad = deg2rad(start_angle + sweep);
319
320 start_x = cos(start_angle_rad) * radius;
321 start_y = -sin(start_angle_rad) * radius;
322 end_x = cos(end_angle_rad) * radius;
323 end_y = -sin(end_angle_rad) * radius;
324
325 // Check if start and endpoint are very near
326 if((end_x - start_x) * (end_x - start_x)
327 + (end_y - start_y) * (end_y - start_y)
328 < 2.0f)
329 {
330 if(sweep > 180)
331 circle = true;
332 else
333 // Nothing to draw
334 return;
335 }
336
337 t_x = -radius;
338 t_y = 0;
339 err = 2 - 2 * radius;
340
341 do
342 {
343 if(!circle)
344 {
345 t_sxy = start_x * t_y;
346 t_syx = start_y * t_x;
347 t_sxny = start_x * -t_y;
348 t_synx = start_y * -t_x;
349 t_exy = end_x * t_y;
350 t_eyx = end_y * t_x;
351 t_exny = end_x * -t_y;
352 t_eynx = end_y * -t_x;
353
354 if(sweep > 180)
355 {
356 d1 = (t_sxy - t_synx < 0 || t_exy - t_eynx > 0);
357 d2 = (t_sxy - t_syx < 0 || t_exy - t_eyx > 0);
358 d3 = (t_sxny - t_syx < 0 || t_exny - t_eyx > 0);
359 d4 = (t_sxny - t_synx < 0 || t_exny - t_eynx > 0);
360 }
361 else
362 {
363 d1 = (t_sxy - t_synx < 0 && t_exy - t_eynx > 0);
364 d2 = (t_sxy - t_syx < 0 && t_exy - t_eyx > 0);
365 d3 = (t_sxny - t_syx < 0 && t_exny - t_eyx > 0);
366 d4 = (t_sxny - t_synx < 0 && t_exny - t_eynx > 0);
367 }
368 }
369
370 if(d1)
371 ((ChildType*)(this))
372 ->ChildType::DrawPixel(x - t_x, y + t_y, on);
373 if(d2)
374 ((ChildType*)(this))
375 ->ChildType::DrawPixel(x + t_x, y + t_y, on);
376 if(d3)
377 ((ChildType*)(this))
378 ->ChildType::DrawPixel(x + t_x, y - t_y, on);
379 if(d4)
380 ((ChildType*)(this))
381 ->ChildType::DrawPixel(x - t_x, y - t_y, on);
382
383 e2 = err;
384 if(e2 <= t_y)
385 {
386 t_y++;
387 err = err + (t_y * 2 + 1);
388 if(-t_x == t_y && e2 <= t_x)
389 {
390 e2 = 0;
391 }
392 }
393 if(e2 > t_x)
394 {
395 t_x++;
396 err = err + (t_x * 2 + 1);
397 }
398 } while(t_x <= 0);
399 }
400
401 char WriteChar(char ch, FontDef font, bool on) override
402 {
403 uint32_t i, b, j;
404
405 // Check if character is valid
406 if(ch < 32 || ch > 126)
407 return 0;
408
409 // Check remaining space on current line
410 if(Width() < (currentX_ + font.FontWidth)
411 || Height() < (currentY_ + font.FontHeight))
412 {
413 // Not enough space on current line
414 return 0;
415 }
416
417 // Use the font to write
418 for(i = 0; i < font.FontHeight; i++)
419 {
420 b = font.data[(ch - 32) * font.FontHeight + i];
421 for(j = 0; j < font.FontWidth; j++)
422 {
423 if((b << j) & 0x8000)
424 {
425 ((ChildType*)(this))
426 ->ChildType::DrawPixel(
427 currentX_ + j, (currentY_ + i), on);
428 }
429 else
430 {
431 ((ChildType*)(this))
432 ->ChildType::DrawPixel(
433 currentX_ + j, (currentY_ + i), !on);
434 }
435 }
436 }
437
438 // The current space is now taken
440
441 // Return written char for validation
442 return ch;
443 }
444
445 char WriteString(const char* str, FontDef font, bool on) override
446 {
447 // Write until null-byte
448 while(*str)
449 {
450 if(((ChildType*)(this))->ChildType::WriteChar(*str, font, on)
451 != *str)
452 {
453 // Char could not be written
454 return *str;
455 }
456
457 // Next char
458 str++;
459 }
460
461 // Everything ok
462 return *str;
463 }
464
466 const FontDef& font,
467 Rectangle boundingBox,
468 Alignment alignment,
469 bool on) override
470 {
471 const auto alignedRect
472 = GetTextRect(str, font).AlignedWithin(boundingBox, alignment);
473 SetCursor(alignedRect.GetX(), alignedRect.GetY());
474 ((ChildType*)(this))->ChildType::WriteString(str, font, on);
475 return alignedRect;
476 }
477
478 private:
479 uint32_t strlen(const char* string)
480 {
481 uint32_t result = 0;
482 while(*string++ != '\0')
483 result++;
484 return result;
485 }
486
487 Rectangle GetTextRect(const char* text, const FontDef& font)
488 {
489 const auto numChars = strlen(text);
490 return {int16_t(numChars * font.FontWidth), font.FontHeight};
491 }
492};
493
494} // namespace daisy
495
496#endif
Definition display.h:20
virtual void Fill(bool on)=0
virtual void DrawRect(uint_fast8_t x1, uint_fast8_t y1, uint_fast8_t x2, uint_fast8_t y2, bool on, bool fill=false)=0
uint16_t currentY_
Definition display.h:190
virtual void DrawLine(uint_fast8_t x1, uint_fast8_t y1, uint_fast8_t x2, uint_fast8_t y2, bool on)=0
virtual void DrawPixel(uint_fast8_t x, uint_fast8_t y, bool on)=0
virtual char WriteChar(char ch, FontDef font, bool on)=0
virtual uint16_t Width() const =0
void DrawRect(const Rectangle &rect, bool on, bool fill=false)
Definition display.h:89
Rectangle GetBounds() const
Definition display.h:28
virtual void DrawArc(uint_fast8_t x, uint_fast8_t y, uint_fast8_t radius, int_fast16_t start_angle, int_fast16_t sweep, bool on)=0
size_t CurrentY()
Definition display.h:35
virtual char WriteString(const char *str, FontDef font, bool on)=0
virtual uint16_t Height() const =0
size_t CurrentX()
Definition display.h:34
virtual Rectangle WriteStringAligned(const char *str, const FontDef &font, Rectangle boundingBox, Alignment alignment, bool on)=0
virtual ~OneBitGraphicsDisplay()
Definition display.h:23
void SetCursor(uint16_t x, uint16_t y)
Definition display.h:171
OneBitGraphicsDisplay()
Definition display.h:22
uint16_t currentX_
Definition display.h:189
virtual bool UpdateFinished()=0
void DrawCircle(uint_fast8_t x, uint_fast8_t y, uint_fast8_t radius, bool on)
Definition display.h:124
Definition display.h:221
char WriteString(const char *str, FontDef font, bool on) override
Definition display.h:445
char WriteChar(char ch, FontDef font, bool on) override
Definition display.h:401
OneBitGraphicsDisplayImpl()
Definition display.h:223
virtual ~OneBitGraphicsDisplayImpl()
Definition display.h:224
Rectangle WriteStringAligned(const char *str, const FontDef &font, Rectangle boundingBox, Alignment alignment, bool on) override
Definition display.h:465
void DrawLine(uint_fast8_t x1, uint_fast8_t y1, uint_fast8_t x2, uint_fast8_t y2, bool on) override
Definition display.h:226
void DrawArc(uint_fast8_t x, uint_fast8_t y, uint_fast8_t radius, int_fast16_t start_angle, int_fast16_t sweep, bool on) override
Definition display.h:288
void DrawRect(uint_fast8_t x1, uint_fast8_t y1, uint_fast8_t x2, uint_fast8_t y2, bool on, bool fill=false) override
Definition display.h:262
Definition graphics_common.h:22
int16_t GetY() const
Definition graphics_common.h:57
int16_t GetRight() const
Definition graphics_common.h:60
Rectangle AlignedWithin(const Rectangle &other, Alignment alignment) const
Definition graphics_common.h:209
int16_t GetBottom() const
Definition graphics_common.h:61
int16_t GetX() const
Definition graphics_common.h:56
#define deg2rad(deg)
Definition color_display.h:8
Hardware defines and helpers for daisy field platform.
Definition index.h:2
Alignment
Definition graphics_common.h:9
Definition oled_fonts.h:17
uint8_t FontHeight
Definition oled_fonts.h:19
const uint16_t * data
Definition oled_fonts.h:20
const uint8_t FontWidth
Definition oled_fonts.h:18