A seasonal (Xmas) TFT sketch

To brighten up my desk this Christmas I decided to write a simple seasonal sketch. It draws a tree with twinkling multi-colour lights.

By default it uses the Adafruit_GFX library (plus the hardware specific library for your TFT) or optionally my own libraries.

It uses the width and height of the TFT to scale the tree size for any screen resolution.

// This example uses the either the Bodmer's library here with a ST7735 based TFT display:
// https://github.com/Bodmer/TFT_ST7735
// (don't forget to edit the User_Setup.h file inside that library to define pins etc)

// OR you can use the standard Adafruit_GFX library, see line 15 below
// When using the Adafruit_GFX library update line 61 to suit your display and lines
// 32-34 to define the pins used. Use of hardware SPI lines is assumed.

// Other TFT_xxxxx libraries that could be used can be found here:
// https://github.com/Bodmer?tab=repositories
//

// If using Bodmer's library then comment out the next #define line with //,
// or uncomment (delete the //) to use Adafruit_GFX library
#define USE_ADAFRUIT_GFX


#include <SPI.h>

// Select which library to use
#ifdef USE_ADAFRUIT_GFX

    #include <Adafruit_GFX.h>    // Core graphics library
    #include <Adafruit_ST7735.h> // Hardware-specific library

    // The pins are ONLY defined here for the Adafruit library, in Bodmer's library the pins are defined in User_Setup.h
    // ##### EDIT to suit the pins used ####
    #define TFT_CS  47           // Chip select line for TFT display
    #define TFT_DC  48           // Data/command line for TFT
    #define TFT_RST 44           // Reset line for TFT

    Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

    #define TFT_BLACK       0x0000
    #define TFT_DARKGREY    0x7BEF
    #define TFT_DARKGREEN   0x03E0

#else // Use one of Bodmer's libraries

    // A selection of Bodmer's libraries, comment out those not used

    #include <TFT_ST7735.h> // Graphics and font library for ST7735 driver chip
    TFT_ST7735 tft = TFT_ST7735();  // Invoke libraries, pins etc are defined in User_Setup.h inside the library folder

    //#include <TFT_ILI9163.h> // Graphics and font library for ILI9163 driver chip
    //TFT_ILI9163 tft = TFT_ILI9163();  // Invoke library, pins defined in User_Setup.h

    //#include <TFT_S6D02A1.h> // Hardware-specific library
    //TFT_S6D02A1 tft = TFT_S6D02A1();       // Invoke custom library

    //#include <TFT_ILI9341.h> // Hardware-specific library
    //TFT_ILI9341 tft = TFT_ILI9341();       // Invoke library, pins defined in User_Setup.h

    //#include <TFT_HX8357.h> // Hardware-specific library
    //TFT_HX8357 tft = TFT_HX8357();       // Invoke library, pins defined in User_Setup.h

    //#include <TFT_HX8357_Due.h> // Hardware-specific library
    //TFT_HX8357_Due tft = TFT_HX8357_Due();       // Invoke library, pins defined in User_Setup.h

#endif // end of library selection

int x[6][3];
int y[6][3];

//====================================================================================
// Setup
//====================================================================================

void setup()
{
  Serial.begin(115200);

  // Choose library init function
#ifdef USE_ADAFRUIT_GFX
    // Adafruit init line
    tft.initR(INITR_BLACKTAB);  // <<<<<<<<<<<<<<<  EDIT TO SUIT YOUR DISPLAY
#else
    // Bodmer's library init function
    tft.init();
#endif

  tft.setRotation(0); // portrait

}

//====================================================================================
// Loop
//====================================================================================

void loop()
{

  tft.fillScreen(TFT_BLACK);

  int w = tft.width();
  int h = tft.height();
  
  for (int n = 2; n < 8; n++) {
    int layer = n - 2;
    x[layer][0] = w / 2;
    y[layer][0] = n * h / 8 - h / 6;
    x[layer][1] = w / 2 - n * w / 16;
    y[layer][1] = n * h / 8;
    x[layer][2] = w / 2 + (n * w / 16);
    y[layer][2] = n * h / 8;
  }

  tft.fillRect(w/2-w / 20, h - h / 6, w / 10, h / 6, TFT_DARKGREY);

  for (int layer = 0; layer < 6; layer++) {
    tft.fillTriangle(x[layer][0], y[layer][0], x[layer][1], y[layer][1], x[layer][2], y[layer][2], TFT_DARKGREEN);
  }

  while (1) {
    for (int layer = 0; layer < 6; layer++) {
      for (int corner = 0; corner < 3; corner++) {
        tft.fillCircle(x[layer][corner], y[layer][corner], w / 40, rainbow(random(128)));
        delay(10);
      }
    }
    tft.fillCircle(x[5][0], y[5][1], w / 40, rainbow(random(128))); // Last light
  }
}

//====================================================================================
// Produce a rainbow colour
//====================================================================================

unsigned int rainbow(int value)
{
  // Value is expected to be in range 0-127
  // The value is converted to a spectrum colour from 0 = blue through to red = 127

  byte red = 0; // Red is the top 5 bits of a 16 bit colour value
  byte green = 0;// Green is the middle 6 bits
  byte blue = 0; // Blue is the bottom 5 bits

  byte quadrant = value / 32;

  if (quadrant == 0) {
    blue = 31;
    green = 2 * (value % 32);
    red = 0;
  }
  if (quadrant == 1) {
    blue = 31 - (value % 32);
    green = 63;
    red = 0;
  }
  if (quadrant == 2) {
    blue = 0;
    green = 63;
    red = value % 32;
  }
  if (quadrant == 3) {
    blue = 0;
    green = 63 - 2 * (value % 32);
    red = 31;
  }
  return (red << 11) + (green << 5) + blue;
}

Does anyone else have a similar seasonal sketch to try?