LCDGFX LCD display driver  1.0.2
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-2019, 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>
78 class NanoEngine;
79 
80 template<class C, class D>
82 
86 template<class T>
88 {
89 public:
90  template<class C, class D>
91  friend class NanoEngineTiler;
92 
97  virtual void draw() = 0;
98 
103  virtual void update() = 0;
104 
109  virtual void refresh() = 0;
110 
114  void focus()
115  {
116  m_focused = true;
117  refresh();
118  }
119 
123  void defocus()
124  {
125  m_focused = false;
126  refresh();
127  }
128 
133  bool isFocused()
134  {
135  return m_focused;
136  }
137 
141  bool hasTiler() { return m_tiler != nullptr; }
142 
147  T &getTiler() { return *(static_cast<T *>(m_tiler)); }
148 
149 protected:
150  T *m_tiler = nullptr;
152 
158  void setTiler(T *tiler) { m_tiler = tiler; }
159 
160 private:
161  bool m_focused;
162 };
163 
173 template<class C, class D>
174 class NanoEngineTiler
175 {
176 protected:
178  NanoEngineTiler(D &display):
179  m_display( display ),
180  m_onDraw(nullptr),
181  offset{0, 0}
182  {
183  refresh();
184  };
185 
186 public:
194  void refresh()
195  {
196  memset(m_refreshFlags,0xFF,sizeof(m_refreshFlags));
197  }
198 
204  void refresh(const NanoRect &rect)
205  {
206  refresh(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
207  }
208 
213  void refresh(const NanoPoint &point) __attribute__ ((noinline))
214  {
215  if ((point.x<0)||(point.y<0) || ((point.y/canvas.height())>=NE_MAX_TILE_ROWS)) return;
216  m_refreshFlags[(point.y/canvas.height())] |= (1<<(point.x/canvas.width()));
217  }
218 
223  void refresh(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__ ((noinline))
224  {
225  if (y2 < 0 || x2 < 0) return;
226  if (y1 < 0) y1 = 0;
227  if (x1 < 0) x1 = 0;
228  y1 = y1/canvas.height();
229  y2 = min((y2/canvas.height()), NE_MAX_TILE_ROWS - 1);
230  for(uint8_t x=x1/canvas.width(); x<=(x2/canvas.width()); x++)
231  {
232  for (uint8_t y=y1; y<=y2; y++)
233  {
234  m_refreshFlags[y] |= (1<<x);
235  }
236  }
237  }
238 
244  void refreshWorld(const NanoRect &rect)
245  {
246  refreshWorld(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
247  }
248 
254  void refreshWorld(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__ ((noinline))
255  {
256  refresh(x1 - offset.x, y1 - offset.y, x2 - offset.x, y2 - offset.y);
257  }
258 
263  void refreshWorld(const NanoPoint &point)
264  {
265  refresh( point - offset );
266  }
267 
274  {
275  canvas.offset -= offset;
276  }
277 
284  {
285  canvas.offset += offset;
286  }
287 
291  void moveTo(const NanoPoint & position)
292  {
293  offset = position;
294  }
295 
300  void moveToAndRefresh(const NanoPoint & position)
301  {
302  moveTo(position);
303  refresh();
304  }
305 
309  const NanoPoint & getPosition() const
310  {
311  return offset;
312  }
313 
331  {
332  m_onDraw = callback;
333  }
334 
342  bool collision(NanoPoint &p, NanoRect &rect) { return rect.collision( p ); }
343 
350  void insert(NanoEngineObject<TilerT> &object) __attribute__ ((noinline))
351  {
352  object.m_next = this->m_first;
353  object.setTiler( this );
354  m_first = &object;
355  object.refresh();
356  }
357 
365  void remove(NanoEngineObject<TilerT> &object) __attribute__ ((noinline))
366  {
367  if ( this->m_first == nullptr )
368  {
369  }
370  else if ( &object == m_first )
371  {
372  object.refresh();
373  this->m_first = object.m_next;
374  object.m_next = nullptr;
375  object.m_tiler = nullptr;
376  }
377  else
378  {
379  NanoEngineObject<TilerT> *p = this->m_first;
380  while ( p->m_next )
381  {
382  if ( p->m_next == &object )
383  {
384  object.refresh();
385  p->m_next = object.m_next;
386  object.m_next = nullptr;
387  object.m_tiler = nullptr;
388  break;
389  }
390  p = p->m_next;
391  }
392  }
393  }
394 
398  void update() __attribute__ ((noinline))
399  {
400  NanoEngineObject<TilerT> *p = m_first;
401  while (p)
402  {
403  p->update();
404  p = p->m_next;
405  }
406  }
407 
411  C& getCanvas() { return canvas; }
412 
416  D& getDisplay() { return m_display; }
417 
418 protected:
423 
426 
431  uint16_t m_refreshFlags[NE_MAX_TILE_ROWS];
432 
439  void displayBuffer() __attribute__ ((noinline));
440 
446  void displayPopup(const char *msg);
447 
448 private:
450  C canvas;
451 
452  NanoPoint offset;
453 
454  NanoEngineObject<TilerT> *m_first;
455 
456  void draw() __attribute__ ((noinline))
457  {
458  NanoEngineObject<TilerT> *p = m_first;
459  while (p)
460  {
461  p->draw();
462  p = p->m_next;
463  }
464  }
465 };
466 
467 template<class C, class D>
469 {
470 // printf("--------------\n");
471  for (lcduint_t y = 0; y < m_display.height(); y = y + canvas.height())
472  {
473  uint16_t flag = m_refreshFlags[y/canvas.height()];
474  m_refreshFlags[y/canvas.height()] = 0;
475 // printf("|%d%d%d%d%d%d%d%d|\n", flag & 1, (flag >> 1) & 1, (flag >> 2) & 1, (flag >> 3) & 1, (flag >> 4) & 1, (flag >> 5) & 1,(flag >> 6) & 1,(flag >> 7) & 1 );
476  for (lcduint_t x = 0; x < m_display.width(); x = x + canvas.width())
477  {
478  if (flag & 0x01)
479  {
480  canvas.setOffset(x + offset.x, y + offset.y);
481  if ( m_onDraw == nullptr )
482  {
483  canvas.clear();
484  draw();
485  this->m_display.drawCanvas(x,y,canvas);
486  }
487  else if ( m_onDraw() )
488  {
489  draw();
490  this->m_display.drawCanvas(x,y,canvas);
491  }
492  }
493  flag >>=1;
494  }
495  }
496 }
497 
498 template<class C, class D>
500 {
501  NanoRect rect = { {8, (m_display.height()>>1) - 8}, {m_display.width() - 8, (m_display.height()>>1) + 8} };
502  // TODO: It would be nice to calculate message height
503  NanoPoint textPos = { (m_display.width() - (lcdint_t)strlen(msg)*m_display.getFont().getHeader().width) >> 1,
504  (m_display.height()>>1) - 4 };
505  refresh(rect);
506  for (lcduint_t y = 0; y < m_display.height(); y = y + canvas.height())
507  {
508  uint16_t flag = m_refreshFlags[y/canvas.height()];
509  m_refreshFlags[y/canvas.height()] = 0;
510  for (lcduint_t x = 0; x < m_display.width(); x = x + canvas.width())
511  {
512  if (flag & 0x01)
513  {
514  canvas.setOffset(x + offset.x, y + offset.y);
515  if (!m_onDraw)
516  {
517  canvas.clear();
518  draw();
519  }
520  else if (m_onDraw())
521  {
522  draw();
523  }
524  canvas.setOffset(x, y);
525  canvas.setColor(RGB_COLOR8(0,0,0));
526  canvas.fillRect(rect);
527  canvas.setColor(RGB_COLOR8(192,192,192));
528  canvas.drawRect(rect);
529  canvas.printFixed( textPos.x, textPos.y, msg);
530 
531  m_display.drawCanvas(x,y,canvas);
532  }
533  flag >>=1;
534  }
535  }
536 }
537 
542 #endif
543 
const NanoPoint & getPosition() const
Definition: tiler.h:309
void moveToAndRefresh(const NanoPoint &position)
Definition: tiler.h:300
uint8_t lcduint_t
Definition: canvas_types.h:81
T * m_tiler
Active tiler, assigned to the NanoEngineObject.
Definition: tiler.h:150
void defocus()
Definition: tiler.h:123
void displayBuffer() __attribute__((noinline))
refreshes content on oled display. Refreshes content on oled display. Call it, if you want to update ...
Definition: tiler.h:468
Definition: rect.h:42
void update() __attribute__((noinline))
Definition: tiler.h:398
NanoPoint p2
Definition: rect.h:48
virtual void refresh()=0
int8_t lcdint_t
Definition: canvas_types.h:79
void insert(NanoEngineObject< TilerT > &object) __attribute__((noinline))
Definition: tiler.h:350
C & getCanvas()
Definition: tiler.h:411
void focus()
Definition: tiler.h:114
lcdint_t y
Definition: point.h:45
void refresh(const NanoPoint &point) __attribute__((noinline))
Definition: tiler.h:213
bool collision(const NanoPoint &p) const
Definition: rect.h:143
virtual void draw()=0
void moveTo(const NanoPoint &position)
Definition: tiler.h:291
void displayPopup(const char *msg)
prints popup message over display content prints popup message over display content ...
Definition: tiler.h:499
void refresh()
Definition: tiler.h:194
void refresh(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
Definition: tiler.h:223
bool collision(NanoPoint &p, NanoRect &rect)
Returns true if point is inside the rectangle area. Returns true if point is inside the rectangle are...
Definition: tiler.h:342
void worldCoordinates()
Definition: tiler.h:283
bool hasTiler()
Definition: tiler.h:141
#define NE_MAX_TILE_ROWS
Maximum tile rows supported. Can be defined outside the library.
Definition: tiler.h:41
T & getTiler()
Definition: tiler.h:147
void refreshWorld(const NanoRect &rect)
Definition: tiler.h:244
void refreshWorld(const NanoPoint &point)
Definition: tiler.h:263
void setTiler(T *tiler)
Definition: tiler.h:158
void refreshWorld(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2) __attribute__((noinline))
Definition: tiler.h:254
void refresh(const NanoRect &rect)
Definition: tiler.h:204
virtual void update()=0
NanoEngineTiler< C, D > TilerT
Definition: tiler.h:184
lcdint_t width() const
Definition: rect.h:51
NanoEngineObject< T > * m_next
Next NanoEngineObject in the list.
Definition: tiler.h:151
D & m_display
Definition: tiler.h:422
#define RGB_COLOR8(r, g, b)
Definition: canvas_types.h:52
#define min(a, b)
Definition: canvas_types.h:42
NanoPoint p1
Definition: rect.h:45
lcdint_t x
Definition: point.h:43
void drawCallback(TNanoEngineOnDraw callback)
Definition: tiler.h:330
D & getDisplay()
Definition: tiler.h:416
bool isFocused()
Definition: tiler.h:133
void localCoordinates()
Definition: tiler.h:273
bool(* TNanoEngineOnDraw)(void)
Definition: tiler.h:75
NanoEngineTiler(D &display)
Definition: tiler.h:178
TNanoEngineOnDraw m_onDraw
Definition: tiler.h:425