diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d0a34a28d..9a2da2043 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2373,4 +2373,53 @@ uint16_t WS2812FX::mode_sinelon(void) { } prevpos = pos; return FRAMETIME; +} + + +/* +* POPCORN +*/ +typedef struct Kernel { + float position; + float velocity; + int32_t color; +} kernel; + +#define MAX_NUM_POPCORN 12 +#define GRAVITY 0.06 + +uint16_t WS2812FX::mode_popcorn(void) { + uint32_t popcornColor = SEGCOLOR(0); + uint32_t bgColor = SEGCOLOR(1); + if(popcornColor == bgColor) popcornColor = color_wheel(random8()); + + static kernel popcorn[MAX_NUM_POPCORN]; + static float coeff = 0.0f; + if(coeff == 0.0f) { // calculate the velocity coeff once (the secret sauce) + coeff = pow((float)SEGLEN, 0.5223324f) * 0.3944296f; + } + + fill(SEGCOLOR(1)); + + uint16_t ledIndex; + for(int8_t i=0; i < MAX_NUM_POPCORN; i++) { + bool isActive = popcorn[i].position >= 0.0f; + + if(isActive) { // if kernel is active, update its position + popcorn[i].position += popcorn[i].velocity; + popcorn[i].velocity -= (GRAVITY * SEGMENT.intensity/25); + ledIndex = SEGMENT.start + popcorn[i].position; + if(ledIndex >= SEGMENT.start && ledIndex <= SEGMENT.stop) setPixelColor(ledIndex, popcorn[i].color); + } else { // if kernel is inactive, randomly pop it + if(random8() < 2) { // POP!!! + popcorn[i].position = 0.0f; + popcorn[i].velocity = coeff * (random(66, 100) / 100.0f); + popcorn[i].color = popcornColor; + ledIndex = SEGMENT.start; + setPixelColor(ledIndex, popcorn[i].color); + } + } + } + + return SPEED_FORMULA_L; } \ No newline at end of file diff --git a/wled00/FX.h b/wled00/FX.h index aabf70790..57b256be4 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -84,7 +84,7 @@ #define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE ) #define IS_SELECTED ((SEGMENT.options & SELECTED) == SELECTED ) -#define MODE_COUNT 89 +#define MODE_COUNT 90 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -175,6 +175,7 @@ #define FX_MODE_SPOTS_FADE 86 #define FX_MODE_BOUNCINGBALLS 87 #define FX_MODE_SINELON 88 +#define FX_MODE_POPCORN 89 class WS2812FX { @@ -321,6 +322,7 @@ class WS2812FX { _mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade; _mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_BouncingBalls; _mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon; + _mode[FX_MODE_POPCORN] = &WS2812FX::mode_popcorn; _brightness = DEFAULT_BRIGHTNESS; currentPalette = CRGBPalette16(CRGB::Black); @@ -503,7 +505,8 @@ class WS2812FX { mode_spots(void), mode_spots_fade(void), mode_BouncingBalls(void), - mode_sinelon(void); + mode_sinelon(void), + mode_popcorn(void); private: NeoPixelWrapper *bus; @@ -576,7 +579,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet", "Dual Scanner","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise", "Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Smooth Meteor","Railway","Ripple", -"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Bouncing Balls", "Sinelon" +"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Bouncing Balls", "Sinelon","Popcorn" ])=====";