Topic created by Jean-Marc Zingg
Buffered_GFX and Buffered_GFX_Window are template classes that buffer monochrome text and graphics produced with Adafruit_GFX.
They to allow to write the buffer content in one go to the display.
The method "updateToTarget()" uses the fast update method of the target display library, where available: pushColor or writePixel.
Adaptation to the target library is done by "partial specialization" of the template classes. Such specializations can be added easily.
A demo and test example shows how to use it.
This source is "help yourself" software, comes without warranty and support.
Try it, to see if it's useful for you.
Template class Buffered_GFX:
// Buffered_GFX.h
//
// JZ 20.12.2016
//
// include target class header before this file, for specialization to take effect
//
// the purpose of this template class is to reduce flicker for text output.
// the call to updateToTarget() overwrites the TargetDisplay with the buffer content in one go.
//
// can be used with "Arduinos" with enough RAM, e.g. Arduino Due, ESP8266, STM32.
//
// w and h must correspond to the initial dimension of the TargetDisplay.
// by design, the buffered display and its content DO NOT rotate, if the TargetDisplay is rotated.
// applying rotation to the Buffered_GFX is effective only for content drawn to it afterwards.
//
// this is "help yourself software" : no warranty, no support,
// feel free to use, modify, improve, enhance, re-post etc.
#ifndef _Buffered_GFX_H_
#define _Buffered_GFX_H_
#ifndef _Buffered_GFX_Base_I_
#define _Buffered_GFX_Base_I_
#include <Adafruit_GFX.h>
// base class to provide common functionality and inheritance from Adafruit_GFX
// ****************************************************************************
class Buffered_GFX_Base : public Adafruit_GFX
{
protected:
uint16_t _width;
uint16_t _height;
uint16_t _textfgcolor, _textbgcolor;
uint32_t _elapsed;
uint8_t* _monochrome_buffer;
void printXY(const char* text, uint16_t x, uint16_t y, uint16_t x1, uint16_t y1)
{ // no printf in Print.h of package SAM
Serial.print(text);
Serial.print("(");
Serial.print(x);
Serial.print(",");
Serial.print(y);
Serial.print(",");
Serial.print(x1);
Serial.print(",");
Serial.print(y1);
Serial.println(")");
};
public:
Buffered_GFX_Base(uint16_t w, uint16_t h, uint8_t buffer[]) :
Adafruit_GFX(w, h),
_monochrome_buffer(buffer),
_width(w), _height(h)
{
_textfgcolor = 0xFFFF;
_textbgcolor = 0x0000;
_elapsed = 0;
fillBuffer(0x0000);
};
public:
virtual void drawPixel(int16_t x, int16_t y, uint16_t color)
{
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) return;
int16_t bx = x;
int16_t by = y;
switch (getRotation())
{
case 1:
bx = _width - y - 1;
by = x;
break;
case 2:
bx = _width - x - 1;
by = _height - y - 1;
break;
case 3:
bx = y;
by = _height - x - 1;
break;
}
uint32_t index = (bx + by * _width) / 8;
if (color == _textbgcolor)
{
_monochrome_buffer[index] &= ~(0x80 >> bx % 8);
}
else
{
_monochrome_buffer[index] |= (0x80 >> bx % 8);
}
};
void setTextColor(uint16_t color)
{
_textfgcolor = color;
};
void setTextColor(uint16_t fgcolor, uint16_t bgcolor)
{
_textfgcolor = fgcolor;
_textbgcolor = bgcolor;
};
void fillBuffer(uint16_t color)
{
for (uint32_t index = 0; index < _width * _height / 8; index++)
{
_monochrome_buffer[index] = ((color != _textbgcolor) ? 0xFF : 0x00);
}
};
uint32_t elapsed()
{
return _elapsed;
};
};
#endif // _Buffered_GFX_Base_I_
// template class for full screen buffering
// ****************************************
template<typename Target_t, uint16_t w, uint16_t h>
class Buffered_GFX : public Buffered_GFX_Base
{
private:
Target_t& TargetDisplay;
uint8_t _monochrome_buffer[w * h / 8];
public:
Buffered_GFX(Target_t& target) :
Buffered_GFX_Base(w, h, _monochrome_buffer),
TargetDisplay(target)
{};
// by (my) design, the general method of the template class is for TFT_HX8357_Due and "pushColor" and "setWindow"
void updateToTarget()
{
uint32_t start = micros();
// #ifdef _TFT_HX8357_DueH_ // "quick and dirty" solution
TargetDisplay.setWindow(0, 0, TargetDisplay.width() - 1, TargetDisplay.height() - 1); // my preferred name for the public method
// #else
// TargetDisplay.setAddrWindow(0, 0, TargetDisplay.width() - 1, TargetDisplay.height() - 1); // but most libraries use this name
// #endif
switch (TargetDisplay.getRotation())
{
case 0:
{ // is this faster ? yes, slighly
uint32_t limit = w * h / 8;
for (uint32_t index = 0; index < limit; index++)
{
uint8_t data = _monochrome_buffer[index];
for (uint8_t pixel = 0; pixel < 8; pixel++)
{
TargetDisplay.pushColor((data & 0x80) ? _textfgcolor : _textbgcolor);
data <<= 1;
}
}
}
break;
case 1:
for (int16_t x = w - 1; x >= 0; x--)
{
for (int16_t y = 0; y < h; y++)
{
TargetDisplay.pushColor(((_monochrome_buffer[(x + y * w) / 8]) & (0x80 >> x % 8)) ? _textfgcolor : _textbgcolor);
}
}
break;
case 2:
for (int16_t y = h - 1; y >= 0; y--)
{
for (int16_t x = w - 1; x >= 0; x--)
{
TargetDisplay.pushColor(((_monochrome_buffer[(x + y * w) / 8]) & (0x80 >> x % 8)) ? _textfgcolor : _textbgcolor);
}
}
break;
case 3:
for (int16_t x = 0; x < w; x++)
{
for (int16_t y = h - 1; y >= 0; y--)
{
TargetDisplay.pushColor(((_monochrome_buffer[(x + y * w) / 8]) & (0x80 >> x % 8)) ? _textfgcolor : _textbgcolor);
}
}
break;
}
_elapsed = micros() - start;
};
};
#endif // _Buffered_GFX_H_
Template class Buffered_GFX_Window:
Would exceed the allowed limit. See attached zipfile.
Template class specializations for Buffered_GFX:
Would exceed the allowed limit. See attached zipfile.
Buffered_GFX_V2.zip (10.7 KB)