-
-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Laurence Bank
authored and
Laurence Bank
committed
Mar 3, 2024
1 parent
f107792
commit c9ee66b
Showing
12 changed files
with
124,643 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// | ||
// This example shows how to use "cooked" pixel mode on the CYD (Cheap Yellow Display - an ESP32 + SPI LCD) | ||
// With cooked pixels, we can send each line of pixels to the display without "jumping over" transparent pixels | ||
// This almost always results in much higher display performance because switching between command and data mode | ||
// on SPI displays can cause significant slowdowns. | ||
// | ||
#include <bb_spi_lcd.h> | ||
#include <AnimatedGIF.h> | ||
// Set the name of the example animation | ||
#define GIF_NAME thisisfine_240x179 | ||
// Use any of the provided examples | ||
#include "../test_images/thisisfine_240x179.h" | ||
|
||
uint8_t *pFrameBuffer; | ||
|
||
AnimatedGIF gif; | ||
BB_SPI_LCD lcd; | ||
int iOffX, iOffY; | ||
// | ||
// Draw callback from GIF decoder | ||
// | ||
// called once for each line of the current frame | ||
// MCUs with very little RAM would have to test for disposal methods, transparent pixels | ||
// and translate the 8-bit pixels through the palette to generate the final output. | ||
// The code for MCUs with enough RAM is much simpler because the AnimatedGIF library can | ||
// generate "cooked" pixels that are ready to send to the display | ||
// | ||
void GIFDraw(GIFDRAW *pDraw) | ||
{ | ||
if (pDraw->y == 0) { // set the memory window when the first line is rendered | ||
lcd.setAddrWindow(iOffX + pDraw->iX, iOffY + pDraw->iY, pDraw->iWidth, pDraw->iHeight); | ||
} | ||
// For all other lines, just push the pixels to the display | ||
lcd.pushPixels((uint16_t *)pDraw->pPixels, pDraw->iWidth, DRAW_TO_LCD | DRAW_WITH_DMA); | ||
} /* GIFDraw() */ | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
|
||
lcd.begin(DISPLAY_CYD); | ||
lcd.setRotation(0); | ||
lcd.fillScreen(TFT_BLACK); | ||
} /* setup() */ | ||
|
||
void loop() { | ||
long lTime; | ||
int iLoop, w, h, iFrames, iFPS; | ||
|
||
gif.begin(GIF_PALETTE_RGB565_BE); // the SPI display's native pixel format is RGB565 big endian | ||
if (gif.open((uint8_t *)GIF_NAME, sizeof(GIF_NAME), GIFDraw)) { | ||
w = gif.getCanvasWidth(); | ||
h = gif.getCanvasHeight(); | ||
lcd.setTextColor(TFT_GREEN, TFT_BLACK); | ||
lcd.setFont(FONT_12x16); | ||
lcd.printf("GIF Canvas %dx%d\n", w, h); | ||
// We need fast SRAM the size of the GIF canvas as 8-bit pixels + extra space for 1 line of cooked pixels (canvas width * sizeof(uint16_t)) | ||
pFrameBuffer = (uint8_t *)heap_caps_malloc(w * (h+2), MALLOC_CAP_8BIT); | ||
if (pFrameBuffer == NULL) { | ||
lcd.setTextColor(TFT_RED, TFT_BLACK); | ||
lcd.println("Memory Error!"); | ||
lcd.printf("Failed to allocate %d bytes\n", w*(h+2)); | ||
lcd.println("Halted"); | ||
while (1) {}; // not enough memory to continue | ||
} | ||
iOffX = (lcd.width() - w)/2; | ||
iOffY = (lcd.height() - h)/2; | ||
iLoop = 0; | ||
while (1) { | ||
gif.setDrawType(GIF_DRAW_COOKED); // we want the library to generate ready-made pixels | ||
gif.setFrameBuf(pFrameBuffer); // pass it the buffer to hold the canvas as 8-bit pixels (it merges new opaque pixels for each frame rendered) | ||
lTime = micros(); | ||
iFrames = 0; | ||
while (gif.playFrame(iLoop != 0, NULL)) { // Use the first loop to see the unthrottled library speed | ||
iFrames++; | ||
} | ||
if (iLoop == 0) { // show the maximum possible render speed the first time through the animation loop | ||
lTime = micros() - lTime; | ||
iFPS = (iFrames * 10000000) / lTime; | ||
lcd.setCursor(0, 304); // show speed at the bottom | ||
lcd.printf("Max Speed: %d.%d FPS", iFPS/10, iFPS % 10); | ||
} | ||
gif.reset(); // don't close() the file here, just reset to frame 0 to repeat the sequence forever | ||
iLoop++; | ||
} // while (1) | ||
} // if GIF opened successfully | ||
} /* loop() */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// | ||
// Example of how to use Turbo mode on the LilyGo T-QT | ||
// This code can work equally well with a wide variety of MCUs and displays | ||
// | ||
#include <bb_spi_lcd.h> | ||
#include <AnimatedGIF.h> | ||
#define GIF_NAME earth_128x128 | ||
#include "../test_images/earth_128x128.h" | ||
|
||
uint8_t *pTurboBuffer; | ||
|
||
AnimatedGIF gif; | ||
BB_SPI_LCD lcd; | ||
int iOffX, iOffY; | ||
// | ||
// Draw callback from the AnimatedGIF decoder | ||
// | ||
// Called once for each line of the current frame | ||
// MCUs with minimal RAM would have to process "RAW" pixels into "COOKED" here. | ||
// "Cooking" involves testing for disposal methods, merging non-transparent pixels | ||
// and translating the raw pixels through the palette to generate the final output. | ||
// The code for MCUs with enough RAM is much simpler because the AnimatedGIF library can | ||
// generate "cooked" pixels that are ready to send to the display as-is. | ||
// | ||
void GIFDraw(GIFDRAW *pDraw) | ||
{ | ||
if (pDraw->y == 0) { // set the memory window (once per frame) when the first line is rendered | ||
lcd.setAddrWindow(iOffX + pDraw->iX, iOffY + pDraw->iY, pDraw->iWidth, pDraw->iHeight); | ||
} | ||
// For all other lines, just push the pixels to the display. We requested 'COOKED'big-endian RGB565 and | ||
// the library provides them here. No need to do anything except push them right to the display | ||
lcd.pushPixels((uint16_t *)pDraw->pPixels, pDraw->iWidth, DRAW_TO_LCD | DRAW_WITH_DMA); | ||
} /* GIFDraw() */ | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
|
||
gif.begin(GIF_PALETTE_RGB565_BE); // Set the cooked output type we want (compatible with SPI LCDs) | ||
|
||
// Take a look in bb_spi_lcd.h for a list of popular products which have a pre-configured display | ||
// name. Alternatively, you can pass the library the GPIO pin numbers, but I made it easier | ||
// for well-known IoT products by keeping those details inside my library. | ||
lcd.begin(DISPLAY_T_QT); // Initialize the display controller of the LilyGo T-QT | ||
lcd.fillScreen(TFT_BLACK); | ||
} /* setup() */ | ||
|
||
void loop() { | ||
long lTime; | ||
int iFrames, iFPS; | ||
|
||
// Allocate a buffer to enable Turbo decoding mode (~50% faster) | ||
// it requires enough space for the full "raw" canvas plus about 32K workspace for the decoder | ||
pTurboBuffer = (uint8_t *)heap_caps_malloc(TURBO_BUFFER_SIZE + (128*128), MALLOC_CAP_8BIT); | ||
|
||
while (1) { // loop forever | ||
// The GIFDraw callback is optional if you use Turbo mode (pass NULL to disable it). You can either | ||
// manage the transparent pixels + palette conversion yourself or provide a framebuffer for the 'cooked' | ||
// version of the canvas size (setDrawType to GIF_DRAW_FULLFRAME). | ||
if (gif.open((uint8_t *)GIF_NAME, sizeof(GIF_NAME), GIFDraw)) { | ||
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight()); | ||
gif.setDrawType(GIF_DRAW_COOKED); // We want the library to generate ready-made pixels | ||
gif.setTurboBuf(pTurboBuffer); // Set this before calling playFrame() | ||
iOffX = (lcd.width() - gif.getCanvasWidth())/2; // center on the display | ||
iOffY = (lcd.height() - gif.getCanvasHeight())/2; | ||
lTime = micros(); | ||
// Decode frames until we hit the end of the file | ||
// false in the first parameter tells it to return immediately so we can test the decode speed | ||
// Change to true if you would like the animation to run at the speed programmed into the file | ||
iFrames = 0; | ||
while (gif.playFrame(false, NULL)) { | ||
iFrames++; | ||
} | ||
lTime = micros() - lTime; | ||
iFPS = (iFrames * 10000000) / lTime; // get 10x FPS to make an integer fraction of 1/10th | ||
Serial.printf("total decode time for %d frames = %d us, %d.%d FPS\n", iFrames, (int)lTime, iFPS/10, iFPS % 10); | ||
gif.close(); // You can also use gif.reset() instead of close() to start playing the same file again | ||
} // if the file opened successfully | ||
} // while (1) | ||
} /* loop() */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.