From 7ca1970fff2080929b8a89e77202d5b660403ce6 Mon Sep 17 00:00:00 2001 From: fishbone-git Date: Tue, 10 Dec 2019 20:06:00 +0100 Subject: [PATCH 1/6] add bouncing balls effect --- wled00/FX.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 9 +++++--- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2bdb75ba9..495c0397a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2285,3 +2285,67 @@ uint16_t WS2812FX::mode_spots_fade() uint16_t tr = (t >> 1) + (t >> 2); return spots_base(tr); } + + +/* +* Bouncing Balls Effect +* Adapted from: https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ +*/ +uint16_t WS2812FX::mode_BouncingBalls(void) { + // number of balls based on intensity setting, + // only has 4 for a few of the higher settings as there is no colour selection + // fourth ball is a random colour + int balls = int(((SEGMENT.intensity * 6.2) / 255) + 1); + + // ideally use speed for gravity effect on the bounce + float Gravity = -9.81; + + const int maxBallCount = 7; + static float Height[maxBallCount]; + static float ImpactVelocity[maxBallCount]; + static int Position[maxBallCount]; + static float TimeSinceLastBounce[maxBallCount]; + static long ClockTimeSinceLastBounce[maxBallCount]; + static int StartHeight = 1; // height in metres (strip length) + static float Dampening[maxBallCount] = {0}; // Coefficient of Restitution (bounce damping) + static float ImpactVelocityStart=sqrt( -2 * Gravity * StartHeight); + + // Different from the examples, to allow for initialisation of the first bounce + if (Dampening[0] == 0) { + for (int i = 0 ; i < maxBallCount ; i++) { + ClockTimeSinceLastBounce[i] = millis(); + ImpactVelocity[i] = ImpactVelocityStart; + TimeSinceLastBounce[i] = 0; + Dampening[i] = 0.90 - float(i)/pow(maxBallCount,2); + } + } + + for (int i = 0 ; i < balls ; i++) { + TimeSinceLastBounce[i] = millis() - ClockTimeSinceLastBounce[i]; + Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000; + + if ( Height[i] < 0 ) { + Height[i] = 0; + ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i]; + ClockTimeSinceLastBounce[i] = millis(); + + if ( ImpactVelocity[i] < 0.01 ) { + ImpactVelocity[i] = ImpactVelocityStart; + } + } + Position[i] = round( Height[i] * (SEGLEN - 1) / StartHeight); + } + + fill(BLACK); + + for (int i = 0 ; i < balls ; i++) { + uint32_t color = SEGCOLOR(i % NUM_COLORS); + if (!color) { + color = color_wheel(random8()); + } + + setPixelColor(Position[i],color); + } + + return 20; +} \ No newline at end of file diff --git a/wled00/FX.h b/wled00/FX.h index 5a3865ae0..5642850a3 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 87 +#define MODE_COUNT 88 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -173,6 +173,7 @@ #define FX_MODE_TRI_STATIC_PATTERN 84 #define FX_MODE_SPOTS 85 #define FX_MODE_SPOTS_FADE 86 +#define FX_MODE_BOUNCINGBALLS 87 class WS2812FX { @@ -317,6 +318,7 @@ class WS2812FX { _mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern; _mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots; _mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade; + _mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_BouncingBalls; _brightness = DEFAULT_BRIGHTNESS; currentPalette = CRGBPalette16(CRGB::Black); @@ -497,7 +499,8 @@ class WS2812FX { mode_static_pattern(void), mode_tri_static_pattern(void), mode_spots(void), - mode_spots_fade(void); + mode_spots_fade(void), + mode_BouncingBalls(void); private: NeoPixelWrapper *bus; @@ -570,7 +573,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" +"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Bouncing Balls" ])====="; From 86ae11f4c44fe1b37a325af5040b9438a6d5ed9d Mon Sep 17 00:00:00 2001 From: fishbone-git Date: Tue, 10 Dec 2019 20:26:02 +0100 Subject: [PATCH 2/6] add sinelon effect --- wled00/FX.cpp | 25 +++++++++++++++++++++++++ wled00/FX.h | 9 ++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 495c0397a..d0a34a28d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2348,4 +2348,29 @@ uint16_t WS2812FX::mode_BouncingBalls(void) { } return 20; +} + +/* +* Sinelon stolen from FASTLED examples +*/ +uint16_t WS2812FX::mode_sinelon(void) { + + fade_out(SEGMENT.intensity); + int pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1); + static int prevpos = 0; + + // setRange seems great to use, but doesn't work here for some reason + if( pos < prevpos ) { + for (uint16_t i = pos; i < prevpos; i++) + { + setPixelColor(i, color_from_palette(pos, false, false, 0)); + } + } else { + for (uint16_t i = prevpos; i < pos; i++) + { + setPixelColor(i, color_from_palette(pos, false, false, 0)); + } + } + prevpos = pos; + return FRAMETIME; } \ No newline at end of file diff --git a/wled00/FX.h b/wled00/FX.h index 5642850a3..aabf70790 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 88 +#define MODE_COUNT 89 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -174,6 +174,7 @@ #define FX_MODE_SPOTS 85 #define FX_MODE_SPOTS_FADE 86 #define FX_MODE_BOUNCINGBALLS 87 +#define FX_MODE_SINELON 88 class WS2812FX { @@ -319,6 +320,7 @@ class WS2812FX { _mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots; _mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade; _mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_BouncingBalls; + _mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon; _brightness = DEFAULT_BRIGHTNESS; currentPalette = CRGBPalette16(CRGB::Black); @@ -500,7 +502,8 @@ class WS2812FX { mode_tri_static_pattern(void), mode_spots(void), mode_spots_fade(void), - mode_BouncingBalls(void); + mode_BouncingBalls(void), + mode_sinelon(void); private: NeoPixelWrapper *bus; @@ -573,7 +576,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" +"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Bouncing Balls", "Sinelon" ])====="; From c1dec16c500d1fe5adfcedb3c54163e9a1f597bd Mon Sep 17 00:00:00 2001 From: fishbone-git Date: Tue, 10 Dec 2019 20:34:59 +0100 Subject: [PATCH 3/6] add popcorn effect --- wled00/FX.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 9 ++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) 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" ])====="; From 8817dc6d73cea90079387c9f8203e4f856b7610a Mon Sep 17 00:00:00 2001 From: cschwinne Date: Tue, 24 Dec 2019 00:06:23 +0100 Subject: [PATCH 4/6] Add tertiary color to presets (#509) --- wled00/wled00.ino | 2 +- wled00/wled01_eeprom.ino | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 90bf0ac8e..a577c95d4 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -98,7 +98,7 @@ //version code in format yymmddb (b = daily build) -#define VERSION 1912231 +#define VERSION 1912232 char versionString[] = "0.9.0-b2"; diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 2f68703ea..8a43a79db 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -561,6 +561,7 @@ bool applyPreset(byte index, bool loadBri = true, bool loadCol = true, bool load col[j] = EEPROM.read(i+j+2); colSec[j] = EEPROM.read(i+j+6); } + strip.setColor(2, EEPROM.read(i+12), EEPROM.read(i+13), EEPROM.read(i+14), EEPROM.read(i+15)); //tertiary color } if (loadFX) { @@ -598,6 +599,12 @@ void savePreset(byte index) } EEPROM.write(i+10, effectCurrent); EEPROM.write(i+11, effectSpeed); + + uint32_t colTer = strip.getSegment(strip.getMainSegmentId()).colors[2]; + EEPROM.write(i+12, (colTer >> 16) & 0xFF); + EEPROM.write(i+13, (colTer >> 8) & 0xFF); + EEPROM.write(i+14, (colTer >> 0) & 0xFF); + EEPROM.write(i+15, (colTer >> 24) & 0xFF); EEPROM.write(i+16, effectIntensity); EEPROM.write(i+17, effectPalette); From 924f97cbe818f79b90d411c6ca23c986155d137e Mon Sep 17 00:00:00 2001 From: cschwinne Date: Tue, 24 Dec 2019 00:48:51 +0100 Subject: [PATCH 5/6] Improvements to scan and segment fixes --- wled00/FX.cpp | 28 ++++++++++++++-------------- wled00/wled00.ino | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 8349f0f69..aeba14854 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -301,24 +301,24 @@ uint16_t WS2812FX::scan(bool dual) uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; uint32_t perc = now % cycleTime; uint16_t prog = (perc * 65535) / cycleTime; - uint16_t ledIndex = (prog * ((SEGLEN * 2) - 2)) >> 16; - uint16_t size = 1 + SEGMENT.intensity >> 3; + uint16_t size = 1 + ((SEGMENT.intensity * SEGLEN) >>9); + uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16; fill(SEGCOLOR(1)); - int led_offset = ledIndex - (SEGLEN - 1); + int led_offset = ledIndex - (SEGLEN - size); led_offset = abs(led_offset); - uint16_t i = SEGMENT.start + led_offset; - for (int16_t j=i-size/2; j<=i+size/2; j++) { - if (j>=0) setPixelColor(j, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + if (dual) { + for (uint16_t j = led_offset; j < led_offset + size; j++) { + uint16_t i2 = SEGMENT.stop -1 -j; + setPixelColor(i2, color_from_palette(i2, true, PALETTE_SOLID_WRAP, (SEGCOLOR(2))? 2:0)); + } } - if (dual) { - uint16_t i2 = SEGMENT.start + SEGLEN - led_offset - 1; - for (int16_t j=i2-size/2; j<=i2+size/2; j++) { - if (j>=0) setPixelColor(j, color_from_palette(i2, true, PALETTE_SOLID_WRAP, 0)); - } + for (uint16_t j = led_offset; j < led_offset + size; j++) { + uint16_t i = SEGMENT.start + j; + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } return FRAMETIME; @@ -998,7 +998,7 @@ uint16_t WS2812FX::larson_scanner(bool dual) { for (uint16_t i = SEGENV.step; i < index; i++) { uint16_t j = (SEGENV.aux0)?i:SEGLEN-1-i; - setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0)); + setPixelColor(SEGMENT.start + j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0)); } if (dual) { uint32_t c; @@ -1010,7 +1010,7 @@ uint16_t WS2812FX::larson_scanner(bool dual) { for (uint16_t i = SEGENV.step; i < index; i++) { uint16_t j = (SEGENV.aux0)?SEGLEN-1-i:i; - setPixelColor(j, c); + setPixelColor(SEGMENT.start + j, c); } } @@ -1028,7 +1028,7 @@ uint16_t WS2812FX::mode_comet(void) { fade_out(SEGMENT.intensity); - setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); + setPixelColor(SEGMENT.start + index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); return FRAMETIME; } diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 90bf0ac8e..a577c95d4 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -98,7 +98,7 @@ //version code in format yymmddb (b = daily build) -#define VERSION 1912231 +#define VERSION 1912232 char versionString[] = "0.9.0-b2"; From f3371c443e16599dff26610e311d627ac4ce7875 Mon Sep 17 00:00:00 2001 From: fishbone-git Date: Tue, 24 Dec 2019 14:46:07 +0100 Subject: [PATCH 6/6] more effects to FRAMETIME --- wled00/FX.cpp | 178 +++++++++----------------------------------------- 1 file changed, 32 insertions(+), 146 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b1e348849..1791b710c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -961,6 +961,10 @@ uint16_t WS2812FX::mode_halloween(void) { * Random colored pixels running. */ uint16_t WS2812FX::mode_running_random(void) { + uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed)); + uint32_t it = now / cycleTime; + if (SEGENV.aux1 == it) return FRAMETIME; + for(uint16_t i=SEGLEN-1; i > 0; i--) { setPixelColor(SEGMENT.start + i, getPixelColor(SEGMENT.start + i - 1)); } @@ -975,7 +979,9 @@ uint16_t WS2812FX::mode_running_random(void) { { SEGENV.step = 0; } - return SPEED_FORMULA_L; + + SEGENV.aux1 = it; + return FRAMETIME; } @@ -1091,6 +1097,10 @@ uint16_t WS2812FX::mode_rain() * Fire flicker function */ uint16_t WS2812FX::mode_fire_flicker(void) { + uint32_t cycleTime = 40 + (255 - SEGMENT.speed); + uint32_t it = now / cycleTime; + if (SEGENV.step == it) return FRAMETIME; + byte w = (SEGCOLOR(0) >> 24) & 0xFF; byte r = (SEGCOLOR(0) >> 16) & 0xFF; byte g = (SEGCOLOR(0) >> 8) & 0xFF; @@ -1105,7 +1115,9 @@ uint16_t WS2812FX::mode_fire_flicker(void) { setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker)); } } - return 20 + random((255 - SEGMENT.speed),(2 * (uint16_t)(255 - SEGMENT.speed))); + + SEGENV.step = it; + return FRAMETIME; } @@ -1285,6 +1297,7 @@ uint16_t WS2812FX::mode_icu(void) { setPixelColor(SEGMENT.start + dest, col); setPixelColor(SEGMENT.start + dest + SEGLEN/2, col); + if (SEGMENT.intensity > 127) return FRAMETIME; return SPEED_FORMULA_L; } @@ -1294,6 +1307,11 @@ uint16_t WS2812FX::mode_icu(void) { */ uint16_t WS2812FX::mode_tricolor_wipe(void) { + uint32_t cycleTime = 40 + (3 * (uint32_t)(255 - SEGMENT.speed)); + uint32_t it = now / cycleTime; + if (SEGENV.step == it) return FRAMETIME; + uint8_t incr = it-SEGENV.step; + if(SEGENV.step < SEGLEN) { uint32_t led_offset = SEGENV.step; setPixelColor(SEGMENT.start + led_offset, SEGCOLOR(0)); @@ -1307,7 +1325,7 @@ uint16_t WS2812FX::mode_tricolor_wipe(void) } SEGENV.step = (SEGENV.step + 1) % (SEGLEN * 3); - return SPEED_FORMULA_L; + return FRAMETIME; } @@ -1318,6 +1336,9 @@ uint16_t WS2812FX::mode_tricolor_wipe(void) */ uint16_t WS2812FX::mode_tricolor_fade(void) { + uint16_t counter = now * ((SEGMENT.speed >> 3) +1); + SEGENV.step = (counter * 768) >> 16; + uint32_t color1 = 0, color2 = 0; byte stage = 0; @@ -1348,10 +1369,7 @@ uint16_t WS2812FX::mode_tricolor_fade(void) setPixelColor(i, color); } - SEGENV.step += 4; - if(SEGENV.step >= 768) SEGENV.step = 0; - - return 5 + ((uint32_t)(255 - SEGMENT.speed) / 10); + return FRAMETIME; } @@ -1361,6 +1379,10 @@ uint16_t WS2812FX::mode_tricolor_fade(void) */ uint16_t WS2812FX::mode_multi_comet(void) { + uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed)); + uint32_t it = now / cycleTime; + if (SEGENV.step == it) return FRAMETIME; + fade_out(SEGMENT.intensity); static uint16_t comets[] = {UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX}; @@ -1382,7 +1404,9 @@ uint16_t WS2812FX::mode_multi_comet(void) } } } - return SPEED_FORMULA_L; + + SEGENV.step = it; + return FRAMETIME; } @@ -2341,95 +2365,6 @@ uint16_t WS2812FX::mode_spots_fade() } -/* -* Bouncing Balls Effect -* Adapted from: https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ -*/ -uint16_t WS2812FX::mode_BouncingBalls(void) { - // number of balls based on intensity setting, - // only has 4 for a few of the higher settings as there is no colour selection - // fourth ball is a random colour - int balls = int(((SEGMENT.intensity * 6.2) / 255) + 1); - - // ideally use speed for gravity effect on the bounce - float Gravity = -9.81; - - const int maxBallCount = 7; - static float Height[maxBallCount]; - static float ImpactVelocity[maxBallCount]; - static int Position[maxBallCount]; - static float TimeSinceLastBounce[maxBallCount]; - static long ClockTimeSinceLastBounce[maxBallCount]; - static int StartHeight = 1; // height in metres (strip length) - static float Dampening[maxBallCount] = {0}; // Coefficient of Restitution (bounce damping) - static float ImpactVelocityStart=sqrt( -2 * Gravity * StartHeight); - - // Different from the examples, to allow for initialisation of the first bounce - if (Dampening[0] == 0) { - for (int i = 0 ; i < maxBallCount ; i++) { - ClockTimeSinceLastBounce[i] = millis(); - ImpactVelocity[i] = ImpactVelocityStart; - TimeSinceLastBounce[i] = 0; - Dampening[i] = 0.90 - float(i)/pow(maxBallCount,2); - } - } - - for (int i = 0 ; i < balls ; i++) { - TimeSinceLastBounce[i] = millis() - ClockTimeSinceLastBounce[i]; - Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000; - - if ( Height[i] < 0 ) { - Height[i] = 0; - ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i]; - ClockTimeSinceLastBounce[i] = millis(); - - if ( ImpactVelocity[i] < 0.01 ) { - ImpactVelocity[i] = ImpactVelocityStart; - } - } - Position[i] = round( Height[i] * (SEGLEN - 1) / StartHeight); - } - - fill(BLACK); - - for (int i = 0 ; i < balls ; i++) { - uint32_t color = SEGCOLOR(i % NUM_COLORS); - if (!color) { - color = color_wheel(random8()); - } - - setPixelColor(Position[i],color); - } - - return 20; -} - -/* -* Sinelon stolen from FASTLED examples -*/ -uint16_t WS2812FX::mode_sinelon(void) { - - fade_out(SEGMENT.intensity); - int pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1); - static int prevpos = 0; - - // setRange seems great to use, but doesn't work here for some reason - if( pos < prevpos ) { - for (uint16_t i = pos; i < prevpos; i++) - { - setPixelColor(i, color_from_palette(pos, false, false, 0)); - } - } else { - for (uint16_t i = prevpos; i < pos; i++) - { - setPixelColor(i, color_from_palette(pos, false, false, 0)); - } - } - prevpos = pos; - return FRAMETIME; -} - - //Rainbow with glitter, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6 uint16_t WS2812FX::mode_glitter() { @@ -2444,55 +2379,6 @@ uint16_t WS2812FX::mode_glitter() } -/* -* 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; -} - - //values close to 100 produce 5Hz flicker, which looks very candle-y //Inspired by https://github.com/avanhanegem/ArduinoCandleEffectNeoPixel //and https://cpldcpu.wordpress.com/2016/01/05/reverse-engineering-a-real-candle/