#include "FastLED.h"

// length of the trail
#define STRING_SIZE 12

#define NUM_STRIPS 8
#define NUM_LEDS_PER_STRIP 300
#define NUM_LEDS ((NUM_LEDS_PER_STRIP) * (NUM_STRIPS))

CRGB leds[NUM_LEDS];

// A 1-bit flag for each strip to signal whether it needs to be refreshed
uint8_t dirtystrips = -1;


// write a pixel and set the appropriate strip's dirty bit
void plotLED(int16_t lednum, CRGB col) {
  if (lednum < 0 || lednum >= NUM_LEDS)
    return;
  leds[lednum] = col;
  uint8_t bitset = 1;
  while (lednum >= NUM_LEDS_PER_STRIP)
    bitset <<= 1, lednum -= NUM_LEDS_PER_STRIP;
  dirtystrips |= bitset;
}


// show() only strips modified since the last showDirtyStrips()
void showDirtyStrips() {
  uint8_t strip = 0;
  while (dirtystrips) {
    if (dirtystrips & 1)
      FastLED[strip].showLeds(255);
    dirtystrips >>= 1;
    strip++;
  }
}


void setup() {
  FastLED.addLeds<NEOPIXEL, 8> (leds, 0 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 27>(leds, 1 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 16>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 17>(leds, 3 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 25>(leds, 4 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 26>(leds, 5 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 12>(leds, 6 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 13>(leds, 7 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
}


void loop() {
  for (int16_t i = 0; i < NUM_LEDS + STRING_SIZE; i++) {
    plotLED(i, CRGB::Red);
    plotLED(i - STRING_SIZE, CRGB::Black);
    showDirtyStrips();
  }
}