2016-12-18 23:02:44 +01:00
|
|
|
// based on ColorTwinkles by Mark Kriegsman: https://gist.github.com/kriegsman/5408ecd397744ba0393e
|
|
|
|
|
|
|
|
#define STARTING_BRIGHTNESS 64
|
|
|
|
#define FADE_IN_SPEED 32
|
|
|
|
#define FADE_OUT_SPEED 20
|
|
|
|
#define DENSITY 255
|
|
|
|
|
|
|
|
enum { GETTING_DARKER = 0, GETTING_BRIGHTER = 1 };
|
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
CRGB makeBrighter(const CRGB& color, fract8 howMuchBrighter)
|
2016-12-18 23:02:44 +01:00
|
|
|
{
|
|
|
|
CRGB incrementalColor = color;
|
2019-01-13 16:45:50 +01:00
|
|
|
incrementalColor.nscale8(howMuchBrighter);
|
2016-12-18 23:02:44 +01:00
|
|
|
return color + incrementalColor;
|
|
|
|
}
|
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
CRGB makeDarker(const CRGB& color, fract8 howMuchDarker)
|
2016-12-18 23:02:44 +01:00
|
|
|
{
|
|
|
|
CRGB newcolor = color;
|
2019-01-13 16:45:50 +01:00
|
|
|
newcolor.nscale8(255 - howMuchDarker);
|
2016-12-18 23:02:44 +01:00
|
|
|
return newcolor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compact implementation of
|
|
|
|
// the directionFlags array, using just one BIT of RAM
|
|
|
|
// per pixel. This requires a bunch of bit wrangling,
|
|
|
|
// but conserves precious RAM. The cost is a few
|
|
|
|
// cycles and about 100 bytes of flash program memory.
|
2019-01-13 16:45:50 +01:00
|
|
|
uint8_t directionFlags[(NUM_LEDS + 7) / 8];
|
2016-12-18 23:02:44 +01:00
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
bool getPixelDirection(uint16_t i)
|
2016-12-18 23:02:44 +01:00
|
|
|
{
|
|
|
|
uint16_t index = i / 8;
|
|
|
|
uint8_t bitNum = i & 0x07;
|
|
|
|
|
|
|
|
uint8_t andMask = 1 << bitNum;
|
|
|
|
return (directionFlags[index] & andMask) != 0;
|
|
|
|
}
|
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
void setPixelDirection(uint16_t i, bool dir)
|
2016-12-18 23:02:44 +01:00
|
|
|
{
|
|
|
|
uint16_t index = i / 8;
|
|
|
|
uint8_t bitNum = i & 0x07;
|
|
|
|
|
|
|
|
uint8_t orMask = 1 << bitNum;
|
|
|
|
uint8_t andMask = 255 - orMask;
|
|
|
|
uint8_t value = directionFlags[index] & andMask;
|
2019-01-13 16:45:50 +01:00
|
|
|
if (dir) {
|
2016-12-18 23:02:44 +01:00
|
|
|
value += orMask;
|
|
|
|
}
|
|
|
|
directionFlags[index] = value;
|
|
|
|
}
|
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
void brightenOrDarkenEachPixel(fract8 fadeUpAmount, fract8 fadeDownAmount)
|
2016-12-18 23:02:44 +01:00
|
|
|
{
|
2019-01-13 16:45:50 +01:00
|
|
|
for (uint16_t i = 0; i < LEAFCOUNT; i++) {
|
|
|
|
if (getPixelDirection(i*PIXELS_PER_LEAF) == GETTING_DARKER) {
|
2016-12-18 23:02:44 +01:00
|
|
|
// This pixel is getting darker
|
2019-01-13 16:45:50 +01:00
|
|
|
for (int i2 = 0; i2 < PIXELS_PER_LEAF; i2++)leds[i*PIXELS_PER_LEAF + i2] = makeDarker(leds[i*PIXELS_PER_LEAF + i2], fadeDownAmount);
|
|
|
|
}
|
|
|
|
else {
|
2016-12-18 23:02:44 +01:00
|
|
|
// This pixel is getting brighter
|
2019-01-13 16:45:50 +01:00
|
|
|
for (int i2 = 0; i2 < PIXELS_PER_LEAF; i2++)leds[i*PIXELS_PER_LEAF + i2] = makeBrighter(leds[i*PIXELS_PER_LEAF + i2], fadeUpAmount);
|
2016-12-18 23:02:44 +01:00
|
|
|
// now check to see if we've maxxed out the brightness
|
2019-01-13 16:45:50 +01:00
|
|
|
if (leds[i*PIXELS_PER_LEAF].r == 255 || leds[i*PIXELS_PER_LEAF].g == 255 || leds[i*PIXELS_PER_LEAF].b == 255) {
|
2016-12-18 23:02:44 +01:00
|
|
|
// if so, turn around and start getting darker
|
2019-01-13 16:45:50 +01:00
|
|
|
for (int i2 = 0; i2 < PIXELS_PER_LEAF; i2++)setPixelDirection(i*PIXELS_PER_LEAF + i2, GETTING_DARKER);
|
2016-12-18 23:02:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void colortwinkles()
|
|
|
|
{
|
|
|
|
EVERY_N_MILLIS(30)
|
|
|
|
{
|
|
|
|
// Make each pixel brighter or darker, depending on
|
|
|
|
// its 'direction' flag.
|
2019-01-13 16:45:50 +01:00
|
|
|
brightenOrDarkenEachPixel(FADE_IN_SPEED, FADE_OUT_SPEED);
|
|
|
|
|
2016-12-18 23:02:44 +01:00
|
|
|
// Now consider adding a new random twinkle
|
2019-01-13 16:45:50 +01:00
|
|
|
if (random8() < DENSITY) {
|
|
|
|
int pos = random16(LEAFCOUNT);
|
|
|
|
if (!leds[pos]) {
|
|
|
|
uint8_t rdo = random8();
|
|
|
|
for (int i = 0; i < PIXELS_PER_LEAF; i++)
|
|
|
|
{
|
|
|
|
leds[pos*PIXELS_PER_LEAF + i] = ColorFromPalette(gCurrentPalette, rdo, STARTING_BRIGHTNESS, NOBLEND);
|
|
|
|
setPixelDirection(pos*PIXELS_PER_LEAF + i, GETTING_BRIGHTER);
|
|
|
|
}
|
2016-12-18 23:02:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cloudTwinkles()
|
|
|
|
{
|
|
|
|
gCurrentPalette = CloudColors_p; // Blues and whites!
|
|
|
|
colortwinkles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void rainbowTwinkles()
|
|
|
|
{
|
|
|
|
gCurrentPalette = RainbowColors_p;
|
|
|
|
colortwinkles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void snowTwinkles()
|
|
|
|
{
|
|
|
|
CRGB w(85, 85, 85), W(CRGB::White);
|
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
gCurrentPalette = CRGBPalette16(W, W, W, W, w, w, w, w, w, w, w, w, w, w, w, w);
|
2016-12-18 23:02:44 +01:00
|
|
|
colortwinkles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void incandescentTwinkles()
|
|
|
|
{
|
|
|
|
CRGB l(0xE1A024);
|
|
|
|
|
2019-01-13 16:45:50 +01:00
|
|
|
gCurrentPalette = CRGBPalette16(l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l);
|
2016-12-18 23:02:44 +01:00
|
|
|
colortwinkles();
|
|
|
|
}
|
|
|
|
|