TFT_eSPI/examples/Sprite/Sprite_draw_4bit/Sprite_draw_4bit.ino

199 lines
5.6 KiB
C++

/*
Sketch to show how a 4 bit Sprite is created, how to draw pixels
and text within the Sprite and then push the Sprite onto
the display screen.
The advantage of 4 bit sprites is:
1. Small memory footprint
2. Any set of 16 colours can be specified
3. Colours can be changed without redrawing in Sprite
4. Simple animations like flashing text can be achieved
by colour palette cycling and pushing sprite to TFT:
https://en.wikipedia.org/wiki/Color_cycling
Example for library:
https://github.com/Bodmer/TFT_eSPI
A Sprite is notionally an invisible graphics screen that is
kept in the processors RAM. Graphics can be drawn into the
Sprite just as it can be drawn directly to the screen. Once
the Sprite is completed it can be plotted onto the screen in
any position. If there is sufficient RAM then the Sprite can
be the same size as the screen and used as a frame buffer.
A 4 bit Sprite occupies (width * height)/2 bytes in RAM.
*/
// Set delay after plotting the sprite
#define DELAY 1000
// Width and height of sprite
#define WIDTH 128
#define HEIGHT 128
#include <TFT_eSPI.h> // Include the graphics library (this includes the sprite functions)
TFT_eSPI tft = TFT_eSPI(); // Declare object "tft"
TFT_eSprite spr = TFT_eSprite(&tft); // Declare Sprite object "spr" with pointer to "tft" object
void setup()
{
Serial.begin(115200);
Serial.println();
delay(500);
// Initialise the TFT registers
tft.init();
// Set the sprite colour depth to 4
spr.setColorDepth(4);
// Create a sprite of defined size
spr.createSprite(WIDTH, HEIGHT);
// Clear the TFT screen to blue
tft.fillScreen(TFT_BLUE);
}
void loop(void)
{
// Fill the whole sprite with color 0 (Sprite is in memory so not visible yet)
spr.fillSprite(0);
// create a color map with known colors (16 maximum for 4 bit Sprite
uint16_t cmap[16];
cmap[0] = TFT_BLACK; // We will keep this as black
cmap[1] = TFT_NAVY;
cmap[2] = TFT_DARKGREEN;
cmap[3] = TFT_DARKCYAN;
cmap[4] = TFT_MAROON;
cmap[5] = TFT_PURPLE;
cmap[6] = TFT_PINK;
cmap[7] = TFT_LIGHTGREY;
cmap[8] = TFT_YELLOW;
cmap[9] = TFT_BLUE;
cmap[10] = TFT_GREEN;
cmap[11] = TFT_CYAN;
cmap[12] = TFT_RED;
cmap[13] = TFT_MAGENTA;
cmap[14] = TFT_WHITE; // Keep as white for text
cmap[15] = TFT_BLUE; // Keep as blue for sprite border
// Pass the palette to the Sprite class
spr.createPalette(cmap);
// Push Sprite parially off-screen to test cropping
spr.pushSprite(-40, -40);
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2, 10);
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
// Number of pixels to draw
uint16_t n = 100;
// Draw 100 random color pixels at random positions in sprite
while (n--)
{
uint16_t color = random(0x10); // Returns color 0 - 0x0F (i.e. 0-15)
int16_t x = random(WIDTH); // Random x coordinate
int16_t y = random(HEIGHT); // Random y coordinate
spr.drawPixel(x, y, color); // Draw pixel in sprite
}
// Draw some lines
spr.drawLine(1, 0, WIDTH, HEIGHT-1, 10);
spr.drawLine(0, 0, WIDTH, HEIGHT, 10);
spr.drawLine(0, 1, WIDTH-1, HEIGHT, 10);
spr.drawLine(0, HEIGHT-1, WIDTH-1, 0, 12);
spr.drawLine(0, HEIGHT, WIDTH, 0, 12);
spr.drawLine(1, HEIGHT, WIDTH, 1, 12);
// Draw some text with Middle Centre datum
spr.setTextDatum(MC_DATUM);
spr.setTextColor(14); // White text
spr.drawString("Sprite", WIDTH / 2, HEIGHT / 2, 4);
// Now push the sprite to the TFT at 3 positions on screen
spr.pushSprite(-40, -40);
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2);
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
delay(DELAY * 4);
// create a new color map for colours 1-13 and use it instead
for (auto i = 1; i <= 13; i++)
{
cmap[i] = random(0x10000);
}
spr.createPalette(cmap, 16);
// Now push the sprite to the TFT at position 0,0 on screen
spr.pushSprite(-40, -40);
spr.pushSprite(tft.width() / 2 - WIDTH / 2, tft.height() / 2 - HEIGHT / 2);
spr.pushSprite(tft.width() - WIDTH + 40, tft.height() - HEIGHT + 40);
delay(DELAY);
// Fill TFT screen with blue
tft.fillScreen(TFT_BLUE);
// Draw a blue rectangle in sprite so when we move it 1 pixel it does not leave a trail
// on the blue screen background
spr.createPalette(cmap);
spr.drawRect(0, 0, WIDTH, HEIGHT, 15); // Blue rectangle
int x = tft.width() / 2 - WIDTH / 2;
int y = tft.height() / 2 - HEIGHT / 2;
uint32_t updateTime = 0; // time for next update
while (true)
{
// Random movement direction
int dx = 1; if (random(2)) dx = -1;
int dy = 1; if (random(2)) dy = -1;
// Pull it back onto screen if it wanders off
if (x < -WIDTH/2) dx = 1;
if (x >= tft.width()-WIDTH/2) dx = -1;
if (y < -HEIGHT/2) dy = 1;
if (y >= tft.height()-HEIGHT/2) dy = -1;
// Randomise the palette to change colours without redrawing
// the sprite
for (auto i = 1; i <= 13; i++)
{
cmap[i] = random(0x10000);
}
spr.createPalette(cmap); // Update sprite class palette
// Draw it 50 times, moving in random direct or staying still
n = 50;
int wait = random (50);
while (n)
{
if (updateTime <= millis())
{
// Use time delay so sprite does not move fast when not all on screen
updateTime = millis() + wait;
// Push the sprite to the TFT screen
spr.pushSprite(x, y);
// Change coord for next loop
x += dx;
y += dy;
n--;
yield(); // Stop watchdog reset
}
}
} // Infinite while, will not exit!
}