#include <Adafruit_NeoPixel.h>

#define PIN        6
#define NUMPIXELS 100

#define ARRAY_LEN NUMPIXELS
#define SPEED 2

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
uint8_t ledBrightness[ARRAY_LEN];

void fade(uint32_t colorStart, uint32_t colorEnd)
{
  uint8_t colorStartW = (uint8_t)(colorStart >> 24);
  uint8_t colorStartR = (uint8_t)(colorStart >> 16);
  uint8_t colorStartG = (uint8_t)(colorStart >> 8);
  uint8_t colorStartB = (uint8_t)colorStart;
  uint8_t colorEndW = (uint8_t)(colorEnd >> 24);
  uint8_t colorEndR = (uint8_t)(colorEnd >> 16);
  uint8_t colorEndG = (uint8_t)(colorEnd >> 8);
  uint8_t colorEndB = (uint8_t)colorEnd;
  bool isUpdated = true;

  memset(ledBrightness, 0, sizeof(uint8_t) * ARRAY_LEN);

  while (isUpdated)
  {
    isUpdated = false;

    for(int i = 0; i < NUMPIXELS; i++)
    {
      if (ledBrightness[i] == 255)
      {
        continue;
      }

      float percent = 0.0f;
      if (ledBrightness[i] > 0)
      {
        percent = (float)ledBrightness[i] / 255.0f;
      }  

      if (255 - ledBrightness[i] < SPEED)
      {
        ledBrightness[i] = 255;
      }
      else
      {
        ledBrightness[i] += SPEED;
      }

      uint8_t w = floor(percent * colorEndW) + floor((1.0 - percent) * colorStartW);
      uint8_t r = floor(percent * colorEndR) + floor((1.0 - percent) * colorStartR);
      uint8_t g = floor(percent * colorEndG) + floor((1.0 - percent) * colorStartG);
      uint8_t b = floor(percent * colorEndB) + floor((1.0 - percent) * colorStartB);

      pixels.setPixelColor(i, r, g, b, w);
      isUpdated = true;

      if (percent <= 0.01)
      {
        break;
      }
    }

    while(!pixels.canShow()){}
    pixels.show();
  }
}

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

void loop()
{
  pixels.clear();
  pixels.show();

  fade(pixels.Color(0, 0, 0, 0), pixels.Color(41, 143, 194, 42));
  fade(pixels.Color(41, 143, 194, 42), pixels.Color(255, 0, 0, 0));
  fade(pixels.Color(255, 0, 0, 0), pixels.Color(0, 0, 0, 0));
}