mirror of
https://github.com/thelastoutpostworkshop/ESP32ManyRoundScreenTest.git
synced 2025-09-26 23:09:22 +08:00
137 lines
3.8 KiB
C++
137 lines
3.8 KiB
C++
// GIFDraw is called by AnimatedGIF library frame to screen
|
|
|
|
#define DISPLAY_WIDTH tft.width()
|
|
#define DISPLAY_HEIGHT tft.height()
|
|
#define BUFFER_SIZE 256 // Optimum is >= GIF width or integral division of width
|
|
|
|
#ifdef USE_DMA
|
|
uint16_t usTemp[2][BUFFER_SIZE]; // Global to support DMA use
|
|
#else
|
|
uint16_t usTemp[1][BUFFER_SIZE]; // Global to support DMA use
|
|
#endif
|
|
bool dmaBuf = 0;
|
|
|
|
// Draw a line of image directly on the LCD
|
|
void GIFDraw(GIFDRAW *pDraw)
|
|
{
|
|
digitalWrite(CS_PINS[currentScreenIndex], LOW); // Select the display
|
|
tft.startWrite();
|
|
|
|
uint8_t *s;
|
|
uint16_t *d, *usPalette;
|
|
int x, y, iWidth, iCount;
|
|
|
|
// Displ;ay bounds chech and cropping
|
|
iWidth = pDraw->iWidth;
|
|
if (iWidth + pDraw->iX > DISPLAY_WIDTH)
|
|
iWidth = DISPLAY_WIDTH - pDraw->iX;
|
|
usPalette = pDraw->pPalette;
|
|
y = pDraw->iY + pDraw->y; // current line
|
|
if (y >= DISPLAY_HEIGHT || pDraw->iX >= DISPLAY_WIDTH || iWidth < 1)
|
|
return;
|
|
|
|
// Old image disposal
|
|
s = pDraw->pPixels;
|
|
if (pDraw->ucDisposalMethod == 2) // restore to background color
|
|
{
|
|
for (x = 0; x < iWidth; x++)
|
|
{
|
|
if (s[x] == pDraw->ucTransparent)
|
|
s[x] = pDraw->ucBackground;
|
|
}
|
|
pDraw->ucHasTransparency = 0;
|
|
}
|
|
|
|
// Apply the new pixels to the main image
|
|
if (pDraw->ucHasTransparency) // if transparency used
|
|
{
|
|
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
|
|
pEnd = s + iWidth;
|
|
x = 0;
|
|
iCount = 0; // count non-transparent pixels
|
|
while (x < iWidth)
|
|
{
|
|
c = ucTransparent - 1;
|
|
d = &usTemp[0][0];
|
|
while (c != ucTransparent && s < pEnd && iCount < BUFFER_SIZE)
|
|
{
|
|
c = *s++;
|
|
if (c == ucTransparent) // done, stop
|
|
{
|
|
s--; // back up to treat it like transparent
|
|
}
|
|
else // opaque
|
|
{
|
|
*d++ = usPalette[c];
|
|
iCount++;
|
|
}
|
|
} // while looking for opaque pixels
|
|
if (iCount) // any opaque pixels?
|
|
{
|
|
// DMA would degrtade performance here due to short line segments
|
|
tft.setAddrWindow(pDraw->iX + x, y, iCount, 1);
|
|
tft.pushPixels(usTemp, iCount);
|
|
x += iCount;
|
|
iCount = 0;
|
|
}
|
|
// no, look for a run of transparent pixels
|
|
c = ucTransparent;
|
|
while (c == ucTransparent && s < pEnd)
|
|
{
|
|
c = *s++;
|
|
if (c == ucTransparent)
|
|
x++;
|
|
else
|
|
s--;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
s = pDraw->pPixels;
|
|
|
|
// Unroll the first pass to boost DMA performance
|
|
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
|
|
if (iWidth <= BUFFER_SIZE)
|
|
for (iCount = 0; iCount < iWidth; iCount++)
|
|
usTemp[dmaBuf][iCount] = usPalette[*s++];
|
|
else
|
|
for (iCount = 0; iCount < BUFFER_SIZE; iCount++)
|
|
usTemp[dmaBuf][iCount] = usPalette[*s++];
|
|
|
|
#ifdef USE_DMA // 71.6 fps (ST7796 84.5 fps)
|
|
tft.dmaWait();
|
|
tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
|
|
tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
|
|
dmaBuf = !dmaBuf;
|
|
#else // 57.0 fps
|
|
tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
|
|
tft.pushPixels(&usTemp[0][0], iCount);
|
|
#endif
|
|
|
|
iWidth -= iCount;
|
|
// Loop if pixel buffer smaller than width
|
|
while (iWidth > 0)
|
|
{
|
|
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
|
|
if (iWidth <= BUFFER_SIZE)
|
|
for (iCount = 0; iCount < iWidth; iCount++)
|
|
usTemp[dmaBuf][iCount] = usPalette[*s++];
|
|
else
|
|
for (iCount = 0; iCount < BUFFER_SIZE; iCount++)
|
|
usTemp[dmaBuf][iCount] = usPalette[*s++];
|
|
|
|
#ifdef USE_DMA
|
|
tft.dmaWait();
|
|
tft.pushPixelsDMA(&usTemp[dmaBuf][0], iCount);
|
|
dmaBuf = !dmaBuf;
|
|
#else
|
|
tft.pushPixels(&usTemp[0][0], iCount);
|
|
#endif
|
|
iWidth -= iCount;
|
|
}
|
|
}
|
|
tft.endWrite();
|
|
digitalWrite(CS_PINS[currentScreenIndex], HIGH); // Deselect the display
|
|
} /* GIFDraw() */
|