// 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() */