added color maps and examples

This commit is contained in:
kamorris
2020-01-24 22:07:45 -08:00
parent 04eacf56c9
commit e019b6dcf6
7 changed files with 947 additions and 37 deletions
+245 -5
View File
@@ -36,6 +36,8 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
_xpivot = 0;
_ypivot = 0;
_colorMap = nullptr;
this->cursor_y = this->cursor_x = 0; // Text cursor position
}
@@ -55,6 +57,8 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
_iwidth = _dwidth = _bitwidth = w;
_iheight = _dheight = h;
_colorMap = nullptr;
this->cursor_x = 0;
this->cursor_y = 0;
@@ -72,6 +76,7 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
_img8_1 = _img8;
_img8_2 = _img8;
_img = (uint16_t*) _img8;
_img4 = _img8;
// This is to make it clear what pointer size is expected to be used
// but casting in the user sketch is needed due to the use of void*
@@ -132,6 +137,17 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
ptr8 = ( uint8_t*) calloc(w * h + 1, sizeof(uint8_t));
}
else if (_bpp == 4)
{
w = (w+1) & 0xFFFE; // width needs to be multiple of 2, with an extra "off screen" pixel
_iwidth = w;
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
if ( psramFound() ) ptr8 = ( uint8_t*) ps_calloc(((w * h) >> 1) + 1, sizeof(uint8_t));
else
#endif
ptr8 = ( uint8_t*) calloc(((w * h) >> 1) + 1, sizeof(uint8_t));
}
else // Must be 1 bpp
{
//_dwidth Display width+height in pixels always in rotation 0 orientation
@@ -154,6 +170,28 @@ void* TFT_eSprite::callocSprite(int16_t w, int16_t h, uint8_t frames)
return ptr8;
}
/***************************************************************************************
** Function name: setColorMap
** Description: Set a colour map for a 4-bit per pixel sprite
*************************************************************************************x*/
void TFT_eSprite::setColorMap(uint16_t colorMap[], int colors)
{
if (_colorMap != nullptr)
{
free(_colorMap);
}
// allocate color map
_colorMap = (uint16_t *)calloc(16, sizeof(uint16_t));
if (colors > 16)
colors = 16;
for (auto i = 0; i < colors; i++)
{
_colorMap[i] = colorMap[i];
}
}
/***************************************************************************************
** Function name: frameBuffer
** Description: For 1 bpp Sprites, select the frame used for graphics
@@ -167,6 +205,8 @@ void* TFT_eSprite::frameBuffer(int8_t f)
if (_bpp == 8) return _img8;
if (_bpp == 4) return _img4;
if ( f == 2 ) _img8 = _img8_2;
else _img8 = _img8_1;
@@ -185,7 +225,8 @@ void* TFT_eSprite::setColorDepth(int8_t b)
// Now define the new colour depth
if ( b > 8 ) _bpp = 16; // Bytes per pixel
else if ( b > 1 ) _bpp = 8;
else if ( b > 4 ) _bpp = 8;
else if ( b > 1 ) _bpp = 4;
else _bpp = 1;
// If it existed, re-create the sprite with the new colour depth
@@ -231,6 +272,11 @@ void TFT_eSprite::deleteSprite(void)
{
if (!_created ) return;
if (_colorMap != nullptr)
{
free(_colorMap);
}
free(_img8_1);
_created = false;
@@ -667,6 +713,13 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y)
_tft->pushImage(x, y, _iwidth, _iheight, _img );
_tft->setSwapBytes(oldSwapBytes);
}
else if (_bpp == 4)
{
if (_colorMap == nullptr) {
return;
}
_tft->pushImage(x, y, _dwidth, _dheight, _img4, false, _colorMap);
}
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8));
}
@@ -692,10 +745,33 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp)
transp = (uint8_t)((transp & 0xE000)>>8 | (transp & 0x0700)>>6 | (transp & 0x0018)>>3);
_tft->pushImage(x, y, _dwidth, _dheight, _img8, (uint8_t)transp, (bool)true);
}
else if (_bpp == 4)
{
_tft->pushImage(x, y, _dwidth, _dheight, _img4, (uint8_t)(transp & 0x0F), false, _colorMap);
}
else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false);
}
/***************************************************************************************
** Function name: cmapPixel
** Description: Read the color map index of a pixel at defined coordinates
*************************************************************************************x*/
uint8_t TFT_eSprite::cmapPixel(int32_t x, int32_t y)
{
if ((x < 0) || (x >= _iwidth) || (y < 0) || (y >= _iheight) || !_created) return 0xFFFF;
if (_bpp == 4)
{
uint16_t color;
if ((x & 0x01) == 0)
return ((_img4[((x+y*_iwidth)>>1)] & 0xF0) >> 4) & 0x0F; // even index = bits 7 .. 4
else
return _img4[((x-1+y*_iwidth)>>1)] & 0x0F; // odd index = bits 3 .. 0.
}
return 0;
}
/***************************************************************************************
** Function name: readPixel
** Description: Read 565 colour of a pixel at defined coordinates
@@ -723,6 +799,16 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y)
return color;
}
if (_bpp == 4)
{
uint16_t color;
if ((x & 0x01) == 0)
color = _colorMap[((_img4[((x+y*_iwidth)>>1)] & 0xF0) >> 4) & 0x0F ]; // even index = bits 7 .. 4
else
color = _colorMap[_img4[((x-1+y*_iwidth)>>1)] & 0x0F]; // odd index = bits 3 .. 0.
return color;
}
if (_rotation == 1)
{
uint16_t tx = x;
@@ -802,6 +888,13 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
ys++;
}
}
else if (_bpp == 4)
{
// not supported. The image is unlikely to have the correct colors for the color map.
// we could implement a way to push a 4-bit image using the color map?
Serial.println("pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) not implemented");
return;
}
else // 1bpp
{
@@ -900,6 +993,12 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u
}
}
else if (_bpp == 4)
{
Serial.println("TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) not implemented");
return;
}
else // 1bpp
{
// Move coordinate rotation to support fn
@@ -1007,6 +1106,17 @@ void TFT_eSprite::pushColor(uint32_t color)
else if (_bpp == 8)
_img8[_xptr + _yptr * _iwidth] = (uint8_t )((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
else if (_bpp == 4)
{
uint8_t c = (uint8_t)color & 0x0F;
if ((_xptr & 0x01) == 0) {
_img4[(_xptr + _yptr * _iwidth)>>1] = ((c << 4) & 0xF0) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4
}
else {
_img4[(_xptr - 1 + _yptr * _iwidth)>>1] = (_img4[(_xptr - 1 + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits
}
}
else drawPixel(_xptr, _yptr, color);
@@ -1040,7 +1150,7 @@ void TFT_eSprite::pushColor(uint32_t color, uint16_t len)
else if (_bpp == 8)
pixelColor = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
else pixelColor = (uint16_t) color; // for 1bpp
else pixelColor = (uint16_t) color; // for 1bpp or 4bpp
while(len--) writeColor(pixelColor);
}
@@ -1060,6 +1170,15 @@ void TFT_eSprite::writeColor(uint16_t color)
// Write 8 bit RGB 332 encoded colour to RAM
else if (_bpp == 8) _img8[_xptr + _yptr * _iwidth] = (uint8_t) color;
else if (_bpp == 4)
{
uint8_t c = (uint8_t)color & 0x0F;
if ((_xptr & 0x01) == 0)
_img4[(_xptr + _yptr * _iwidth)>>1] = ((c << 4) & 0xF0) | (_img4[(_xptr + _yptr * _iwidth)>>1] & 0x0F); // new color is in bits 7 .. 4
else
_img4[(_xptr - 1 + _yptr * _iwidth)>>1] = (_img4[(_xptr - 1 + _yptr * _iwidth)>>1] & 0xF0) | c; // new color is the low bits (x is odd)
}
else drawPixel(_xptr, _yptr, color);
// Increment x
@@ -1159,7 +1278,22 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
fyp += iw;
}
}
else if (_bpp == 1)
else if (_bpp == 4)
{
// could optimize for scrolling by even # pixels using memove (later)
if (dx > 0) { tx += w; fx += w; } // Start from right edge
while (h--)
{ // move pixels one by one
for (uint16_t xp = 0; xp < w; xp++)
{
if (dx <= 0) drawPixel(tx + xp, ty, cmapPixel(fx + xp, fy));
if (dx > 0) drawPixel(tx - xp, ty, cmapPixel(fx - xp, fy));
}
if (dy <= 0) { ty++; fy++; }
else { ty--; fy--; }
}
}
else if (_bpp == 1 )
{
if (dx > 0) { tx += w; fx += w; } // Start from right edge
while (h--)
@@ -1173,7 +1307,7 @@ void TFT_eSprite::scroll(int16_t dx, int16_t dy)
else { ty--; fy--; }
}
}
else return; // Not 1, 8 or 16 bpp
else return; // Not 1, 4, 8 or 16 bpp
// Fill the gap left by the scrolling
if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor);
@@ -1199,6 +1333,11 @@ void TFT_eSprite::fillSprite(uint32_t color)
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
memset(_img8, (uint8_t)color, _iwidth * _iheight);
}
else if (_bpp == 4)
{
uint8_t c = ((color & 0x0F) | (((color & 0x0F) << 4) & 0xF0));
memset(_img4, c, (_iwidth * _iheight) >> 1);
}
else if (_bpp == 1)
{
if(color) memset(_img8, 0xFF, (_iwidth>>3) * _iheight + 1);
@@ -1301,6 +1440,19 @@ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color)
{
_img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3);
}
else if (_bpp == 4)
{
uint8_t c = color & 0x0F;
int index = 0;
if ((x & 0x01) == 0) {
index = (x+y*_iwidth)>>1;
_img4[index] = (uint8_t)(((c << 4) & 0xF0) | (_img4[index] & 0x0F));
}
else {
index = (x-1+y*_iwidth)>>1;
_img4[index] = (uint8_t)(c | (_img4[index] & 0xF0));
}
}
else // 1 bpp
{
if (_rotation == 1)
@@ -1409,6 +1561,24 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
while (h--) _img8[x + _iwidth * y++] = (uint8_t) color;
}
else if (_bpp == 4)
{
if ((x & 0x01) == 0)
{
uint8_t c = (uint8_t) (color & 0xF) << 4;
while (h--) {
_img4[(x + _iwidth * y)>>1] = (uint8_t) (c | _img4[(x + _iwidth * y)>>1] & 0x0F);
y++;
}
}
else {
uint8_t c = (uint8_t)color & 0xF;
while (h--) {
_img4[(x - 1 + _iwidth * y)>>1] = (uint8_t) (c | _img4[(x - 1 + _iwidth * y)>>1] & 0xF0); // x is odd; new color goes into the low bits.
y++;
}
}
}
else
{
while (h--)
@@ -1445,8 +1615,28 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3;
memset(_img8+_iwidth * y + x, (uint8_t)color, w);
}
else
else if (_bpp == 4)
{
uint8_t c = (uint8_t)color & 0x0F;
uint8_t c2 = (c | ((c << 4) & 0xF0));
if ((x & 0x01) == 1)
{
drawPixel(x, y, color);
x++; w--;
if (w < 1)
return;
}
if (((w + x) & 0x01) == 1)
{
// handle the extra one at the other end
drawPixel(x + w - 1, y, color);
w--;
if (w < 1) return;
}
memset(_img4 + ((_iwidth * y + x) >> 1), c2, (w >> 1));
}
else {
while (w--)
{
drawPixel(x, y, color);
@@ -1498,6 +1688,56 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
yp += _iwidth;
}
}
else if (_bpp == 4)
{
uint8_t c1 = (uint8_t)color & 0x0F;
uint8_t c2 = c1 | ((c1 << 4) & 0xF0);
if ((x & 0x01) == 0 && (w & 0x01) == 0)
{
yp = (yp >> 1);
while (h--)
{
memset(_img4 + yp, c2, (w>>1));
yp += (_iwidth >> 1);
}
}
else if ((x & 0x01) == 0)
{
// same as above but you have a hangover on the right.
yp = (yp >> 1);
while (h--)
{
if (w > 1)
memset(_img4 + yp, c2, (w-1)>>1);
// handle the rightmost pixel by calling drawPixel
drawPixel(x+w-1, y+h, c1);
yp += (_iwidth >> 1);
}
}
else if ((w & 0x01) == 1)
{
yp = (yp + 1) >> 1;
while (h--) {
drawPixel(x, y+h-1, color & 0x0F);
if (w > 1)
memset(_img4 + (yp + ((x-1)>>1)), c2, (w-1)>>1);
// same as above but you have a hangover on the left instead
yp += (_iwidth >> 1);
}
}
else
{
yp = (yp + 1) >> 1;
while (h--) {
drawPixel(x, y+h-1, color & 0x0F);
drawPixel(x+w-1, y+h-1, color & 0x0F);
if (w > 2)
memset(_img4 + (yp + ((x-1)>>1)), c2, (w-2)>>1);
// maximal hacking, single pixels on left and right.
yp += (_iwidth >> 1);
}
}
}
else
{
while (h--)