Sprite (Off-Screen Canvas)
Class: LGFX_Sprite / M5Canvas (from M5GFX)
Header: M5GFX.h (auto-includes LGFX_Sprite)
A sprite is an off-screen drawing buffer. You draw into it with the same API as M5Cardputer.Display, then blit it to the screen in a single operation. This enables double-buffered rendering for flicker-free animation and smooth UI.
M5Canvas is a convenience subclass of LGFX_Sprite that sets PSRAM allocation by default.
M5Canvas vs LGFX_Sprite
M5Canvas sprite(&M5Cardputer.Display); // auto PSRAM, binds parent display
LGFX_Sprite sprite; // no parent, manual PSRAM
Use M5Canvas for most cases. Use LGFX_Sprite only when you want explicit control over PSRAM via setPsram().
Lifecycle
void* createSprite(int32_t w, int32_t h); // Allocate off-screen buffer
void deleteSprite(); // Free the buffer
M5Canvas sprite(&M5Cardputer.Display);
sprite.setColorDepth(16); // MUST be called BEFORE createSprite
sprite.createSprite(320, 240);
// ... draw into sprite ...
sprite.deleteSprite(); // Clean up when done
Buffer Management
void setPsram(bool enabled); // Use PSRAM for next createSprite
void* setColorDepth(color_depth_t depth); // Change color depth (re-creates buffer)
void setBuffer(void* buffer, int32_t w, int32_t h, uint8_t bpp = 0); // Wrap external memory
void* getBuffer(); // Raw buffer pointer
uint32_t bufferLength(); // Buffer size in bytes
Color depth options: 1, 4, 8, 16, 24, 32 (bits per pixel). For M5Cardputer, 16 is usually best.
Warning
setColorDepth() and setPsram() must be called before createSprite(). Changing color depth after creation destroys and re-creates the buffer.
Pushing to Display
void pushSprite(int32_t x, int32_t y); // Push to parent display
void pushSprite(LovyanGFX* dst, int32_t x, int32_t y); // Push to any display
void pushSprite(int32_t x, int32_t y, uint16_t transparent); // With transparent color
sprite.pushSprite(0, 0); // Full sprite at (0,0) on parent
sprite.pushSprite(&M5Cardputer.Display, 10, 20); // At (10,20)
sprite.pushSprite(0, 0, TFT_BLACK); // TFT_BLACK pixels are transparent
Rotated / Zoomed Push
void pushRotated(float angle); // Rotate & push
void pushRotated(float angle, uint16_t transparent); // With transparency
void pushRotateZoom(float angle, float zoom_x, float zoom_y); // Rotate + scale
void pushAffine(const float matrix[6]); // Affine transform
Inherited Drawing Methods
LGFX_Sprite inherits ALL LGFXBase drawing methods, so everything from Display (M5GFX) works on sprites:
sprite.fillScreen(TFT_BLACK);
sprite.fillRect(10, 10, 100, 50, TFT_RED);
sprite.drawCircle(160, 120, 60, TFT_GREEN);
sprite.drawString("Hello", 10, 10);
Double-Buffered Rendering
M5Canvas backBuffer(&M5Cardputer.Display);
void setup() {
M5Cardputer.begin();
backBuffer.setColorDepth(16);
backBuffer.createSprite(320, 240);
}
void loop() {
M5Cardputer.update();
// Draw everything to back buffer
backBuffer.fillScreen(TFT_BLACK);
backBuffer.drawString("FPS counter", 10, 10);
// ... more drawing ...
// Blit in one shot — no flicker
backBuffer.pushSprite(0, 0);
}
Low-BPP Sprites with Palette
For memory-constrained scenarios, use 8-bit (or lower) color depth with a palette:
M5Canvas sprite(&M5Cardputer.Display);
sprite.setColorDepth(8);
sprite.createSprite(320, 240);
sprite.createPalette();
sprite.setPaletteColor(0, TFT_BLACK);
sprite.setPaletteColor(1, TFT_WHITE);
sprite.setPaletteColor(2, TFT_RED);
sprite.fillScreen(0); // Use palette index 0
sprite.drawString("Hi", 10, 10); // Text color uses palette
sprite.pushSprite(0, 0);
Loading Sprite from BMP
bool createFromBmpFile(const char* path); // From SD card
bool createFromBmp(const uint8_t* data, uint32_t len); // From memory
This replaces the sprite buffer with the BMP content (no need to call createSprite first).
Quick Example: Simple Game Loop
M5Canvas canvas(&M5Cardputer.Display);
void setup() {
M5Cardputer.begin();
canvas.setColorDepth(16);
canvas.createSprite(320, 240);
}
int x = 100, y = 100;
void loop() {
M5Cardputer.update();
// Clear back buffer
canvas.fillScreen(TFT_BLACK);
// Move player
auto& keys = M5Cardputer.Keyboard.keysState();
if (M5Cardputer.Keyboard.isKeyPressed('w')) y--;
if (M5Cardputer.Keyboard.isKeyPressed('s')) y++;
if (M5Cardputer.Keyboard.isKeyPressed('a')) x--;
if (M5Cardputer.Keyboard.isKeyPressed('d')) x++;
// Draw game objects
canvas.fillRect(x, y, 16, 16, TFT_GREEN);
// Flip to screen
canvas.pushSprite(0, 0);
}
void cleanup() {
canvas.deleteSprite();
}