Sparkling Belt Code

#include <Adafruit_NeoPixel.h>

enum { PIN = A3, NUMPIXELS = 144, FULLY_SATURATED = 255 };

typedef struct RgbColor
{
  unsigned char r;
  unsigned char g;
  unsigned char b;
} RgbColor;

typedef struct HsvColor
{
  unsigned char h;
  unsigned char s;
  unsigned char v;
  HsvColor( void ) { h = s = v = 0; }
  HsvColor( int a, int b, int c )
  {
    h = a;
    s = b;
    v = c;
  }
} HsvColor;

RgbColor HsvToRgb( HsvColor hsv )
{
  RgbColor rgb;
  unsigned char region, p, q, t;
  unsigned int h, s, v, remainder;

  if( hsv.s == 0 )
  {
    rgb.r = hsv.v;
    rgb.g = hsv.v;
    rgb.b = hsv.v;
    return rgb;
  }

  // converting to 16 bit to prevent overflow
  h = hsv.h;
  s = hsv.s;
  v = hsv.v;

  region = h / 43;
  remainder = (h - (region * 43)) * 6; 

  p = (v * (255 - s)) >> 8;
  q = (v * (255 - ((s * remainder) >> 8))) >> 8;
  t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;

  switch (region)
  {
    case 0:
      rgb.r = v;
      rgb.g = t;
      rgb.b = p;
      break;
    case 1:
      rgb.r = q;
      rgb.g = v;
      rgb.b = p;
      break;
    case 2:
      rgb.r = p;
      rgb.g = v;
      rgb.b = t;
      break;
    case 3:
      rgb.r = p;
      rgb.g = q;
      rgb.b = v;
      break;
    case 4:
      rgb.r = t;
      rgb.g = p;
      rgb.b = v;
      break;
    default:
      rgb.r = v;
      rgb.g = p;
      rgb.b = q;
      break;
  }

  return rgb;
}

HsvColor RgbToHsv( RgbColor rgb )
{
  HsvColor hsv;
  unsigned char rgbMin, rgbMax;

  rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
  rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);

  hsv.v = rgbMax;
  if( hsv.v == 0 )
  {
    hsv.h = 0;
    hsv.s = 0;
    return hsv;
  }

  hsv.s = 255 * ((long)(rgbMax - rgbMin)) / hsv.v;
  if( hsv.s == 0 )
  {
    hsv.h = 0;
    return hsv;
  }

  if( rgbMax == rgb.r )
    hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
  else if( rgbMax == rgb.g )
    hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
  else
    hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);

  return hsv;
}

Adafruit_NeoPixel pixels = Adafruit_NeoPixel( NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800 );

void
setup( void )
{
  pixels.begin();
}

unsigned char hue = 0;
int train_length = 10;
int train_position = 0;

void
train( void )
{
  for( int i = 0; i < NUMPIXELS; i++ )
  {
    int bright = 0;
    if( i > train_position && i < train_position + train_length )
      bright = 255;
    int low = (train_position + train_length) - NUMPIXELS;
    if( i < low )
      bright = 255;
    HsvColor hsv( hue, FULLY_SATURATED, bright );
    RgbColor rgb = HsvToRgb( hsv );
    pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
  }
  pixels.show();
  hue++;
  train_position++;
  train_position %= (NUMPIXELS + train_length);
}

void
collide( void )
{
  int reverse = NUMPIXELS + train_length/2 - train_position;
  for( int i = 0; i < NUMPIXELS; i++ )
  {
    int bright = 0;
    if( i > train_position && i < train_position + train_length/2 )
      bright = 255;
    int low = (train_position + train_length/2) - NUMPIXELS;
    if( i < low )
      bright = 255;
    if( i < reverse && i > reverse - train_length/2 )
      bright = 255;
    int high = reverse - NUMPIXELS;
    if( i < high )
      bright = 255;
    HsvColor hsv( hue, FULLY_SATURATED, bright );
    RgbColor rgb = HsvToRgb( hsv );
    pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
  }

  pixels.show();
  hue++;
  train_position++;
  train_position %= (NUMPIXELS + train_length);
}

void
chaser( void )
{
  for( int i = 0; i < NUMPIXELS; i++ )
  {
    int bright = 0;
    if( (i + train_position) % 20 == 0 )
      bright = 255;
    HsvColor hsv( hue, FULLY_SATURATED, bright );
    RgbColor rgb = HsvToRgb( hsv );
    pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
    hue += 7;
  }
  pixels.show();
  train_position++;
  train_position %= NUMPIXELS;
}

unsigned char stars[5];

void
sparkle( void )
{
  for( unsigned x = 0; x < sizeof stars; x++ )
    stars[x] = random( NUMPIXELS );
  for( int i = 0; i < NUMPIXELS; i++ )
  {
    int bright = 0;
    for( unsigned x = 0; x < sizeof stars; x++ )
      if( stars[x] == i )
        bright = 255;
    hue = random( 255 );
    HsvColor hsv( hue, FULLY_SATURATED, bright );
    RgbColor rgb = HsvToRgb( hsv );
    pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
  }
  pixels.show();
}

enum
{
  CHASER,
  TRAIN,
  COLLIDE,
  SPARKLE,
  SLOWTRAIN,
  SLOWCHASER,
  SLOWCOLLIDE,
  SLOWSPARKLE,
  THE_END
  };

unsigned count = 0, mode = CHASER;

void
loop( void )
{
  if( mode == CHASER )
    chaser();
  else if( mode == TRAIN )
    train();
  else if( mode == SPARKLE )
    sparkle();
  else if( mode == COLLIDE )
    collide();
  else if( mode == SLOWCHASER )
  {
    chaser();
    count += 9;
    delay( 50 );
  }
  else if( mode == SLOWTRAIN )
  {
    train();
    count += 9;
    delay( 50 );
  }
  else if( mode == SLOWSPARKLE )
  {
    sparkle();
    count += 9;
    delay( 50 );
  }
  else if( mode == SLOWCOLLIDE )
  {
    collide();
    count += 9;
    delay( 50 );
  }
  if( count++ > 1000 )
  {
    mode  = random( THE_END );
    count = 0;
  }
}