LCDGFX LCD display driver  1.1.5
This library is developed to control SSD1306/SSD1325/SSD1327/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
tiler.h
Go to the documentation of this file.
1 /*
2  MIT License
3 
4  Copyright (c) 2018-2021, 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 */
28 #ifndef _NANO_ENGINE_TILER_H_
29 #define _NANO_ENGINE_TILER_H_
30 
31 #include "canvas/rect.h"
32 #include "canvas/canvas.h"
33 #include "v2/lcd/base/display.h"
34 
40 #ifndef NE_MAX_TILE_ROWS
41 #define NE_MAX_TILE_ROWS 20
42 #endif
43 
49 /* The table below defines arguments for NanoEngineTiler. *
50  * canvas bits */
51 // Tiles for monochrome displays
52 #define TILE_128x64_MONO NanoCanvas<128, 64, 1>
53 #define TILE_8x8_MONO NanoCanvas<8, 8, 1>
54 #define TILE_16x16_MONO NanoCanvas<16, 16, 1>
55 #define TILE_32x32_MONO NanoCanvas<32, 32, 1>
56 // Tiles for 4-bit displays
57 #define TILE_16x16_GRAY4 NanoCanvas<16, 16, 4>
58 // Tiles for 8-bit displays
59 #define TILE_8x8_RGB8 NanoCanvas<8, 8, 8>
60 #define TILE_16x16_RGB8 NanoCanvas<16, 16, 8>
61 #define TILE_32x32_RGB8 NanoCanvas<32, 32, 8>
62 #define TILE_8x8_MONO_8 NanoCanvas<8, 8, 1>
63 #define TILE_16x16_MONO_8 NanoCanvas<16, 16, 1>
64 // Tiles for 16-bit displays
65 #define TILE_8x8_RGB16 NanoCanvas<8, 8, 16>
66 #define TILE_16x16_RGB16 NanoCanvas<16, 16, 16>
67 // Adafruit tiles
68 #define ADATILE_8x8_MONO AdafruitCanvas1, 8, 8, 3
69 #define ADATILE_8x8_RGB8 AdafruitCanvas8, 8, 8, 3
70 #define ADATILE_8x8_RGB16 AdafruitCanvas16, 8, 8, 3
71 
72 
75 typedef bool (*TNanoEngineOnDraw)(void);
76 
77 template <class C, class D> class NanoEngine;
78 
79 template <class C, class D> class NanoEngineTiler;
80 
84 template <class T> class NanoEngineObject
85 {
86 public:
87  template <class C, class D> friend class NanoEngineTiler;
88 
89  NanoEngineObject() = default;
90 
95  virtual void draw() = 0;
96 
101  virtual void update() = 0;
102 
107  virtual void refresh() = 0;
108 
112  void focus()
113  {
114  m_focused = true;
115  refresh();
116  }
117 
121  void defocus()
122  {
123  m_focused = false;
124  refresh();
125  }
126 
131  bool isFocused()
132  {
133  return m_focused;
134  }
135 
139  bool hasTiler()
140  {
141  return m_tiler != nullptr;
142  }
143 
148  T &getTiler()
149  {
150  return *(static_cast<T *>(m_tiler));
151  }
152 
153 protected:
154  T *m_tiler = nullptr;
156 
162  void setTiler(T *tiler)
163  {
164  m_tiler = tiler;
165  }
166 
167 private:
168  bool m_focused = false;
169 };
170 
180 template <class C, class D> class NanoEngineTiler
181 {
182 protected:
184  explicit NanoEngineTiler(D &display)
185  : m_display(display)
186  , m_onDraw(nullptr)
187  , offset{0, 0}
188  , m_first(nullptr)
189  {
190  refresh();
191  };
192 
193 public:
201  void refresh()
202  {
203  memset(m_refreshFlags, 0xFF, sizeof(m_refreshFlags));
204  }
205 
211  void refresh(const NanoRect &rect)
212  {
213  refresh(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
214  }
215 
220  void refresh(const NanoPoint &point) __attribute__((noinline))
221  {
222  if ( (point.x < 0) || (point.y < 0) || ((point.y / canvas.height()) >= NE_MAX_TILE_ROWS) )
223  return;
224  m_refreshFlags[(point.y / canvas.height())] |= (1 << (point.x / canvas.width()));
225  }
226 
231  void refresh(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
232  {
233  if ( y2 < 0 || x2 < 0 )
234  return;
235  if ( y1 < 0 )
236  y1 = 0;
237  if ( x1 < 0 )
238  x1 = 0;
239  y1 = y1 / canvas.height();
240  y2 = lcd_gfx_min((y2 / canvas.height()), NE_MAX_TILE_ROWS - 1);
241  for ( uint8_t x = x1 / canvas.width(); x <= (x2 / canvas.width()); x++ )
242  {
243  for ( uint8_t y = y1; y <= y2; y++ )
244  {
245  m_refreshFlags[y] |= (1 << x);
246  }
247  }
248  }
249 
255  void refreshWorld(const NanoRect &rect)
256  {
257  refreshWorld(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
258  }
259 
265  void refreshWorld(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
266  {
267  refresh(x1 - offset.x, y1 - offset.y, x2 - offset.x, y2 - offset.y);
268  }
269 
274  void refreshWorld(const NanoPoint &point)
275  {
276  refresh(point - offset);
277  }
278 
285  {
286  canvas.offset -= offset;
287  }
288 
295  {
296  canvas.offset += offset;
297  }
298 
302  void moveTo(const NanoPoint &position)
303  {
304  offset = position;
305  }
306 
311  void moveToAndRefresh(const NanoPoint &position)
312  {
313  moveTo(position);
314  refresh();
315  }
316 
320  const NanoPoint &getPosition() const
321  {
322  return offset;
323  }
324 
342  {
343  m_onDraw = callback;
344  }
345 
353  bool collision(const NanoPoint &p, const NanoRect &rect)
354  {
355  return rect.collision(p);
356  }
357 
364  void insert(NanoEngineObject<TilerT> &object) __attribute__((noinline))
365  {
366  object.m_next = this->m_first;
367  object.setTiler(this);
368  m_first = &object;
369  object.refresh();
370  }
371 
379  void remove(NanoEngineObject<TilerT> &object) __attribute__((noinline))
380  {
381  if ( this->m_first == nullptr )
382  {
383  }
384  else if ( &object == m_first )
385  {
386  object.refresh();
387  this->m_first = object.m_next;
388  object.m_next = nullptr;
389  object.m_tiler = nullptr;
390  }
391  else
392  {
393  NanoEngineObject<TilerT> *p = this->m_first;
394  while ( p->m_next )
395  {
396  if ( p->m_next == &object )
397  {
398  object.refresh();
399  p->m_next = object.m_next;
400  object.m_next = nullptr;
401  object.m_tiler = nullptr;
402  break;
403  }
404  p = p->m_next;
405  }
406  }
407  }
408 
412  void update() __attribute__((noinline))
413  {
414  NanoEngineObject<TilerT> *p = m_first;
415  while ( p )
416  {
417  p->update();
418  p = p->m_next;
419  }
420  }
421 
426  {
427  return canvas;
428  }
429 
434  {
435  return m_display;
436  }
437 
438 protected:
443 
446 
451  uint16_t m_refreshFlags[NE_MAX_TILE_ROWS];
452 
459  void displayBuffer() __attribute__((noinline));
460 
466  void displayPopup(const char *msg);
467 
468 private:
470  C canvas;
471 
472  NanoPoint offset;
473 
474  NanoEngineObject<TilerT> *m_first = nullptr;
475 
476  void draw() __attribute__((noinline))
477  {
478  NanoEngineObject<TilerT> *p = m_first;
479  while ( p )
480  {
481  p->draw();
482  p = p->m_next;
483  }
484  }
485 };
486 
487 template <class C, class D> void NanoEngineTiler<C, D>::displayBuffer()
488 {
489  // printf("--------------\n");
490  for ( lcduint_t y = 0; y < m_display.height(); y = y + canvas.height() )
491  {
492  uint16_t flag = m_refreshFlags[y / canvas.height()];
493  m_refreshFlags[y / canvas.height()] = 0;
494  // printf("|%d%d%d%d%d%d%d%d|\n", flag & 1, (flag >> 1) & 1, (flag >> 2) & 1, (flag >> 3) & 1, (flag >>
495  // 4) & 1, (flag >> 5) & 1,(flag >> 6) & 1,(flag >> 7) & 1 );
496  for ( lcduint_t x = 0; x < m_display.width(); x = x + canvas.width() )
497  {
498  if ( flag & 0x01 )
499  {
500  canvas.setOffset(x + offset.x, y + offset.y);
501  if ( m_onDraw == nullptr )
502  {
503  canvas.clear();
504  draw();
505  this->m_display.drawCanvas(x, y, canvas);
506  }
507  else if ( m_onDraw() )
508  {
509  draw();
510  this->m_display.drawCanvas(x, y, canvas);
511  }
512  }
513  flag >>= 1;
514  }
515  }
516 }
517 
518 template <class C, class D> void NanoEngineTiler<C, D>::displayPopup(const char *msg)
519 {
520  lcduint_t height = 0;
521  lcduint_t width = m_display.getFont().getTextSize(msg, &height);
522  NanoRect rect = {
523  {((m_display.width() - (lcdint_t)width) >> 1) - 8, ((m_display.height() - (lcdint_t)height) >> 1) - 4},
524  {((m_display.width() + (lcdint_t)width) >> 1) + 8, ((m_display.height() + (lcdint_t)height) >> 1) + 4}};
525  // TODO: It would be nice to calculate message height
526  NanoPoint textPos = {(m_display.width() - (lcdint_t)width) >> 1, (m_display.height() - height) >> 1};
527  refresh(rect);
528  for ( lcduint_t y = 0; y < m_display.height(); y = y + canvas.height() )
529  {
530  uint16_t flag = m_refreshFlags[y / canvas.height()];
531  m_refreshFlags[y / canvas.height()] = 0;
532  for ( lcduint_t x = 0; x < m_display.width(); x = x + canvas.width() )
533  {
534  if ( flag & 0x01 )
535  {
536  canvas.setOffset(x + offset.x, y + offset.y);
537  if ( !m_onDraw )
538  {
539  canvas.clear();
540  draw();
541  }
542  else if ( m_onDraw() )
543  {
544  draw();
545  }
546  canvas.setOffset(x, y);
547  canvas.setColor(RGB_COLOR8(0, 0, 0));
548  canvas.fillRect(rect);
549  canvas.setColor(RGB_COLOR8(192, 192, 192));
550  canvas.drawRect(rect);
551  canvas.printFixed(textPos.x, textPos.y, msg);
552 
553  m_display.drawCanvas(x, y, canvas);
554  }
555  flag >>= 1;
556  }
557  }
558 }
559 
564 #endif
NanoEngineTiler< C, D > TilerT
Definition: tiler.h:191
const NanoPoint & getPosition() const
Definition: tiler.h:320
void moveToAndRefresh(const NanoPoint &position)
Definition: tiler.h:311
uint8_t lcduint_t
Definition: canvas_types.h:79
bool collision(const NanoPoint &p, const NanoRect &rect)
Returns true if point is inside the rectangle area. Returns true if point is inside the rectangle are...
Definition: tiler.h:353
T * m_tiler
Active tiler, assigned to the NanoEngineObject.
Definition: tiler.h:154
void defocus()
Definition: tiler.h:121
void displayBuffer() __attribute__((noinline))
refreshes content on oled display. Refreshes content on oled display. Call it, if you want to update ...
Definition: tiler.h:487
Definition: rect.h:42
void update() __attribute__((noinline))
Definition: tiler.h:412
NanoPoint p2
Definition: rect.h:48
virtual void refresh()=0
int8_t lcdint_t
Definition: canvas_types.h:77
void insert(NanoEngineObject< TilerT > &object) __attribute__((noinline))
Definition: tiler.h:364
C & getCanvas()
Definition: tiler.h:425
void focus()
Definition: tiler.h:112
lcdint_t y
Definition: point.h:44
void refresh(const NanoPoint &point) __attribute__((noinline))
Definition: tiler.h:220
bool collision(const NanoPoint &p) const
Definition: rect.h:161
virtual void draw()=0
void moveTo(const NanoPoint &position)
Definition: tiler.h:302
void displayPopup(const char *msg)
prints popup message over display content prints popup message over display content ...
Definition: tiler.h:518
void refresh()
Definition: tiler.h:201
void refresh(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
Definition: tiler.h:231
void worldCoordinates()
Definition: tiler.h:294
bool hasTiler()
Definition: tiler.h:139
#define NE_MAX_TILE_ROWS
Maximum tile rows supported. Can be defined outside the library.
Definition: tiler.h:41
T & getTiler()
Definition: tiler.h:148
#define lcd_gfx_min(a, b)
void refreshWorld(const NanoRect &rect)
Definition: tiler.h:255
void refreshWorld(const NanoPoint &point)
Definition: tiler.h:274
void setTiler(T *tiler)
Definition: tiler.h:162
void refreshWorld(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
Definition: tiler.h:265
void refresh(const NanoRect &rect)
Definition: tiler.h:211
virtual void update()=0
NanoEngineObject< T > * m_next
Next NanoEngineObject in the list.
Definition: tiler.h:155
D & m_display
Definition: tiler.h:442
#define RGB_COLOR8(r, g, b)
Definition: canvas_types.h:52
NanoPoint p1
Definition: rect.h:45
lcdint_t x
Definition: point.h:42
void drawCallback(TNanoEngineOnDraw callback)
Definition: tiler.h:341
D & getDisplay()
Definition: tiler.h:433
bool isFocused()
Definition: tiler.h:131
void localCoordinates()
Definition: tiler.h:284
bool(* TNanoEngineOnDraw)(void)
Definition: tiler.h:75
NanoEngineTiler(D &display)
Definition: tiler.h:184
TNanoEngineOnDraw m_onDraw
Definition: tiler.h:445