From fd6b12c6872deba2aab676544b68e283c060947b Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Fri, 8 Oct 2021 15:12:48 +0200
Subject: [PATCH 01/31] set hardware compilation constants
---
platformio.ini | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/platformio.ini b/platformio.ini
index 0a64a94c91..112f9a972f 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -12,7 +12,7 @@
; default_envs = travis_esp8266, travis_esp32
# Release binaries
-default_envs = nodemcuv2, esp01_1m_full, esp32dev, esp32_eth
+; default_envs = nodemcuv2, esp01_1m_full, esp32dev, esp32_eth
# Build everything
; default_envs = esp32dev, esp8285_4CH_MagicHome, esp8285_4CH_H801, codm-controller-0.6-rev2, codm-controller-0.6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, travis_esp8266, travis_esp32, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_5CH_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips
@@ -22,7 +22,7 @@ default_envs = nodemcuv2, esp01_1m_full, esp32dev, esp32_eth
; default_envs = nodemcuv2
; default_envs = esp01_1m_full
; default_envs = esp07
-; default_envs = d1_mini
+default_envs = d1_mini
; default_envs = heltec_wifi_kit_8
; default_envs = h803wf
; default_envs = d1_mini_debug
From db6b1b287ec70ff80cc4ab2d6e4f8d6a8dee177d Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Fri, 8 Oct 2021 15:15:51 +0200
Subject: [PATCH 02/31] add new custom effect 'Hive 51'
---
wled00/FX.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
wled00/FX.h | 10 +++++--
2 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 09cef83288..a03e2faca4 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4081,5 +4081,81 @@ uint16_t WS2812FX::mode_aurora(void) {
setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2]);
}
+ return FRAMETIME;
+}
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Random Strobing Segments
+ */
+uint16_t WS2812FX::mode_hive_51(void) {
+ const uint8_t N_LEDS_PER_EDGE = 10;
+
+ uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint16_t prog = (perc * 10) / cycleTime; // current progress in active cycle (0 = start, 65535 = end)
+
+ uint8_t nActiveEdges = SEGLEN / N_LEDS_PER_EDGE / 3; // set 1/3 of the edges to active
+ // check if active edges are set
+ if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
+ if(!SEGENV.allocateData(nActiveEdges)) {
+ // return if memory cannot be allocated
+ return 0;
+ }
+ }
+
+ bool isValidData = true;
+ if (SEGENV.step == prog) {
+ // do not update LEDs
+ for (uint8_t ii = 0; ii < nActiveEdges; ii ++) {
+ if (SEGENV.data[ii] > SEGLEN / N_LEDS_PER_EDGE - 1) {
+ isValidData = false;
+ ii = nActiveEdges;
+ break;
+ }
+ for (uint8_t jj = 0; jj < nActiveEdges; jj ++) {
+ if (ii != jj) {
+ if (SEGENV.data[ii] == SEGENV.data[jj]) {
+ isValidData = false;
+ ii = jj = nActiveEdges;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (SEGENV.step == (uint8_t) (prog - 1) || !isValidData) {
+ // update active segments to next random value
+ for (uint8_t ii = 0; ii < nActiveEdges ; ii++) {
+ bool duplicates;
+ do {
+ duplicates = false;
+ SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE - 1);
+ for (uint8_t jj = 0; jj < ii; jj++) {
+ if (SEGENV.data[ii] == SEGENV.data[jj]) {
+ duplicates = true;
+ break;
+ }
+ }
+ } while (duplicates);
+ }
+ }
+ else {
+ // this should not happen
+ return 0;
+ }
+
+ // set LED colors
+ for (uint16_t ii = 0; ii < SEGLEN; ii++) {
+ // set all LEDs to secondary color
+ setPixelColor(ii, BLACK);
+ }
+ for (uint8_t ii = 0; ii < sizeof(SEGENV.data); ii++) { // cycle through active edges
+ for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(SEGENV.data[ii] * N_LEDS_PER_EDGE + jj, WHITE);
+ }
+ }
+
+ SEGENV.step = prog; // update step counter
return FRAMETIME;
}
\ No newline at end of file
diff --git a/wled00/FX.h b/wled00/FX.h
index 19660a8871..d713575795 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -78,6 +78,7 @@
#define SEGCOLOR(x) _colors_t[x]
#define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength
+
#define SEGACT SEGMENT.stop
#define SPEED_FORMULA_L 5U + (50U*(255U - SEGMENT.speed))/SEGLEN
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
@@ -115,7 +116,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
-#define MODE_COUNT 118
+#define MODE_COUNT 119
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -235,6 +236,7 @@
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
+#define FX_MODE_HIVE_51 118
class WS2812FX {
@@ -608,6 +610,7 @@ class WS2812FX {
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
+ _mode[FX_MODE_HIVE_51] = &WS2812FX::mode_hive_51;
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@@ -823,7 +826,8 @@ class WS2812FX {
mode_candy_cane(void),
mode_blends(void),
mode_tv_simulator(void),
- mode_dynamic_smooth(void);
+ mode_dynamic_smooth(void),
+ mode_hive_51(void);
private:
uint32_t crgb_to_col(CRGB fastled);
@@ -916,7 +920,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
-"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth"
+"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Hive 51"
])=====";
From 2a0634d87b78c98b67c88f6aefd147f81c9c00ea Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Sat, 9 Oct 2021 02:19:06 +0200
Subject: [PATCH 03/31] Code Formatting, modified new effect
---
wled00/FX.cpp | 6096 +++++++++++++++++++++++++------------------------
1 file changed, 3087 insertions(+), 3009 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index a03e2faca4..da9fcc8930 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -33,664 +33,649 @@
* No blinking. Just plain old static light.
*/
uint16_t WS2812FX::mode_static(void) {
- fill(SEGCOLOR(0));
- return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
+ fill(SEGCOLOR(0));
+ return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
}
-
/*
* Blink/strobe function
* Alternate between color1 and color2
* if(strobe == true) then create a strobe effect
*/
uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) {
- uint32_t cycleTime = (255 - SEGMENT.speed)*20;
- uint32_t onTime = FRAMETIME;
- if (!strobe) onTime += ((cycleTime * SEGMENT.intensity) >> 8);
- cycleTime += FRAMETIME*2;
- uint32_t it = now / cycleTime;
- uint32_t rem = now % cycleTime;
-
- bool on = false;
- if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief
- || rem <= onTime) {
- on = true;
- }
-
- SEGENV.step = it; //save previous iteration
+ uint32_t cycleTime = (255 - SEGMENT.speed) * 20;
+ uint32_t onTime = FRAMETIME;
+ if (!strobe) onTime += ((cycleTime * SEGMENT.intensity) >> 8);
+ cycleTime += FRAMETIME * 2;
+ uint32_t it = now / cycleTime;
+ uint32_t rem = now % cycleTime;
+
+ bool on = false;
+ if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief
+ || rem <= onTime) {
+ on = true;
+ }
- uint32_t color = on ? color1 : color2;
- if (color == color1 && do_palette)
- {
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ SEGENV.step = it; //save previous iteration
+
+ uint32_t color = on ? color1 : color2;
+ if (color == color1 && do_palette) {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ }
+ } else {
+ fill(color);
}
- } else fill(color);
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Normal blinking. 50% on/off time.
*/
uint16_t WS2812FX::mode_blink(void) {
- return blink(SEGCOLOR(0), SEGCOLOR(1), false, true);
+ return blink(SEGCOLOR(0), SEGCOLOR(1), false, true);
}
-
/*
* Classic Blink effect. Cycling through the rainbow.
*/
uint16_t WS2812FX::mode_blink_rainbow(void) {
- return blink(color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), false, false);
+ return blink(color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), false, false);
}
-
/*
* Classic Strobe effect.
*/
uint16_t WS2812FX::mode_strobe(void) {
- return blink(SEGCOLOR(0), SEGCOLOR(1), true, true);
+ return blink(SEGCOLOR(0), SEGCOLOR(1), true, true);
}
-
/*
* Classic Strobe effect. Cycling through the rainbow.
*/
uint16_t WS2812FX::mode_strobe_rainbow(void) {
- return blink(color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), true, false);
+ return blink(color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), true, false);
}
-
/*
* Color wipe function
* LEDs are turned on (color1) in sequence, then turned off (color2) in sequence.
* if (bool rev == true) then LEDs are turned off in reverse order
*/
uint16_t WS2812FX::color_wipe(bool rev, bool useRandomColors) {
- uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150;
- uint32_t perc = now % cycleTime;
- uint16_t prog = (perc * 65535) / cycleTime;
- bool back = (prog > 32767);
- if (back) {
- prog -= 32767;
- if (SEGENV.step == 0) SEGENV.step = 1;
- } else {
- if (SEGENV.step == 2) SEGENV.step = 3; //trigger color change
- }
-
- if (useRandomColors) {
- if (SEGENV.call == 0) {
- SEGENV.aux0 = random8();
- SEGENV.step = 3;
- }
- if (SEGENV.step == 1) { //if flag set, change to new random color
- SEGENV.aux1 = get_random_wheel_index(SEGENV.aux0);
- SEGENV.step = 2;
- }
- if (SEGENV.step == 3) {
- SEGENV.aux0 = get_random_wheel_index(SEGENV.aux1);
- SEGENV.step = 0;
- }
- }
-
- uint16_t ledIndex = (prog * SEGLEN) >> 15;
- uint16_t rem = 0;
- rem = (prog * SEGLEN) * 2; //mod 0xFFFF
- rem /= (SEGMENT.intensity +1);
- if (rem > 255) rem = 255;
-
- uint32_t col1 = useRandomColors? color_wheel(SEGENV.aux1) : SEGCOLOR(1);
- for (uint16_t i = 0; i < SEGLEN; i++)
- {
- uint16_t index = (rev && back)? SEGLEN -1 -i : i;
- uint32_t col0 = useRandomColors? color_wheel(SEGENV.aux0) : color_from_palette(index, true, PALETTE_SOLID_WRAP, 0);
-
- if (i < ledIndex)
- {
- setPixelColor(index, back? col1 : col0);
- } else
- {
- setPixelColor(index, back? col0 : col1);
- if (i == ledIndex) setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, rem));
+ uint32_t cycleTime = 750 + (255 - SEGMENT.speed) * 150;
+ uint32_t perc = now % cycleTime;
+ uint16_t prog = (perc * 65535) / cycleTime;
+ bool back = (prog > 32767);
+ if (back) {
+ prog -= 32767;
+ if (SEGENV.step == 0) {
+ SEGENV.step = 1;
+ }
+ } else {
+ if (SEGENV.step == 2) {
+ SEGENV.step = 3; //trigger color change
+ }
+ }
+
+ if (useRandomColors) {
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = random8();
+ SEGENV.step = 3;
+ }
+ if (SEGENV.step == 1) { //if flag set, change to new random color
+ SEGENV.aux1 = get_random_wheel_index(SEGENV.aux0);
+ SEGENV.step = 2;
+ }
+ if (SEGENV.step == 3) {
+ SEGENV.aux0 = get_random_wheel_index(SEGENV.aux1);
+ SEGENV.step = 0;
+ }
+ }
+
+ uint16_t ledIndex = (prog * SEGLEN) >> 15;
+ uint16_t rem = 0;
+ rem = (prog * SEGLEN) * 2; //mod 0xFFFF
+ rem /= (SEGMENT.intensity + 1);
+ if (rem > 255) {
+ rem = 255;
}
- }
- return FRAMETIME;
-}
+ uint32_t col1 = useRandomColors ? color_wheel(SEGENV.aux1) : SEGCOLOR(1);
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint16_t index = (rev && back) ? SEGLEN - 1 - i : i;
+ uint32_t col0 = useRandomColors ? color_wheel(SEGENV.aux0) : color_from_palette(index, true, PALETTE_SOLID_WRAP, 0);
+
+ if (i < ledIndex) {
+ setPixelColor(index, back ? col1 : col0);
+ } else {
+ setPixelColor(index, back ? col0 : col1);
+ if (i == ledIndex) {
+ setPixelColor(index, color_blend(back ? col0 : col1, back ? col1 : col0, rem));
+ }
+ }
+ }
+ return FRAMETIME;
+}
/*
* Lights all LEDs one after another.
*/
uint16_t WS2812FX::mode_color_wipe(void) {
- return color_wipe(false, false);
+ return color_wipe(false, false);
}
/*
* Lights all LEDs one after another. Turns off opposite
*/
uint16_t WS2812FX::mode_color_sweep(void) {
- return color_wipe(true, false);
+ return color_wipe(true, false);
}
-
/*
* Turns all LEDs after each other to a random color.
* Then starts over with another color.
*/
uint16_t WS2812FX::mode_color_wipe_random(void) {
- return color_wipe(false, true);
+ return color_wipe(false, true);
}
-
/*
* Random color introduced alternating from start and end of strip.
*/
uint16_t WS2812FX::mode_color_sweep_random(void) {
- return color_wipe(true, true);
+ return color_wipe(true, true);
}
-
/*
* Lights all LEDs in one random color up. Then switches them
* to the next random color.
*/
uint16_t WS2812FX::mode_random_color(void) {
- uint32_t cycleTime = 200 + (255 - SEGMENT.speed)*50;
- uint32_t it = now / cycleTime;
- uint32_t rem = now % cycleTime;
- uint16_t fadedur = (cycleTime * SEGMENT.intensity) >> 8;
-
- uint32_t fade = 255;
- if (fadedur) {
- fade = (rem * 255) / fadedur;
- if (fade > 255) fade = 255;
- }
-
- if (SEGENV.call == 0) {
- SEGENV.aux0 = random8();
- SEGENV.step = 2;
- }
- if (it != SEGENV.step) //new color
- {
- SEGENV.aux1 = SEGENV.aux0;
- SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
- SEGENV.step = it;
- }
+ uint32_t cycleTime = 200 + (255 - SEGMENT.speed) * 50;
+ uint32_t it = now / cycleTime;
+ uint32_t rem = now % cycleTime;
+ uint16_t fadedur = (cycleTime * SEGMENT.intensity) >> 8;
+
+ uint32_t fade = 255;
+ if (fadedur) {
+ fade = (rem * 255) / fadedur;
+ if (fade > 255) {
+ fade = 255;
+ }
+ }
- fill(color_blend(color_wheel(SEGENV.aux1), color_wheel(SEGENV.aux0), fade));
- return FRAMETIME;
-}
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = random8();
+ SEGENV.step = 2;
+ }
+ if (it != SEGENV.step) //new color
+ {
+ SEGENV.aux1 = SEGENV.aux0;
+ SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
+ SEGENV.step = it;
+ }
+ fill(color_blend(color_wheel(SEGENV.aux1), color_wheel(SEGENV.aux0), fade));
+ return FRAMETIME;
+}
/*
* Lights every LED in a random color. Changes all LED at the same time
* to new random colors.
*/
-uint16_t WS2812FX::dynamic(boolean smooth=false) {
- if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
-
- if(SEGENV.call == 0) {
- for (uint16_t i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8();
- }
-
- uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15;
- uint32_t it = now / cycleTime;
- if (it != SEGENV.step && SEGMENT.speed != 0) //new color
- {
- for (uint16_t i = 0; i < SEGLEN; i++) {
- if (random8() <= SEGMENT.intensity) SEGENV.data[i] = random8();
+uint16_t WS2812FX::dynamic(boolean smooth = false) {
+ if (!SEGENV.allocateData(SEGLEN)) {
+ return mode_static(); //allocation failed
}
- SEGENV.step = it;
- }
-
- if (smooth) {
- for (uint16_t i = 0; i < SEGLEN; i++) {
- blendPixelColor(i, color_wheel(SEGENV.data[i]),16);
+
+ if (SEGENV.call == 0) {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ SEGENV.data[i] = random8();
+ }
}
- } else {
- for (uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_wheel(SEGENV.data[i]));
+
+ uint32_t cycleTime = 50 + (255 - SEGMENT.speed) * 15;
+ uint32_t it = now / cycleTime;
+ if (it != SEGENV.step && SEGMENT.speed != 0) //new color
+ {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (random8() <= SEGMENT.intensity) {
+ SEGENV.data[i] = random8();
+ }
+ }
+ SEGENV.step = it;
+ }
+
+ if (smooth) {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ blendPixelColor(i, color_wheel(SEGENV.data[i]), 16);
+ }
+ } else {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_wheel(SEGENV.data[i]));
+ }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
/*
* Original effect "Dynamic"
*/
uint16_t WS2812FX::mode_dynamic(void) {
- return dynamic(false);
+ return dynamic(false);
}
/*
* effect "Dynamic" with smoth color-fading
*/
uint16_t WS2812FX::mode_dynamic_smooth(void) {
- return dynamic(true);
- }
+ return dynamic(true);
+}
/*
* Does the "standby-breathing" of well known i-Devices.
*/
uint16_t WS2812FX::mode_breath(void) {
- uint16_t var = 0;
- uint16_t counter = (now * ((SEGMENT.speed >> 3) +10));
- counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048
- if (counter < 16384) {
- if (counter > 8192) counter = 8192 - (counter - 8192);
- var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170
- }
-
- uint8_t lum = 30 + var;
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum));
- }
+ uint16_t var = 0;
+ uint16_t counter = (now * ((SEGMENT.speed >> 3) + 10));
+ counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048
+ if (counter < 16384) {
+ if (counter > 8192) {
+ counter = 8192 - (counter - 8192);
+ }
+ var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170
+ }
- return FRAMETIME;
-}
+ uint8_t lum = 30 + var;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum));
+ }
+ return FRAMETIME;
+}
/*
* Fades the LEDs between two colors
*/
uint16_t WS2812FX::mode_fade(void) {
- uint16_t counter = (now * ((SEGMENT.speed >> 3) +10));
- uint8_t lum = triwave16(counter) >> 8;
+ uint16_t counter = (now * ((SEGMENT.speed >> 3) + 10));
+ uint8_t lum = triwave16(counter) >> 8;
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum));
- }
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum));
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Scan mode parent function
*/
-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 size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9);
- uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16;
+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 size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9);
+ uint16_t ledIndex = (prog * ((SEGLEN * 2) - size * 2)) >> 16;
- fill(SEGCOLOR(1));
+ fill(SEGCOLOR(1));
- int led_offset = ledIndex - (SEGLEN - size);
- led_offset = abs(led_offset);
+ int led_offset = ledIndex - (SEGLEN - size);
+ led_offset = abs(led_offset);
- if (dual) {
- for (uint16_t j = led_offset; j < led_offset + size; j++) {
- uint16_t i2 = SEGLEN -1 -j;
- setPixelColor(i2, color_from_palette(i2, true, PALETTE_SOLID_WRAP, (SEGCOLOR(2))? 2:0));
+ if (dual) {
+ for (uint16_t j = led_offset; j < led_offset + size; j++) {
+ uint16_t i2 = SEGLEN - 1 - j;
+ setPixelColor(i2, color_from_palette(i2, true, PALETTE_SOLID_WRAP, (SEGCOLOR(2)) ? 2 : 0));
+ }
}
- }
- for (uint16_t j = led_offset; j < led_offset + size; j++) {
- setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0));
- }
+ for (uint16_t j = led_offset; j < led_offset + size; j++) {
+ setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0));
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Runs a single pixel back and forth.
*/
uint16_t WS2812FX::mode_scan(void) {
- return scan(false);
+ return scan(false);
}
-
/*
* Runs two pixel back and forth in opposite directions.
*/
uint16_t WS2812FX::mode_dual_scan(void) {
- return scan(true);
+ return scan(true);
}
-
/*
* Cycles all LEDs at once through a rainbow.
*/
uint16_t WS2812FX::mode_rainbow(void) {
- uint16_t counter = (now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF;
- counter = counter >> 8;
+ uint16_t counter = (now * ((SEGMENT.speed >> 2) + 2)) & 0xFFFF;
+ counter = counter >> 8;
- if (SEGMENT.intensity < 128){
- fill(color_blend(color_wheel(counter),WHITE,128-SEGMENT.intensity));
- } else {
- fill(color_wheel(counter));
- }
+ if (SEGMENT.intensity < 128) {
+ fill(color_blend(color_wheel(counter), WHITE, 128 - SEGMENT.intensity));
+ } else {
+ fill(color_wheel(counter));
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Cycles a rainbow over the entire string of LEDs.
*/
uint16_t WS2812FX::mode_rainbow_cycle(void) {
- uint16_t counter = (now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF;
- counter = counter >> 8;
-
- for(uint16_t i = 0; i < SEGLEN; i++) {
- //intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16)
- uint8_t index = (i * (16 << (SEGMENT.intensity /29)) / SEGLEN) + counter;
- setPixelColor(i, color_wheel(index));
- }
+ uint16_t counter = (now * ((SEGMENT.speed >> 2) + 2)) & 0xFFFF;
+ counter = counter >> 8;
- return FRAMETIME;
-}
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ //intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16)
+ uint8_t index = (i * (16 << (SEGMENT.intensity / 29)) / SEGLEN) + counter;
+ setPixelColor(i, color_wheel(index));
+ }
+ return FRAMETIME;
+}
/*
* Theatre-style crawling lights.
* Inspired by the Adafruit examples.
*/
uint16_t WS2812FX::mode_theater_chase(void) {
- return running(SEGCOLOR(0), SEGCOLOR(1), true);
+ return running(SEGCOLOR(0), SEGCOLOR(1), true);
}
-
/*
* Theatre-style crawling lights with rainbow effect.
* Inspired by the Adafruit examples.
*/
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
- return running(color_wheel(SEGENV.step), SEGCOLOR(1), true);
+ return running(color_wheel(SEGENV.step), SEGCOLOR(1), true);
}
-
/*
* Running lights effect with smooth sine transition base.
*/
-uint16_t WS2812FX::running_base(bool saw, bool dual=false) {
- uint8_t x_scale = SEGMENT.intensity >> 2;
- uint32_t counter = (now * SEGMENT.speed) >> 9;
-
- for(uint16_t i = 0; i < SEGLEN; i++) {
- uint16_t a = i*x_scale - counter;
- if (saw) {
- a &= 0xFF;
- if (a < 16)
- {
- a = 192 + a*8;
- } else {
- a = map(a,16,255,64,192);
- }
- a = 255 - a;
- }
- uint8_t s = dual ? sin_gap(a) : sin8(a);
- uint32_t ca = color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s);
- if (dual) {
- uint16_t b = (SEGLEN-1-i)*x_scale - counter;
- uint8_t t = sin_gap(b);
- uint32_t cb = color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t);
- ca = color_blend(ca, cb, 127);
+uint16_t WS2812FX::running_base(bool saw, bool dual = false) {
+ uint8_t x_scale = SEGMENT.intensity >> 2;
+ uint32_t counter = (now * SEGMENT.speed) >> 9;
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint16_t a = i * x_scale - counter;
+ if (saw) {
+ a &= 0xFF;
+ if (a < 16) {
+ a = 192 + a * 8;
+ } else {
+ a = map(a, 16, 255, 64, 192);
+ }
+ a = 255 - a;
+ }
+ uint8_t s = dual ? sin_gap(a) : sin8(a);
+ uint32_t ca = color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s);
+ if (dual) {
+ uint16_t b = (SEGLEN - 1 - i) * x_scale - counter;
+ uint8_t t = sin_gap(b);
+ uint32_t cb = color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t);
+ ca = color_blend(ca, cb, 127);
+ }
+ setPixelColor(i, ca);
}
- setPixelColor(i, ca);
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Running lights in opposite directions.
* Idea: Make the gap width controllable with a third slider in the future
*/
uint16_t WS2812FX::mode_running_dual(void) {
- return running_base(false, true);
+ return running_base(false, true);
}
-
/*
* Running lights effect with smooth sine transition.
*/
uint16_t WS2812FX::mode_running_lights(void) {
- return running_base(false);
+ return running_base(false);
}
-
/*
* Running lights effect with sawtooth transition.
*/
uint16_t WS2812FX::mode_saw(void) {
- return running_base(true);
+ return running_base(true);
}
-
/*
* Blink several LEDs in random colors on, reset, repeat.
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/
uint16_t WS2812FX::mode_twinkle(void) {
- fill(SEGCOLOR(1));
-
- uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5;
- uint32_t it = now / cycleTime;
- if (it != SEGENV.step)
- {
- uint16_t maxOn = map(SEGMENT.intensity, 0, 255, 1, SEGLEN); // make sure at least one LED is on
- if (SEGENV.aux0 >= maxOn)
- {
- SEGENV.aux0 = 0;
- SEGENV.aux1 = random16(); //new seed for our PRNG
+ fill(SEGCOLOR(1));
+
+ uint32_t cycleTime = 20 + (255 - SEGMENT.speed) * 5;
+ uint32_t it = now / cycleTime;
+ if (it != SEGENV.step) {
+ uint16_t maxOn = map(SEGMENT.intensity, 0, 255, 1, SEGLEN); // make sure at least one LED is on
+ if (SEGENV.aux0 >= maxOn) {
+ SEGENV.aux0 = 0;
+ SEGENV.aux1 = random16(); //new seed for our PRNG
+ }
+ SEGENV.aux0++;
+ SEGENV.step = it;
}
- SEGENV.aux0++;
- SEGENV.step = it;
- }
-
- uint16_t PRNG16 = SEGENV.aux1;
- for (uint16_t i = 0; i < SEGENV.aux0; i++)
- {
- PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next 'random' number
- uint32_t p = (uint32_t)SEGLEN * (uint32_t)PRNG16;
- uint16_t j = p >> 16;
- setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0));
- }
+ uint16_t PRNG16 = SEGENV.aux1;
- return FRAMETIME;
-}
+ for (uint16_t i = 0; i < SEGENV.aux0; i++) {
+ PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next 'random' number
+ uint32_t p = (uint32_t)SEGLEN * (uint32_t)PRNG16;
+ uint16_t j = p >> 16;
+ setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0));
+ }
+ return FRAMETIME;
+}
/*
* Dissolve function
*/
uint16_t WS2812FX::dissolve(uint32_t color) {
- bool wa = (SEGCOLOR(1) != 0 && _brightness < 255); //workaround, can't compare getPixel to color if not full brightness
-
- for (uint16_t j = 0; j <= SEGLEN / 15; j++)
- {
- if (random8() <= SEGMENT.intensity) {
- for (uint8_t times = 0; times < 10; times++) //attempt to spawn a new pixel 5 times
- {
- uint16_t i = random16(SEGLEN);
- if (SEGENV.aux0) { //dissolve to primary/palette
- if (getPixelColor(i) == SEGCOLOR(1) || wa) {
- if (color == SEGCOLOR(0))
+ bool wa = (SEGCOLOR(1) != 0 && _brightness < 255); //workaround, can't compare getPixel to color if not full brightness
+
+ for (uint16_t j = 0; j <= SEGLEN / 15; j++) {
+ if (random8() <= SEGMENT.intensity) {
+ for (uint8_t times = 0; times < 10; times++) //attempt to spawn a new pixel 5 times
{
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- } else { setPixelColor(i, color); }
- break; //only spawn 1 new pixel per frame per 50 LEDs
- }
- } else { //dissolve to secondary
- if (getPixelColor(i) != SEGCOLOR(1)) { setPixelColor(i, SEGCOLOR(1)); break; }
+ uint16_t i = random16(SEGLEN);
+ if (SEGENV.aux0) { //dissolve to primary/palette
+ if (getPixelColor(i) == SEGCOLOR(1) || wa) {
+ if (color == SEGCOLOR(0)) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ } else {
+ setPixelColor(i, color);
+ }
+ break; //only spawn 1 new pixel per frame per 50 LEDs
+ }
+ } else { //dissolve to secondary
+ if (getPixelColor(i) != SEGCOLOR(1)) {
+ setPixelColor(i, SEGCOLOR(1));
+ break;
+ }
+ }
+ }
}
- }
}
- }
- if (SEGENV.call > (255 - SEGMENT.speed) + 15U)
- {
- SEGENV.aux0 = !SEGENV.aux0;
- SEGENV.call = 0;
- }
-
- return FRAMETIME;
-}
+ if (SEGENV.call > (255 - SEGMENT.speed) + 15U) {
+ SEGENV.aux0 = !SEGENV.aux0;
+ SEGENV.call = 0;
+ }
+ return FRAMETIME;
+}
/*
* Blink several LEDs on and then off
*/
uint16_t WS2812FX::mode_dissolve(void) {
- return dissolve(SEGCOLOR(0));
+ return dissolve(SEGCOLOR(0));
}
-
/*
* Blink several LEDs on and then off in random colors
*/
uint16_t WS2812FX::mode_dissolve_random(void) {
- return dissolve(color_wheel(random8()));
+ return dissolve(color_wheel(random8()));
}
-
/*
* Blinks one LED at a time.
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/
uint16_t WS2812FX::mode_sparkle(void) {
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
- }
- uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2;
- uint32_t it = now / cycleTime;
- if (it != SEGENV.step)
- {
- SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index
- SEGENV.step = it;
- }
-
- setPixelColor(SEGENV.aux0, SEGCOLOR(0));
- return FRAMETIME;
-}
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
+ }
+ uint32_t cycleTime = 10 + (255 - SEGMENT.speed) * 2;
+ uint32_t it = now / cycleTime;
+ if (it != SEGENV.step) {
+ SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index
+ SEGENV.step = it;
+ }
+ setPixelColor(SEGENV.aux0, SEGCOLOR(0));
+ return FRAMETIME;
+}
/*
* Lights all LEDs in the color. Flashes single col 1 pixels randomly. (List name: Sparkle Dark)
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/
uint16_t WS2812FX::mode_flash_sparkle(void) {
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- }
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ }
- if (now - SEGENV.aux0 > SEGENV.step) {
- if(random8((255-SEGMENT.intensity) >> 4) == 0) {
- setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
+ if (now - SEGENV.aux0 > SEGENV.step) {
+ if (random8((255 - SEGMENT.intensity) >> 4) == 0) {
+ setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
+ }
+ SEGENV.step = now;
+ SEGENV.aux0 = 255 - SEGMENT.speed;
}
- SEGENV.step = now;
- SEGENV.aux0 = 255-SEGMENT.speed;
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Like flash sparkle. With more flash.
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/
uint16_t WS2812FX::mode_hyper_sparkle(void) {
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- }
-
- if (now - SEGENV.aux0 > SEGENV.step) {
- if(random8((255-SEGMENT.intensity) >> 4) == 0) {
- for(uint16_t i = 0; i < MAX(1, SEGLEN/3); i++) {
- setPixelColor(random16(SEGLEN), SEGCOLOR(1));
- }
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
}
- SEGENV.step = now;
- SEGENV.aux0 = 255-SEGMENT.speed;
- }
- return FRAMETIME;
-}
+ if (now - SEGENV.aux0 > SEGENV.step) {
+ if (random8((255 - SEGMENT.intensity) >> 4) == 0) {
+ for (uint16_t i = 0; i < MAX(1, SEGLEN / 3); i++) {
+ setPixelColor(random16(SEGLEN), SEGCOLOR(1));
+ }
+ }
+ SEGENV.step = now;
+ SEGENV.aux0 = 255 - SEGMENT.speed;
+ }
+ return FRAMETIME;
+}
/*
* Strobe effect with different strobe count and pause, controlled by speed.
*/
uint16_t WS2812FX::mode_multi_strobe(void) {
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
- }
-
- SEGENV.aux0 = 50 + 20*(uint16_t)(255-SEGMENT.speed);
- uint16_t count = 2 * ((SEGMENT.intensity / 10) + 1);
- if(SEGENV.aux1 < count) {
- if((SEGENV.aux1 & 1) == 0) {
- fill(SEGCOLOR(0));
- SEGENV.aux0 = 15;
- } else {
- SEGENV.aux0 = 50;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
+ }
+
+ SEGENV.aux0 = 50 + 20 * (uint16_t)(255 - SEGMENT.speed);
+ uint16_t count = 2 * ((SEGMENT.intensity / 10) + 1);
+ if (SEGENV.aux1 < count) {
+ if ((SEGENV.aux1 & 1) == 0) {
+ fill(SEGCOLOR(0));
+ SEGENV.aux0 = 15;
+ } else {
+ SEGENV.aux0 = 50;
+ }
}
- }
- if (now - SEGENV.aux0 > SEGENV.step) {
- SEGENV.aux1++;
- if (SEGENV.aux1 > count) SEGENV.aux1 = 0;
- SEGENV.step = now;
- }
+ if (now - SEGENV.aux0 > SEGENV.step) {
+ SEGENV.aux1++;
+ if (SEGENV.aux1 > count) {
+ SEGENV.aux1 = 0;
+ }
+ SEGENV.step = now;
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
/*
* Android loading circle
*/
uint16_t WS2812FX::mode_android(void) {
-
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
- }
-
- if (SEGENV.aux1 > ((float)SEGMENT.intensity/255.0)*(float)SEGLEN)
- {
- SEGENV.aux0 = 1;
- } else
- {
- if (SEGENV.aux1 < 2) SEGENV.aux0 = 0;
- }
-
- uint16_t a = SEGENV.step;
-
- if (SEGENV.aux0 == 0)
- {
- if (SEGENV.call %3 == 1) {a++;}
- else {SEGENV.aux1++;}
- } else
- {
- a++;
- if (SEGENV.call %3 != 1) SEGENV.aux1--;
- }
-
- if (a >= SEGLEN) a = 0;
-
- if (a + SEGENV.aux1 < SEGLEN)
- {
- for(int i = a; i < a+SEGENV.aux1; i++) {
- setPixelColor(i, SEGCOLOR(0));
- }
- } else
- {
- for(int i = a; i < SEGLEN; i++) {
- setPixelColor(i, SEGCOLOR(0));
- }
- for(int i = 0; i < SEGENV.aux1 - (SEGLEN -a); i++) {
- setPixelColor(i, SEGCOLOR(0));
- }
- }
- SEGENV.step = a;
-
- return 3 + ((8 * (uint32_t)(255 - SEGMENT.speed)) / SEGLEN);
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
+ }
+
+ if (SEGENV.aux1 > ((float)SEGMENT.intensity / 255.0) * (float)SEGLEN) {
+ SEGENV.aux0 = 1;
+ } else {
+ if (SEGENV.aux1 < 2) {
+ SEGENV.aux0 = 0;
+ }
+ }
+
+ uint16_t a = SEGENV.step;
+
+ if (SEGENV.aux0 == 0) {
+ if (SEGENV.call % 3 == 1) {
+ a++;
+ } else {
+ SEGENV.aux1++;
+ }
+ } else {
+ a++;
+ if (SEGENV.call % 3 != 1) {
+ SEGENV.aux1--;
+ }
+ }
+
+ if (a >= SEGLEN) {
+ a = 0;
+ }
+
+ if (a + SEGENV.aux1 < SEGLEN) {
+ for (int i = a; i < a + SEGENV.aux1; i++) {
+ setPixelColor(i, SEGCOLOR(0));
+ }
+ } else {
+ for (int i = a; i < SEGLEN; i++) {
+ setPixelColor(i, SEGCOLOR(0));
+ }
+ for (int i = 0; i < SEGENV.aux1 - (SEGLEN - a); i++) {
+ setPixelColor(i, SEGCOLOR(0));
+ }
+ }
+ SEGENV.step = a;
+
+ return 3 + ((8 * (uint32_t)(255 - SEGMENT.speed)) / SEGLEN);
}
/*
@@ -699,992 +684,1014 @@ uint16_t WS2812FX::mode_android(void) {
* color2 and color3 = colors of two adjacent leds
*/
uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palette) {
- uint16_t counter = now * ((SEGMENT.speed >> 2) + 1);
- uint16_t a = counter * SEGLEN >> 16;
+ uint16_t counter = now * ((SEGMENT.speed >> 2) + 1);
+ uint16_t a = counter * SEGLEN >> 16;
- bool chase_random = (SEGMENT.mode == FX_MODE_CHASE_RANDOM);
- if (chase_random) {
- if (a < SEGENV.step) //we hit the start again, choose new color for Chase random
- {
- SEGENV.aux1 = SEGENV.aux0; //store previous random color
- SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
- }
- color1 = color_wheel(SEGENV.aux0);
- }
- SEGENV.step = a;
-
- // Use intensity setting to vary chase up to 1/2 string length
- uint8_t size = 1 + (SEGMENT.intensity * SEGLEN >> 10);
-
- uint16_t b = a + size; //"trail" of chase, filled with color1
- if (b > SEGLEN) b -= SEGLEN;
- uint16_t c = b + size;
- if (c > SEGLEN) c -= SEGLEN;
-
- //background
- if (do_palette)
- {
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
- }
- } else fill(color1);
-
- //if random, fill old background between a and end
- if (chase_random)
- {
- color1 = color_wheel(SEGENV.aux1);
- for (uint16_t i = a; i < SEGLEN; i++)
- setPixelColor(i, color1);
- }
-
- //fill between points a and b with color2
- if (a < b)
- {
- for (uint16_t i = a; i < b; i++)
- setPixelColor(i, color2);
- } else {
- for (uint16_t i = a; i < SEGLEN; i++) //fill until end
- setPixelColor(i, color2);
- for (uint16_t i = 0; i < b; i++) //fill from start until b
- setPixelColor(i, color2);
- }
-
- //fill between points b and c with color2
- if (b < c)
- {
- for (uint16_t i = b; i < c; i++)
- setPixelColor(i, color3);
- } else {
- for (uint16_t i = b; i < SEGLEN; i++) //fill until end
- setPixelColor(i, color3);
- for (uint16_t i = 0; i < c; i++) //fill from start until c
- setPixelColor(i, color3);
- }
-
- return FRAMETIME;
-}
+ bool chase_random = (SEGMENT.mode == FX_MODE_CHASE_RANDOM);
+ if (chase_random) {
+ if (a < SEGENV.step) //we hit the start again, choose new color for Chase random
+ {
+ SEGENV.aux1 = SEGENV.aux0; //store previous random color
+ SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
+ }
+ color1 = color_wheel(SEGENV.aux0);
+ }
+ SEGENV.step = a;
+
+ // Use intensity setting to vary chase up to 1/2 string length
+ uint8_t size = 1 + (SEGMENT.intensity * SEGLEN >> 10);
+
+ uint16_t b = a + size; //"trail" of chase, filled with color1
+ if (b > SEGLEN) {
+ b -= SEGLEN;
+ }
+ uint16_t c = b + size;
+ if (c > SEGLEN) {
+ c -= SEGLEN;
+ }
+
+ //background
+ if (do_palette) {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
+ }
+ } else {
+ fill(color1);
+ }
+
+ //if random, fill old background between a and end
+ if (chase_random) {
+ color1 = color_wheel(SEGENV.aux1);
+ for (uint16_t i = a; i < SEGLEN; i++) {
+ setPixelColor(i, color1);
+ }
+ }
+
+ //fill between points a and b with color2
+ if (a < b) {
+ for (uint16_t i = a; i < b; i++) {
+ setPixelColor(i, color2);
+ }
+ } else {
+ for (uint16_t i = a; i < SEGLEN; i++) //fill until end
+ setPixelColor(i, color2);
+ for (uint16_t i = 0; i < b; i++) //fill from start until b
+ setPixelColor(i, color2);
+ }
+
+ //fill between points b and c with color2
+ if (b < c) {
+ for (uint16_t i = b; i < c; i++) {
+ setPixelColor(i, color3);
+ }
+ } else {
+ for (uint16_t i = b; i < SEGLEN; i++) //fill until end
+ setPixelColor(i, color3);
+ for (uint16_t i = 0; i < c; i++) //fill from start until c
+ setPixelColor(i, color3);
+ }
+ return FRAMETIME;
+}
/*
* Bicolor chase, more primary color.
*/
uint16_t WS2812FX::mode_chase_color(void) {
- return chase(SEGCOLOR(1), (SEGCOLOR(2)) ? SEGCOLOR(2) : SEGCOLOR(0), SEGCOLOR(0), true);
+ return chase(SEGCOLOR(1), (SEGCOLOR(2)) ? SEGCOLOR(2) : SEGCOLOR(0), SEGCOLOR(0), true);
}
-
/*
* Primary running followed by random color.
*/
uint16_t WS2812FX::mode_chase_random(void) {
- return chase(SEGCOLOR(1), (SEGCOLOR(2)) ? SEGCOLOR(2) : SEGCOLOR(0), SEGCOLOR(0), false);
+ return chase(SEGCOLOR(1), (SEGCOLOR(2)) ? SEGCOLOR(2) : SEGCOLOR(0), SEGCOLOR(0), false);
}
-
/*
* Primary, secondary running on rainbow.
*/
uint16_t WS2812FX::mode_chase_rainbow(void) {
- uint8_t color_sep = 256 / SEGLEN;
- if (color_sep == 0) color_sep = 1; // correction for segments longer than 256 LEDs
- uint8_t color_index = SEGENV.call & 0xFF;
- uint32_t color = color_wheel(((SEGENV.step * color_sep) + color_index) & 0xFF);
+ uint8_t color_sep = 256 / SEGLEN;
+ if (color_sep == 0) {
+ color_sep = 1; // correction for segments longer than 256 LEDs
+ }
+ uint8_t color_index = SEGENV.call & 0xFF;
+ uint32_t color = color_wheel(((SEGENV.step * color_sep) + color_index) & 0xFF);
- return chase(color, SEGCOLOR(0), SEGCOLOR(1), false);
+ return chase(color, SEGCOLOR(0), SEGCOLOR(1), false);
}
-
/*
* Primary running on rainbow.
*/
uint16_t WS2812FX::mode_chase_rainbow_white(void) {
- uint16_t n = SEGENV.step;
- uint16_t m = (SEGENV.step + 1) % SEGLEN;
- uint32_t color2 = color_wheel(((n * 256 / SEGLEN) + (SEGENV.call & 0xFF)) & 0xFF);
- uint32_t color3 = color_wheel(((m * 256 / SEGLEN) + (SEGENV.call & 0xFF)) & 0xFF);
+ uint16_t n = SEGENV.step;
+ uint16_t m = (SEGENV.step + 1) % SEGLEN;
+ uint32_t color2 = color_wheel(((n * 256 / SEGLEN) + (SEGENV.call & 0xFF)) & 0xFF);
+ uint32_t color3 = color_wheel(((m * 256 / SEGLEN) + (SEGENV.call & 0xFF)) & 0xFF);
- return chase(SEGCOLOR(0), color2, color3, false);
+ return chase(SEGCOLOR(0), color2, color3, false);
}
-
/*
* Red - Amber - Green - Blue lights running
*/
uint16_t WS2812FX::mode_colorful(void) {
- uint8_t numColors = 4; //3, 4, or 5
- uint32_t cols[9]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC};
- if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color
- if (!SEGMENT.palette) {
- numColors = 3;
- for (uint8_t i = 0; i < 3; i++) cols[i] = SEGCOLOR(i);
- } else {
- uint16_t fac = 80;
- if (SEGMENT.palette == 52) {numColors = 5; fac = 61;} //C9 2 has 5 colors
- for (uint8_t i = 0; i < numColors; i++) {
- cols[i] = color_from_palette(i*fac, false, true, 255);
- }
+ uint8_t numColors = 4; //3, 4, or 5
+ uint32_t cols[9]{0x00FF0000, 0x00EEBB00, 0x0000EE00, 0x000077CC};
+ if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color
+ if (!SEGMENT.palette) {
+ numColors = 3;
+ for (uint8_t i = 0; i < 3; i++) {
+ cols[i] = SEGCOLOR(i);
+ }
+ } else {
+ uint16_t fac = 80;
+ if (SEGMENT.palette == 52) {
+ numColors = 5;
+ fac = 61;
+ } //C9 2 has 5 colors
+ for (uint8_t i = 0; i < numColors; i++) {
+ cols[i] = color_from_palette(i * fac, false, true, 255);
+ }
+ }
+ } else if (SEGMENT.intensity < 80) //pastel (easter) colors
+ {
+ cols[0] = 0x00FF8040;
+ cols[1] = 0x00E5D241;
+ cols[2] = 0x0077FF77;
+ cols[3] = 0x0077F0F0;
+ }
+ for (uint8_t i = numColors; i < numColors * 2 - 1; i++) {
+ cols[i] = cols[i - numColors];
}
- } else if (SEGMENT.intensity < 80) //pastel (easter) colors
- {
- cols[0] = 0x00FF8040;
- cols[1] = 0x00E5D241;
- cols[2] = 0x0077FF77;
- cols[3] = 0x0077F0F0;
- }
- for (uint8_t i = numColors; i < numColors*2 -1; i++) cols[i] = cols[i-numColors];
-
- uint32_t cycleTime = 50 + (8 * (uint32_t)(255 - SEGMENT.speed));
- uint32_t it = now / cycleTime;
- if (it != SEGENV.step)
- {
- if (SEGMENT.speed > 0) SEGENV.aux0++;
- if (SEGENV.aux0 >= numColors) SEGENV.aux0 = 0;
- SEGENV.step = it;
- }
-
- for (uint16_t i = 0; i < SEGLEN; i+= numColors)
- {
- for (uint16_t j = 0; j < numColors; j++) setPixelColor(i + j, cols[SEGENV.aux0 + j]);
- }
-
- return FRAMETIME;
-}
+ uint32_t cycleTime = 50 + (8 * (uint32_t)(255 - SEGMENT.speed));
+ uint32_t it = now / cycleTime;
+ if (it != SEGENV.step) {
+ if (SEGMENT.speed > 0) {
+ SEGENV.aux0++;
+ }
+ if (SEGENV.aux0 >= numColors) {
+ SEGENV.aux0 = 0;
+ }
+ SEGENV.step = it;
+ }
+
+ for (uint16_t i = 0; i < SEGLEN; i += numColors) {
+ for (uint16_t j = 0; j < numColors; j++) {
+ setPixelColor(i + j, cols[SEGENV.aux0 + j]);
+ }
+ }
+
+ return FRAMETIME;
+}
/*
* Emulates a traffic light.
*/
uint16_t WS2812FX::mode_traffic_light(void) {
- for(uint16_t i=0; i < SEGLEN; i++)
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
- uint32_t mdelay = 500;
- for (int i = 0; i < SEGLEN-2 ; i+=3)
- {
- switch (SEGENV.aux0)
- {
- case 0: setPixelColor(i, 0x00FF0000); mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));break;
- case 1: setPixelColor(i, 0x00FF0000); mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed)); setPixelColor(i+1, 0x00EECC00); break;
- case 2: setPixelColor(i+2, 0x0000FF00); mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));break;
- case 3: setPixelColor(i+1, 0x00EECC00); mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed));break;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
+ }
+ uint32_t mdelay = 500;
+ for (int i = 0; i < SEGLEN - 2; i += 3) {
+ switch (SEGENV.aux0) {
+ case 0:
+ setPixelColor(i, 0x00FF0000);
+ mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));
+ break;
+ case 1:
+ setPixelColor(i, 0x00FF0000);
+ mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed));
+ setPixelColor(i + 1, 0x00EECC00);
+ break;
+ case 2:
+ setPixelColor(i + 2, 0x0000FF00);
+ mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));
+ break;
+ case 3:
+ setPixelColor(i + 1, 0x00EECC00);
+ mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed));
+ break;
+ }
}
- }
- if (now - SEGENV.step > mdelay)
- {
- SEGENV.aux0++;
- if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence
- if (SEGENV.aux0 > 3) SEGENV.aux0 = 0;
- SEGENV.step = now;
- }
-
- return FRAMETIME;
-}
+ if (now - SEGENV.step > mdelay) {
+ SEGENV.aux0++;
+ if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) {
+ SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence
+ }
+ if (SEGENV.aux0 > 3) {
+ SEGENV.aux0 = 0;
+ }
+ SEGENV.step = now;
+ }
+ return FRAMETIME;
+}
/*
* Sec flashes running on prim.
*/
#define FLASH_COUNT 4
uint16_t WS2812FX::mode_chase_flash(void) {
- uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
-
- for(uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- }
-
- uint16_t delay = 10 + ((30 * (uint16_t)(255 - SEGMENT.speed)) / SEGLEN);
- if(flash_step < (FLASH_COUNT * 2)) {
- if(flash_step % 2 == 0) {
- uint16_t n = SEGENV.step;
- uint16_t m = (SEGENV.step + 1) % SEGLEN;
- setPixelColor( n, SEGCOLOR(1));
- setPixelColor( m, SEGCOLOR(1));
- delay = 20;
+ uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ }
+
+ uint16_t delay = 10 + ((30 * (uint16_t)(255 - SEGMENT.speed)) / SEGLEN);
+ if (flash_step < (FLASH_COUNT * 2)) {
+ if (flash_step % 2 == 0) {
+ uint16_t n = SEGENV.step;
+ uint16_t m = (SEGENV.step + 1) % SEGLEN;
+ setPixelColor(n, SEGCOLOR(1));
+ setPixelColor(m, SEGCOLOR(1));
+ delay = 20;
+ } else {
+ delay = 30;
+ }
} else {
- delay = 30;
+ SEGENV.step = (SEGENV.step + 1) % SEGLEN;
}
- } else {
- SEGENV.step = (SEGENV.step + 1) % SEGLEN;
- }
- return delay;
+ return delay;
}
-
/*
* Prim flashes running, followed by random color.
*/
uint16_t WS2812FX::mode_chase_flash_random(void) {
- uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
+ uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
- for(uint16_t i = 0; i < SEGENV.step; i++) {
- setPixelColor(i, color_wheel(SEGENV.aux0));
- }
+ for (uint16_t i = 0; i < SEGENV.step; i++) {
+ setPixelColor(i, color_wheel(SEGENV.aux0));
+ }
- uint16_t delay = 1 + ((10 * (uint16_t)(255 - SEGMENT.speed)) / SEGLEN);
- if(flash_step < (FLASH_COUNT * 2)) {
- uint16_t n = SEGENV.step;
- uint16_t m = (SEGENV.step + 1) % SEGLEN;
- if(flash_step % 2 == 0) {
- setPixelColor( n, SEGCOLOR(0));
- setPixelColor( m, SEGCOLOR(0));
- delay = 20;
+ uint16_t delay = 1 + ((10 * (uint16_t)(255 - SEGMENT.speed)) / SEGLEN);
+ if (flash_step < (FLASH_COUNT * 2)) {
+ uint16_t n = SEGENV.step;
+ uint16_t m = (SEGENV.step + 1) % SEGLEN;
+ if (flash_step % 2 == 0) {
+ setPixelColor(n, SEGCOLOR(0));
+ setPixelColor(m, SEGCOLOR(0));
+ delay = 20;
+ } else {
+ setPixelColor(n, color_wheel(SEGENV.aux0));
+ setPixelColor(m, SEGCOLOR(1));
+ delay = 30;
+ }
} else {
- setPixelColor( n, color_wheel(SEGENV.aux0));
- setPixelColor( m, SEGCOLOR(1));
- delay = 30;
- }
- } else {
- SEGENV.step = (SEGENV.step + 1) % SEGLEN;
+ SEGENV.step = (SEGENV.step + 1) % SEGLEN;
- if(SEGENV.step == 0) {
- SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
+ if (SEGENV.step == 0) {
+ SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
+ }
}
- }
- return delay;
+ return delay;
}
-
/*
* Alternating pixels running function.
*/
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) {
- uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
- uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
- uint32_t it = now / cycleTime;
- bool usePalette = color1 == SEGCOLOR(0);
-
- for(uint16_t i = 0; i < SEGLEN; i++) {
- uint32_t col = color2;
- if (usePalette) color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
- if (theatre) {
- if ((i % width) == SEGENV.aux0) col = color1;
- } else {
- int8_t pos = (i % (width<<1));
- if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1;
+ uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
+ uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
+ uint32_t it = now / cycleTime;
+ bool usePalette = color1 == SEGCOLOR(0);
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint32_t col = color2;
+ if (usePalette) {
+ color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
+ }
+ if (theatre) {
+ if ((i % width) == SEGENV.aux0) {
+ col = color1;
+ }
+ } else {
+ int8_t pos = (i % (width << 1));
+ if ((pos < SEGENV.aux0 - width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0 + width))) {
+ col = color1;
+ }
+ }
+ setPixelColor(i, col);
}
- setPixelColor(i,col);
- }
- if (it != SEGENV.step )
- {
- SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1));
- SEGENV.step = it;
- }
- return FRAMETIME;
+ if (it != SEGENV.step) {
+ SEGENV.aux0 = (SEGENV.aux0 + 1) % (theatre ? width : (width << 1));
+ SEGENV.step = it;
+ }
+ return FRAMETIME;
}
/*
* Alternating color/sec pixels running.
*/
uint16_t WS2812FX::mode_running_color(void) {
- return running(SEGCOLOR(0), SEGCOLOR(1));
+ return running(SEGCOLOR(0), SEGCOLOR(1));
}
/*
* Alternating red/white pixels running.
*/
uint16_t WS2812FX::mode_candy_cane(void) {
- return running(RED, WHITE);
+ return running(RED, WHITE);
}
/*
* Alternating orange/purple pixels running.
*/
uint16_t WS2812FX::mode_halloween(void) {
- return running(PURPLE, ORANGE);
+ return running(PURPLE, ORANGE);
}
-
/*
* 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( i, getPixelColor( i - 1));
- }
+ uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed));
+ uint32_t it = now / cycleTime;
+ if (SEGENV.aux1 == it) {
+ return FRAMETIME;
+ }
- if(SEGENV.step == 0) {
- SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
- setPixelColor(0, color_wheel(SEGENV.aux0));
- }
+ for (uint16_t i = SEGLEN - 1; i > 0; i--) {
+ setPixelColor(i, getPixelColor(i - 1));
+ }
- SEGENV.step++;
- if (SEGENV.step > (uint8_t)((255-SEGMENT.intensity) >> 4))
- {
- SEGENV.step = 0;
- }
+ if (SEGENV.step == 0) {
+ SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
+ setPixelColor(0, color_wheel(SEGENV.aux0));
+ }
- SEGENV.aux1 = it;
- return FRAMETIME;
-}
+ SEGENV.step++;
+ if (SEGENV.step > (uint8_t)((255 - SEGMENT.intensity) >> 4)) {
+ SEGENV.step = 0;
+ }
+ SEGENV.aux1 = it;
+ return FRAMETIME;
+}
/*
* K.I.T.T.
*/
-uint16_t WS2812FX::mode_larson_scanner(void){
- return larson_scanner(false);
+uint16_t WS2812FX::mode_larson_scanner(void) {
+ return larson_scanner(false);
}
uint16_t WS2812FX::larson_scanner(bool dual) {
- uint16_t counter = now * ((SEGMENT.speed >> 2) +8);
- uint16_t index = counter * SEGLEN >> 16;
-
- fade_out(SEGMENT.intensity);
-
- if (SEGENV.step > index && SEGENV.step - index > SEGLEN/2) {
- SEGENV.aux0 = !SEGENV.aux0;
- }
-
- 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));
- }
- if (dual) {
- uint32_t c;
- if (SEGCOLOR(2) != 0) {
- c = SEGCOLOR(2);
- } else {
- c = color_from_palette(index, true, PALETTE_SOLID_WRAP, 0);
+ uint16_t counter = now * ((SEGMENT.speed >> 2) + 8);
+ uint16_t index = counter * SEGLEN >> 16;
+
+ fade_out(SEGMENT.intensity);
+
+ if (SEGENV.step > index && SEGENV.step - index > SEGLEN / 2) {
+ SEGENV.aux0 = !SEGENV.aux0;
}
for (uint16_t i = SEGENV.step; i < index; i++) {
- uint16_t j = (SEGENV.aux0)?SEGLEN-1-i:i;
- setPixelColor(j, c);
+ uint16_t j = (SEGENV.aux0) ? i : SEGLEN - 1 - i;
+ setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0));
+ }
+ if (dual) {
+ uint32_t c;
+ if (SEGCOLOR(2) != 0) {
+ c = SEGCOLOR(2);
+ } else {
+ c = color_from_palette(index, true, PALETTE_SOLID_WRAP, 0);
+ }
+
+ for (uint16_t i = SEGENV.step; i < index; i++) {
+ uint16_t j = (SEGENV.aux0) ? SEGLEN - 1 - i : i;
+ setPixelColor(j, c);
+ }
}
- }
- SEGENV.step = index;
- return FRAMETIME;
+ SEGENV.step = index;
+ return FRAMETIME;
}
-
/*
* Firing comets from one end. "Lighthouse"
*/
uint16_t WS2812FX::mode_comet(void) {
- uint16_t counter = now * ((SEGMENT.speed >>2) +1);
- uint16_t index = counter * SEGLEN >> 16;
- if (SEGENV.call == 0) SEGENV.aux0 = index;
+ uint16_t counter = now * ((SEGMENT.speed >> 2) + 1);
+ uint16_t index = counter * SEGLEN >> 16;
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = index;
+ }
- fade_out(SEGMENT.intensity);
+ fade_out(SEGMENT.intensity);
- setPixelColor( index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0));
- if (index > SEGENV.aux0) {
- for (uint16_t i = SEGENV.aux0; i < index ; i++) {
- setPixelColor( i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0));
+ if (index > SEGENV.aux0) {
+ for (uint16_t i = SEGENV.aux0; i < index; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ }
+ } else if (index < SEGENV.aux0 && index < 10) {
+ for (uint16_t i = 0; i < index; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ }
}
- } else if (index < SEGENV.aux0 && index < 10) {
- for (uint16_t i = 0; i < index ; i++) {
- setPixelColor( i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- }
- }
- SEGENV.aux0 = index++;
+ SEGENV.aux0 = index++;
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Fireworks function.
*/
uint16_t WS2812FX::mode_fireworks() {
- fade_out(0);
- if (SEGENV.call == 0) {
- SEGENV.aux0 = UINT16_MAX;
- SEGENV.aux1 = UINT16_MAX;
- }
- bool valid1 = (SEGENV.aux0 < SEGLEN);
- bool valid2 = (SEGENV.aux1 < SEGLEN);
- uint32_t sv1 = 0, sv2 = 0;
- if (valid1) sv1 = getPixelColor(SEGENV.aux0);
- if (valid2) sv2 = getPixelColor(SEGENV.aux1);
- blur(255-SEGMENT.speed);
- if (valid1) setPixelColor(SEGENV.aux0 , sv1);
- if (valid2) setPixelColor(SEGENV.aux1, sv2);
-
- for(uint16_t i=0; i> 1)) == 0) {
- uint16_t index = random(SEGLEN);
- setPixelColor(index, color_from_palette(random8(), false, false, 0));
- SEGENV.aux1 = SEGENV.aux0;
- SEGENV.aux0 = index;
- }
- }
- return FRAMETIME;
+ fade_out(0);
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = UINT16_MAX;
+ SEGENV.aux1 = UINT16_MAX;
+ }
+ bool valid1 = (SEGENV.aux0 < SEGLEN);
+ bool valid2 = (SEGENV.aux1 < SEGLEN);
+ uint32_t sv1 = 0, sv2 = 0;
+ if (valid1) {
+ sv1 = getPixelColor(SEGENV.aux0);
+ }
+ if (valid2) {
+ sv2 = getPixelColor(SEGENV.aux1);
+ }
+ blur(255 - SEGMENT.speed);
+ if (valid1) {
+ setPixelColor(SEGENV.aux0, sv1);
+ }
+ if (valid2) {
+ setPixelColor(SEGENV.aux1, sv2);
+ }
+ for (uint16_t i = 0; i < MAX(1, SEGLEN / 20); i++) {
+ if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
+ uint16_t index = random(SEGLEN);
+ setPixelColor(index, color_from_palette(random8(), false, false, 0));
+ SEGENV.aux1 = SEGENV.aux0;
+ SEGENV.aux0 = index;
+ }
+ }
+ return FRAMETIME;
}
-
//Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h
-uint16_t WS2812FX::mode_rain()
-{
- SEGENV.step += FRAMETIME;
- if (SEGENV.step > SPEED_FORMULA_L) {
- SEGENV.step = 0;
- //shift all leds left
- uint32_t ctemp = getPixelColor(0);
- for(uint16_t i = 0; i < SEGLEN - 1; i++) {
- setPixelColor(i, getPixelColor(i+1));
- }
- setPixelColor(SEGLEN -1, ctemp);
- SEGENV.aux0++;
- SEGENV.aux1++;
- if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX;
- if (SEGENV.aux1 == 0) SEGENV.aux0 = UINT16_MAX;
- if (SEGENV.aux0 == SEGLEN) SEGENV.aux0 = 0;
- if (SEGENV.aux1 == SEGLEN) SEGENV.aux1 = 0;
- }
- return mode_fireworks();
+uint16_t WS2812FX::mode_rain() {
+ SEGENV.step += FRAMETIME;
+ if (SEGENV.step > SPEED_FORMULA_L) {
+ SEGENV.step = 0;
+ //shift all leds left
+ uint32_t ctemp = getPixelColor(0);
+ for (uint16_t i = 0; i < SEGLEN - 1; i++) {
+ setPixelColor(i, getPixelColor(i + 1));
+ }
+ setPixelColor(SEGLEN - 1, ctemp);
+ SEGENV.aux0++;
+ SEGENV.aux1++;
+ if (SEGENV.aux0 == 0) {
+ SEGENV.aux0 = UINT16_MAX;
+ }
+ if (SEGENV.aux1 == 0) {
+ SEGENV.aux0 = UINT16_MAX;
+ }
+ if (SEGENV.aux0 == SEGLEN) {
+ SEGENV.aux0 = 0;
+ }
+ if (SEGENV.aux1 == SEGLEN) {
+ SEGENV.aux1 = 0;
+ }
+ }
+ return mode_fireworks();
}
-
/*
* 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;
- byte b = (SEGCOLOR(0) & 0xFF);
- byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255;
- lum /= (((256-SEGMENT.intensity)/16)+1);
- for(uint16_t i = 0; i < SEGLEN; i++) {
- byte flicker = random8(lum);
- if (SEGMENT.palette == 0) {
- setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0));
- } else {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker));
+ uint32_t cycleTime = 40 + (255 - SEGMENT.speed);
+ uint32_t it = now / cycleTime;
+ if (SEGENV.step == it) {
+ return FRAMETIME;
}
- }
- SEGENV.step = it;
- return FRAMETIME;
-}
+ byte w = (SEGCOLOR(0) >> 24) & 0xFF;
+ byte r = (SEGCOLOR(0) >> 16) & 0xFF;
+ byte g = (SEGCOLOR(0) >> 8) & 0xFF;
+ byte b = (SEGCOLOR(0) & 0xFF);
+ byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255;
+ lum /= (((256 - SEGMENT.intensity) / 16) + 1);
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ byte flicker = random8(lum);
+ if (SEGMENT.palette == 0) {
+ setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0));
+ } else {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker));
+ }
+ }
+ SEGENV.step = it;
+ return FRAMETIME;
+}
/*
* Gradient run base function
*/
uint16_t WS2812FX::gradient_base(bool loading) {
- uint16_t counter = now * ((SEGMENT.speed >> 2) + 1);
- uint16_t pp = counter * SEGLEN >> 16;
- if (SEGENV.call == 0) pp = 0;
- float val; //0.0 = sec 1.0 = pri
- float brd = loading ? SEGMENT.intensity : SEGMENT.intensity/2;
- if (brd <1.0) brd = 1.0;
- int p1 = pp-SEGLEN;
- int p2 = pp+SEGLEN;
-
- for(uint16_t i = 0; i < SEGLEN; i++)
- {
- if (loading)
- {
- val = abs(((i>pp) ? p2:pp) -i);
- } else {
- val = MIN(abs(pp-i),MIN(abs(p1-i),abs(p2-i)));
+ uint16_t counter = now * ((SEGMENT.speed >> 2) + 1);
+ uint16_t pp = counter * SEGLEN >> 16;
+ if (SEGENV.call == 0) {
+ pp = 0;
}
- val = (brd > val) ? val/brd * 255 : 255;
- setPixelColor(i, color_blend(SEGCOLOR(0), color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val));
- }
+ float val; //0.0 = sec 1.0 = pri
+ float brd = loading ? SEGMENT.intensity : SEGMENT.intensity / 2;
+ if (brd < 1.0) {
+ brd = 1.0;
+ }
+ int p1 = pp - SEGLEN;
+ int p2 = pp + SEGLEN;
- return FRAMETIME;
-}
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (loading) {
+ val = abs(((i > pp) ? p2 : pp) - i);
+ } else {
+ val = MIN(abs(pp - i), MIN(abs(p1 - i), abs(p2 - i)));
+ }
+ val = (brd > val) ? val / brd * 255 : 255;
+ setPixelColor(i, color_blend(SEGCOLOR(0), color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val));
+ }
+ return FRAMETIME;
+}
/*
* Gradient run
*/
uint16_t WS2812FX::mode_gradient(void) {
- return gradient_base(false);
+ return gradient_base(false);
}
-
/*
* Gradient run with hard transition
*/
uint16_t WS2812FX::mode_loading(void) {
- return gradient_base(true);
+ return gradient_base(true);
}
+//American Police Light with all LEDs Red and Blue
+uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, uint16_t width) {
+ uint16_t delay = 1 + (FRAMETIME << 3) / SEGLEN; // longer segments should change faster
+ uint32_t it = now / map(SEGMENT.speed, 0, 255, delay << 4, delay);
+ uint16_t offset = it % SEGLEN;
-//American Police Light with all LEDs Red and Blue
-uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, uint16_t width)
-{
- uint16_t delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster
- uint32_t it = now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
- uint16_t offset = it % SEGLEN;
-
- if (!width) width = 1;
- for (uint16_t i = 0; i < width; i++) {
- uint16_t indexR = (offset + i) % SEGLEN;
- uint16_t indexB = (offset + i + (SEGLEN>>1)) % SEGLEN;
- setPixelColor(indexR, color1);
- setPixelColor(indexB, color2);
- }
- return FRAMETIME;
+ if (!width) {
+ width = 1;
+ }
+ for (uint16_t i = 0; i < width; i++) {
+ uint16_t indexR = (offset + i) % SEGLEN;
+ uint16_t indexB = (offset + i + (SEGLEN >> 1)) % SEGLEN;
+ setPixelColor(indexR, color1);
+ setPixelColor(indexB, color2);
+ }
+ return FRAMETIME;
}
-
-//American Police Light with all LEDs Red and Blue
-uint16_t WS2812FX::mode_police_all()
-{
- return police_base(RED, BLUE, (SEGLEN>>1));
+//American Police Light with all LEDs Red and Blue
+uint16_t WS2812FX::mode_police_all() {
+ return police_base(RED, BLUE, (SEGLEN >> 1));
}
-
-//Police Lights Red and Blue
-uint16_t WS2812FX::mode_police()
-{
- fill(SEGCOLOR(1));
- return police_base(RED, BLUE, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
+//Police Lights Red and Blue
+uint16_t WS2812FX::mode_police() {
+ fill(SEGCOLOR(1));
+ return police_base(RED, BLUE, ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
}
-
//Police All with custom colors
-uint16_t WS2812FX::mode_two_areas()
-{
- fill(SEGCOLOR(2));
- return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
+uint16_t WS2812FX::mode_two_areas() {
+ fill(SEGCOLOR(2));
+ return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
}
+//Police Lights with custom colors
+uint16_t WS2812FX::mode_two_dots() {
+ fill(SEGCOLOR(2));
+ uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
-//Police Lights with custom colors
-uint16_t WS2812FX::mode_two_dots()
-{
- fill(SEGCOLOR(2));
- uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
-
- return police_base(SEGCOLOR(0), color2, ((SEGLEN*(SEGMENT.intensity+1))>>9)); // max width is half the strip
+ return police_base(SEGCOLOR(0), color2, ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
}
-
/*
* Tricolor chase function
*/
uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
- uint32_t cycleTime = 50 + ((255 - SEGMENT.speed)<<1);
- uint32_t it = now / cycleTime; // iterator
- uint8_t width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour
- uint8_t index = it % (width*3);
-
- for (uint16_t i = 0; i < SEGLEN; i++, index++) {
- if (index > (width*3)-1) index = 0;
-
- uint32_t color = color1;
- if (index > (width<<1)-1) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
- else if (index > width-1) color = color2;
-
- setPixelColor(SEGLEN - i -1, color);
- }
- return FRAMETIME;
+ uint32_t cycleTime = 50 + ((255 - SEGMENT.speed) << 1);
+ uint32_t it = now / cycleTime; // iterator
+ uint8_t width = (1 + (SEGMENT.intensity >> 4)); // value of 1-16 for each colour
+ uint8_t index = it % (width * 3);
+
+ for (uint16_t i = 0; i < SEGLEN; i++, index++) {
+ if (index > (width * 3) - 1) {
+ index = 0;
+ }
+ uint32_t color = color1;
+ if (index > (width << 1) - 1) {
+ color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
+ }
+ else if (index > width - 1) {
+ color = color2;
+ }
+ setPixelColor(SEGLEN - i - 1, color);
+ }
+ return FRAMETIME;
}
-
/*
* Tricolor chase mode
*/
uint16_t WS2812FX::mode_tricolor_chase(void) {
- return tricolor_chase(SEGCOLOR(2), SEGCOLOR(0));
+ return tricolor_chase(SEGCOLOR(2), SEGCOLOR(0));
}
-
/*
* ICU mode
*/
uint16_t WS2812FX::mode_icu(void) {
- uint16_t dest = SEGENV.step & 0xFFFF;
- uint8_t space = (SEGMENT.intensity >> 3) +2;
+ uint16_t dest = SEGENV.step & 0xFFFF;
+ uint8_t space = (SEGMENT.intensity >> 3) + 2;
- fill(SEGCOLOR(1));
+ fill(SEGCOLOR(1));
- byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255);
- uint32_t col = color_from_palette(pindex, false, false, 0);
+ byte pindex = map(dest, 0, SEGLEN - SEGLEN / space, 0, 255);
+ uint32_t col = color_from_palette(pindex, false, false, 0);
- setPixelColor(dest, col);
- setPixelColor(dest + SEGLEN/space, col);
+ setPixelColor(dest, col);
+ setPixelColor(dest + SEGLEN / space, col);
- if(SEGENV.aux0 == dest) { // pause between eye movements
- if(random8(6) == 0) { // blink once in a while
- setPixelColor(dest, SEGCOLOR(1));
- setPixelColor(dest + SEGLEN/space, SEGCOLOR(1));
- return 200;
+ if (SEGENV.aux0 == dest) { // pause between eye movements
+ if (random8(6) == 0) { // blink once in a while
+ setPixelColor(dest, SEGCOLOR(1));
+ setPixelColor(dest + SEGLEN / space, SEGCOLOR(1));
+ return 200;
+ }
+ SEGENV.aux0 = random16(SEGLEN - SEGLEN / space);
+ return 1000 + random16(2000);
}
- SEGENV.aux0 = random16(SEGLEN-SEGLEN/space);
- return 1000 + random16(2000);
- }
- if(SEGENV.aux0 > SEGENV.step) {
- SEGENV.step++;
- dest++;
- } else if (SEGENV.aux0 < SEGENV.step) {
- SEGENV.step--;
- dest--;
- }
+ if (SEGENV.aux0 > SEGENV.step) {
+ SEGENV.step++;
+ dest++;
+ } else if (SEGENV.aux0 < SEGENV.step) {
+ SEGENV.step--;
+ dest--;
+ }
- setPixelColor(dest, col);
- setPixelColor(dest + SEGLEN/space, col);
+ setPixelColor(dest, col);
+ setPixelColor(dest + SEGLEN / space, col);
- return SPEED_FORMULA_L;
+ return SPEED_FORMULA_L;
}
-
/*
* Custom mode by Aircoookie. Color Wipe, but with 3 colors
*/
-uint16_t WS2812FX::mode_tricolor_wipe(void)
-{
- uint32_t cycleTime = 1000 + (255 - SEGMENT.speed)*200;
- uint32_t perc = now % cycleTime;
- uint16_t prog = (perc * 65535) / cycleTime;
- uint16_t ledIndex = (prog * SEGLEN * 3) >> 16;
- uint16_t ledOffset = ledIndex;
-
- for (uint16_t i = 0; i < SEGLEN; i++)
- {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2));
- }
-
- if(ledIndex < SEGLEN) { //wipe from 0 to 1
- for (uint16_t i = 0; i < SEGLEN; i++)
- {
- setPixelColor(i, (i > ledOffset)? SEGCOLOR(0) : SEGCOLOR(1));
- }
- } else if (ledIndex < SEGLEN*2) { //wipe from 1 to 2
- ledOffset = ledIndex - SEGLEN;
- for (uint16_t i = ledOffset +1; i < SEGLEN; i++)
- {
- setPixelColor(i, SEGCOLOR(1));
+uint16_t WS2812FX::mode_tricolor_wipe(void) {
+ uint32_t cycleTime = 1000 + (255 - SEGMENT.speed) * 200;
+ uint32_t perc = now % cycleTime;
+ uint16_t prog = (perc * 65535) / cycleTime;
+ uint16_t ledIndex = (prog * SEGLEN * 3) >> 16;
+ uint16_t ledOffset = ledIndex;
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2));
}
- } else //wipe from 2 to 0
- {
- ledOffset = ledIndex - SEGLEN*2;
- for (uint16_t i = 0; i <= ledOffset; i++)
+
+ if (ledIndex < SEGLEN) { //wipe from 0 to 1
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, (i > ledOffset) ? SEGCOLOR(0) : SEGCOLOR(1));
+ }
+ } else if (ledIndex < SEGLEN * 2) { //wipe from 1 to 2
+ ledOffset = ledIndex - SEGLEN;
+ for (uint16_t i = ledOffset + 1; i < SEGLEN; i++) {
+ setPixelColor(i, SEGCOLOR(1));
+ }
+ } else //wipe from 2 to 0
{
- setPixelColor(i, SEGCOLOR(0));
+ ledOffset = ledIndex - SEGLEN * 2;
+ for (uint16_t i = 0; i <= ledOffset; i++) {
+ setPixelColor(i, SEGCOLOR(0));
+ }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Fades between 3 colors
* Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/TriFade.h
* Modified by Aircoookie
*/
-uint16_t WS2812FX::mode_tricolor_fade(void)
-{
- uint16_t counter = now * ((SEGMENT.speed >> 3) +1);
- uint32_t prog = (counter * 768) >> 16;
-
- uint32_t color1 = 0, color2 = 0;
- byte stage = 0;
-
- if(prog < 256) {
- color1 = SEGCOLOR(0);
- color2 = SEGCOLOR(1);
- stage = 0;
- } else if(prog < 512) {
- color1 = SEGCOLOR(1);
- color2 = SEGCOLOR(2);
- stage = 1;
- } else {
- color1 = SEGCOLOR(2);
- color2 = SEGCOLOR(0);
- stage = 2;
- }
-
- byte stp = prog; // % 256
- for(uint16_t i = 0; i < SEGLEN; i++) {
- uint32_t color;
- if (stage == 2) {
- color = color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), color2, stp);
- } else if (stage == 1) {
- color = color_blend(color1, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), stp);
+uint16_t WS2812FX::mode_tricolor_fade(void) {
+ uint16_t counter = now * ((SEGMENT.speed >> 3) + 1);
+ uint32_t prog = (counter * 768) >> 16;
+
+ uint32_t color1 = 0, color2 = 0;
+ byte stage = 0;
+
+ if (prog < 256) {
+ color1 = SEGCOLOR(0);
+ color2 = SEGCOLOR(1);
+ stage = 0;
+ } else if (prog < 512) {
+ color1 = SEGCOLOR(1);
+ color2 = SEGCOLOR(2);
+ stage = 1;
} else {
- color = color_blend(color1, color2, stp);
+ color1 = SEGCOLOR(2);
+ color2 = SEGCOLOR(0);
+ stage = 2;
}
- setPixelColor(i, color);
- }
- return FRAMETIME;
-}
+ byte stp = prog; // % 256
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint32_t color;
+ if (stage == 2) {
+ color = color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), color2, stp);
+ } else if (stage == 1) {
+ color = color_blend(color1, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), stp);
+ } else {
+ color = color_blend(color1, color2, stp);
+ }
+ setPixelColor(i, color);
+ }
+ return FRAMETIME;
+}
/*
* Creates random comets
* Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h
*/
-uint16_t WS2812FX::mode_multi_comet(void)
-{
- uint32_t cycleTime = 10 + (uint32_t)(255 - SEGMENT.speed);
- uint32_t it = now / cycleTime;
- if (SEGENV.step == it) return FRAMETIME;
- if (!SEGENV.allocateData(sizeof(uint16_t) * 8)) return mode_static(); //allocation failed
-
- fade_out(SEGMENT.intensity);
-
- uint16_t* comets = reinterpret_cast(SEGENV.data);
-
- for(uint8_t i=0; i < 8; i++) {
- if(comets[i] < SEGLEN) {
- uint16_t index = comets[i];
- if (SEGCOLOR(2) != 0)
- {
- setPixelColor(index, i % 2 ? color_from_palette(index, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(2));
- } else
- {
- setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0));
- }
- comets[i]++;
- } else {
- if(!random(SEGLEN)) {
- comets[i] = 0;
- }
+uint16_t WS2812FX::mode_multi_comet(void) {
+ uint32_t cycleTime = 10 + (uint32_t)(255 - SEGMENT.speed);
+ uint32_t it = now / cycleTime;
+ if (SEGENV.step == it) {
+ return FRAMETIME;
+ }
+ if (!SEGENV.allocateData(sizeof(uint16_t) * 8)) {
+ return mode_static(); //allocation failed
}
- }
- SEGENV.step = it;
- return FRAMETIME;
-}
+ fade_out(SEGMENT.intensity);
+ uint16_t *comets = reinterpret_cast(SEGENV.data);
+
+ for (uint8_t i = 0; i < 8; i++) {
+ if (comets[i] < SEGLEN) {
+ uint16_t index = comets[i];
+ if (SEGCOLOR(2) != 0) {
+ setPixelColor(index, i % 2 ? color_from_palette(index, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(2));
+ } else {
+ setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0));
+ }
+ comets[i]++;
+ } else {
+ if (!random(SEGLEN)) {
+ comets[i] = 0;
+ }
+ }
+ }
+
+ SEGENV.step = it;
+ return FRAMETIME;
+}
/*
* Creates two Larson scanners moving in opposite directions
* Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/DualLarson.h
*/
-uint16_t WS2812FX::mode_dual_larson_scanner(void){
- return larson_scanner(true);
+uint16_t WS2812FX::mode_dual_larson_scanner(void) {
+ return larson_scanner(true);
}
-
/*
* Running random pixels
* Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/RandomChase.h
*/
-uint16_t WS2812FX::mode_random_chase(void)
-{
- uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed));
- uint32_t it = now / cycleTime;
- if (SEGENV.step == it) return FRAMETIME;
-
- for(uint16_t i = SEGLEN -1; i > 0; i--) {
- setPixelColor(i, getPixelColor(i-1));
- }
- uint32_t color = getPixelColor(0);
- if (SEGLEN > 1) color = getPixelColor( 1);
- uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8();
- uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8();
- uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8();
- setPixelColor(0, r, g, b);
-
- SEGENV.step = it;
- return FRAMETIME;
+uint16_t WS2812FX::mode_random_chase(void) {
+ uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed));
+ uint32_t it = now / cycleTime;
+ if (SEGENV.step == it) {
+ return FRAMETIME;
+ }
+
+ for (uint16_t i = SEGLEN - 1; i > 0; i--) {
+ setPixelColor(i, getPixelColor(i - 1));
+ }
+ uint32_t color = getPixelColor(0);
+ if (SEGLEN > 1) {
+ color = getPixelColor(1);
+ }
+ uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8();
+ uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8();
+ uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8();
+ setPixelColor(0, r, g, b);
+
+ SEGENV.step = it;
+ return FRAMETIME;
}
//7 bytes
typedef struct Oscillator {
- int16_t pos;
- int8_t size;
- int8_t dir;
- int8_t speed;
+ int16_t pos;
+ int8_t size;
+ int8_t dir;
+ int8_t speed;
} oscillator;
/*
/ Oscillating bars of color, updated with standard framerate
*/
-uint16_t WS2812FX::mode_oscillate(void)
-{
- uint8_t numOscillators = 3;
- uint16_t dataSize = sizeof(oscillator) * numOscillators;
-
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- Oscillator* oscillators = reinterpret_cast(SEGENV.data);
-
- if (SEGENV.call == 0)
- {
- oscillators[0] = {(int16_t)(SEGLEN/4), (int8_t)(SEGLEN/8), 1, 1};
- oscillators[1] = {(int16_t)(SEGLEN/4*3), (int8_t)(SEGLEN/8), 1, 2};
- oscillators[2] = {(int16_t)(SEGLEN/4*2), (int8_t)(SEGLEN/8), -1, 1};
- }
-
- uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
- uint32_t it = now / cycleTime;
-
- for(uint8_t i = 0; i < numOscillators; i++) {
- // if the counter has increased, move the oscillator by the random step
- if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
- oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8);
- if((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) {
- oscillators[i].pos = 0;
- oscillators[i].dir = 1;
- // make bigger steps for faster speeds
- oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4):random8(1, 3);
- }
- if((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGLEN - 1))) {
- oscillators[i].pos = SEGLEN - 1;
- oscillators[i].dir = -1;
- oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4):random8(1, 3);
- }
- }
-
- for(uint16_t i=0; i < SEGLEN; i++) {
- uint32_t color = BLACK;
- for(uint8_t j=0; j < numOscillators; j++) {
- if(i >= oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
- color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128);
- }
+uint16_t WS2812FX::mode_oscillate(void) {
+ uint8_t numOscillators = 3;
+ uint16_t dataSize = sizeof(oscillator) * numOscillators;
+
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
}
- setPixelColor(i, color);
- }
-
- SEGENV.step = it;
- return FRAMETIME;
-}
+ Oscillator *oscillators = reinterpret_cast(SEGENV.data);
+
+ if (SEGENV.call == 0) {
+ oscillators[0] = {(int16_t)(SEGLEN / 4), (int8_t)(SEGLEN / 8), 1, 1};
+ oscillators[1] = {(int16_t)(SEGLEN / 4 * 3), (int8_t)(SEGLEN / 8), 1, 2};
+ oscillators[2] = {(int16_t)(SEGLEN / 4 * 2), (int8_t)(SEGLEN / 8), -1, 1};
+ }
-uint16_t WS2812FX::mode_lightning(void)
-{
- uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
- uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
- uint8_t bri = 255/random8(1, 3);
+ uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
+ uint32_t it = now / cycleTime;
+
+ for (uint8_t i = 0; i < numOscillators; i++) {
+ // if the counter has increased, move the oscillator by the random step
+ if (it != SEGENV.step) {
+ oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
+ }
+ oscillators[i].size = SEGLEN / (3 + SEGMENT.intensity / 8);
+ if ((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) {
+ oscillators[i].pos = 0;
+ oscillators[i].dir = 1;
+ // make bigger steps for faster speeds
+ oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4) : random8(1, 3);
+ }
+ if ((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGLEN - 1))) {
+ oscillators[i].pos = SEGLEN - 1;
+ oscillators[i].dir = -1;
+ oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4) : random8(1, 3);
+ }
+ }
- if (SEGENV.aux1 == 0) //init, leader flash
- {
- SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity/20); //number of flashes
- SEGENV.aux1 *= 2;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint32_t color = BLACK;
+ for (uint8_t j = 0; j < numOscillators; j++) {
+ if (i >= oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
+ color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128);
+ }
+ }
+ setPixelColor(i, color);
+ }
- bri = 52; //leader has lower brightness
- SEGENV.aux0 = 200; //200ms delay after leader
- }
+ SEGENV.step = it;
+ return FRAMETIME;
+}
- fill(SEGCOLOR(1));
+uint16_t WS2812FX::mode_lightning(void) {
+ uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
+ uint16_t ledlen = 1 + random16(SEGLEN - ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) {
+ uint8_t bri = 255 / random8(1, 3);
- if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
- for (int i = ledstart; i < ledstart + ledlen; i++)
+ if (SEGENV.aux1 == 0) //init, leader flash
{
- setPixelColor(i,color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri));
+ SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity / 20); //number of flashes
+ SEGENV.aux1 *= 2;
+
+ bri = 52; //leader has lower brightness
+ SEGENV.aux0 = 200; //200ms delay after leader
}
- SEGENV.aux1--;
- SEGENV.step = millis();
- //return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds
- } else {
- if (millis() - SEGENV.step > SEGENV.aux0) {
- SEGENV.aux1--;
- if (SEGENV.aux1 < 2) SEGENV.aux1 = 0;
+ fill(SEGCOLOR(1));
- SEGENV.aux0 = (50 + random8(100)); //delay between flashes
- if (SEGENV.aux1 == 2) {
- SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
- }
- SEGENV.step = millis();
+ if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
+ for (int i = ledstart; i < ledstart + ledlen; i++) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri));
+ }
+ SEGENV.aux1--;
+
+ SEGENV.step = millis();
+ //return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds
+ } else {
+ if (millis() - SEGENV.step > SEGENV.aux0) {
+ SEGENV.aux1--;
+ if (SEGENV.aux1 < 2) {
+ SEGENV.aux1 = 0;
+ }
+
+ SEGENV.aux0 = (50 + random8(100)); //delay between flashes
+ if (SEGENV.aux1 == 2) {
+ SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
+ }
+ SEGENV.step = millis();
+ }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-
// Pride2015
// Animated, ever-changing rainbows.
// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
-uint16_t WS2812FX::mode_pride_2015(void)
-{
- uint16_t duration = 10 + SEGMENT.speed;
- uint16_t sPseudotime = SEGENV.step;
- uint16_t sHue16 = SEGENV.aux0;
+uint16_t WS2812FX::mode_pride_2015(void) {
+ uint16_t duration = 10 + SEGMENT.speed;
+ uint16_t sPseudotime = SEGENV.step;
+ uint16_t sHue16 = SEGENV.aux0;
- uint8_t sat8 = beatsin88( 87, 220, 250);
- uint8_t brightdepth = beatsin88( 341, 96, 224);
- uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
- uint8_t msmultiplier = beatsin88(147, 23, 60);
+ uint8_t sat8 = beatsin88(87, 220, 250);
+ uint8_t brightdepth = beatsin88(341, 96, 224);
+ uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256));
+ uint8_t msmultiplier = beatsin88(147, 23, 60);
- uint16_t hue16 = sHue16;//gHue * 256;
- uint16_t hueinc16 = beatsin88(113, 1, 3000);
+ uint16_t hue16 = sHue16; //gHue * 256;
+ uint16_t hueinc16 = beatsin88(113, 1, 3000);
- sPseudotime += duration * msmultiplier;
- sHue16 += duration * beatsin88( 400, 5,9);
- uint16_t brightnesstheta16 = sPseudotime;
- CRGB fastled_col;
+ sPseudotime += duration * msmultiplier;
+ sHue16 += duration * beatsin88(400, 5, 9);
+ uint16_t brightnesstheta16 = sPseudotime;
+ CRGB fastled_col;
- for (uint16_t i = 0 ; i < SEGLEN; i++) {
- hue16 += hueinc16;
- uint8_t hue8 = hue16 >> 8;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ hue16 += hueinc16;
+ uint8_t hue8 = hue16 >> 8;
- brightnesstheta16 += brightnessthetainc16;
- uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
+ brightnesstheta16 += brightnessthetainc16;
+ uint16_t b16 = sin16(brightnesstheta16) + 32768;
- uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
- uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
- bri8 += (255 - brightdepth);
+ uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
+ uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
+ bri8 += (255 - brightdepth);
- CRGB newcolor = CHSV( hue8, sat8, bri8);
- fastled_col = col_to_crgb(getPixelColor(i));
+ CRGB newcolor = CHSV(hue8, sat8, bri8);
+ fastled_col = col_to_crgb(getPixelColor(i));
- nblend(fastled_col, newcolor, 64);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- SEGENV.step = sPseudotime;
- SEGENV.aux0 = sHue16;
- return FRAMETIME;
+ nblend(fastled_col, newcolor, 64);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ SEGENV.step = sPseudotime;
+ SEGENV.aux0 = sHue16;
+ return FRAMETIME;
}
-
//eight colored dots, weaving in and out of sync with each other
-uint16_t WS2812FX::mode_juggle(void){
- fade_out(SEGMENT.intensity);
- CRGB fastled_col;
- byte dothue = 0;
- for ( byte i = 0; i < 8; i++) {
- uint16_t index = 0 + beatsin88((128 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1);
- fastled_col = col_to_crgb(getPixelColor(index));
- fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(currentPalette, dothue, 255);
- setPixelColor(index, fastled_col.red, fastled_col.green, fastled_col.blue);
- dothue += 32;
- }
- return FRAMETIME;
-}
-
-
-uint16_t WS2812FX::mode_palette()
-{
- uint16_t counter = 0;
- if (SEGMENT.speed != 0)
- {
- counter = (now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF;
- counter = counter >> 8;
- }
-
- bool noWrap = (paletteBlend == 2 || (paletteBlend == 0 && SEGMENT.speed == 0));
- for (uint16_t i = 0; i < SEGLEN; i++)
- {
- uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
-
- if (noWrap) colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end"
-
- setPixelColor(i, color_from_palette(colorIndex, false, true, 255));
- }
- return FRAMETIME;
+uint16_t WS2812FX::mode_juggle(void) {
+ fade_out(SEGMENT.intensity);
+ CRGB fastled_col;
+ byte dothue = 0;
+ for (byte i = 0; i < 8; i++) {
+ uint16_t index = 0 + beatsin88((128 + SEGMENT.speed) * (i + 7), 0, SEGLEN - 1);
+ fastled_col = col_to_crgb(getPixelColor(index));
+ fastled_col |= (SEGMENT.palette == 0) ? CHSV(dothue, 220, 255) : ColorFromPalette(currentPalette, dothue, 255);
+ setPixelColor(index, fastled_col.red, fastled_col.green, fastled_col.blue);
+ dothue += 32;
+ }
+ return FRAMETIME;
}
+uint16_t WS2812FX::mode_palette() {
+ uint16_t counter = 0;
+ if (SEGMENT.speed != 0) {
+ counter = (now * ((SEGMENT.speed >> 3) + 1)) & 0xFFFF;
+ counter = counter >> 8;
+ }
+
+ bool noWrap = (paletteBlend == 2 || (paletteBlend == 0 && SEGMENT.speed == 0));
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
+
+ if (noWrap) {
+ colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end"
+ }
+
+ setPixelColor(i, color_from_palette(colorIndex, false, true, 255));
+ }
+ return FRAMETIME;
+}
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
-////
+////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
-// at each point along the line. Every cycle through the simulation,
+// at each point along the line. Every cycle through the simulation,
// four steps are performed:
// 1) All cells cool down a little bit, losing heat to the air
// 2) The heat from each cell drifts 'up' and diffuses a little
@@ -1695,7 +1702,7 @@ uint16_t WS2812FX::mode_palette()
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
-// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
+// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
@@ -1707,496 +1714,472 @@ uint16_t WS2812FX::mode_palette()
// feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used
// in step 3 above) (Effect Intensity = Sparking).
+uint16_t WS2812FX::mode_fire_2012() {
+ uint32_t it = now >> 5; //div 32
-uint16_t WS2812FX::mode_fire_2012()
-{
- uint32_t it = now >> 5; //div 32
+ if (!SEGENV.allocateData(SEGLEN)) {
+ return mode_static(); //allocation failed
+ }
- if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
-
- byte* heat = SEGENV.data;
+ byte *heat = SEGENV.data;
- if (it != SEGENV.step)
- {
- uint8_t ignition = max(7,SEGLEN/10); // ignition area: 10% of segment length or minimum 7 pixels
-
- // Step 1. Cool down every cell a little
- for (uint16_t i = 0; i < SEGLEN; i++) {
- uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
- heat[i] = (temp==0 && i 1; k--) {
- heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3; // heat[k-2] multiplied by 2
- }
-
- // Step 3. Randomly ignite new 'sparks' of heat near the bottom
- if (random8() <= SEGMENT.intensity) {
- uint8_t y = random8(ignition);
- if (y < SEGLEN) heat[y] = qadd8(heat[y], random8(160,255));
+ if (it != SEGENV.step) {
+ uint8_t ignition = max(7, SEGLEN / 10); // ignition area: 10% of segment length or minimum 7 pixels
+
+ // Step 1. Cool down every cell a little
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed / 3) * 10) / SEGLEN) + 2));
+ heat[i] = (temp == 0 && i < ignition) ? 16 : temp; // prevent ignition area from becoming black
+ }
+
+ // Step 2. Heat from each cell drifts 'up' and diffuses a little
+ for (uint16_t k = SEGLEN - 1; k > 1; k--) {
+ heat[k] = (heat[k - 1] + (heat[k - 2] << 1)) / 3; // heat[k-2] multiplied by 2
+ }
+
+ // Step 3. Randomly ignite new 'sparks' of heat near the bottom
+ if (random8() <= SEGMENT.intensity) {
+ uint8_t y = random8(ignition);
+ if (y < SEGLEN) {
+ heat[y] = qadd8(heat[y], random8(160, 255));
+ }
+ }
+ SEGENV.step = it;
}
- SEGENV.step = it;
- }
- // Step 4. Map from heat cells to LED colors
- for (uint16_t j = 0; j < SEGLEN; j++) {
- CRGB color = ColorFromPalette(currentPalette, MIN(heat[j],240), 255, LINEARBLEND);
- setPixelColor(j, color.red, color.green, color.blue);
- }
- return FRAMETIME;
+ // Step 4. Map from heat cells to LED colors
+ for (uint16_t j = 0; j < SEGLEN; j++) {
+ CRGB color = ColorFromPalette(currentPalette, MIN(heat[j], 240), 255, LINEARBLEND);
+ setPixelColor(j, color.red, color.green, color.blue);
+ }
+ return FRAMETIME;
}
-
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
-uint16_t WS2812FX::mode_colorwaves()
-{
- uint16_t duration = 10 + SEGMENT.speed;
- uint16_t sPseudotime = SEGENV.step;
- uint16_t sHue16 = SEGENV.aux0;
-
- uint8_t brightdepth = beatsin88(341, 96, 224);
- uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
- uint8_t msmultiplier = beatsin88(147, 23, 60);
-
- uint16_t hue16 = sHue16;//gHue * 256;
- // uint16_t hueinc16 = beatsin88(113, 300, 1500);
- uint16_t hueinc16 = beatsin88(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues
-
- sPseudotime += duration * msmultiplier;
- sHue16 += duration * beatsin88(400, 5, 9);
- uint16_t brightnesstheta16 = sPseudotime;
- CRGB fastled_col;
-
- for ( uint16_t i = 0 ; i < SEGLEN; i++) {
- hue16 += hueinc16;
- uint8_t hue8 = hue16 >> 8;
- uint16_t h16_128 = hue16 >> 7;
- if ( h16_128 & 0x100) {
- hue8 = 255 - (h16_128 >> 1);
- } else {
- hue8 = h16_128 >> 1;
- }
+uint16_t WS2812FX::mode_colorwaves() {
+ uint16_t duration = 10 + SEGMENT.speed;
+ uint16_t sPseudotime = SEGENV.step;
+ uint16_t sHue16 = SEGENV.aux0;
- brightnesstheta16 += brightnessthetainc16;
- uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
+ uint8_t brightdepth = beatsin88(341, 96, 224);
+ uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256));
+ uint8_t msmultiplier = beatsin88(147, 23, 60);
- uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
- uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
- bri8 += (255 - brightdepth);
+ uint16_t hue16 = sHue16; //gHue * 256;
+ // uint16_t hueinc16 = beatsin88(113, 300, 1500);
+ uint16_t hueinc16 = beatsin88(113, 60, 300) * SEGMENT.intensity * 10 / 255; // Use the Intensity Slider for the hues
- CRGB newcolor = ColorFromPalette(currentPalette, hue8, bri8);
- fastled_col = col_to_crgb(getPixelColor(i));
+ sPseudotime += duration * msmultiplier;
+ sHue16 += duration * beatsin88(400, 5, 9);
+ uint16_t brightnesstheta16 = sPseudotime;
+ CRGB fastled_col;
- nblend(fastled_col, newcolor, 128);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- SEGENV.step = sPseudotime;
- SEGENV.aux0 = sHue16;
- return FRAMETIME;
-}
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ hue16 += hueinc16;
+ uint8_t hue8 = hue16 >> 8;
+ uint16_t h16_128 = hue16 >> 7;
+ if (h16_128 & 0x100) {
+ hue8 = 255 - (h16_128 >> 1);
+ } else {
+ hue8 = h16_128 >> 1;
+ }
+ brightnesstheta16 += brightnessthetainc16;
+ uint16_t b16 = sin16(brightnesstheta16) + 32768;
-// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
-uint16_t WS2812FX::mode_bpm()
-{
- CRGB fastled_col;
- uint32_t stp = (now / 20) & 0xFF;
- uint8_t beat = beatsin8(SEGMENT.speed, 64, 255);
- for (uint16_t i = 0; i < SEGLEN; i++) {
- fastled_col = ColorFromPalette(currentPalette, stp + (i * 2), beat - stp + (i * 10));
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- return FRAMETIME;
-}
+ uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
+ uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
+ bri8 += (255 - brightdepth);
+ CRGB newcolor = ColorFromPalette(currentPalette, hue8, bri8);
+ fastled_col = col_to_crgb(getPixelColor(i));
-uint16_t WS2812FX::mode_fillnoise8()
-{
- if (SEGENV.call == 0) SEGENV.step = random16(12345);
- CRGB fastled_col;
- for (uint16_t i = 0; i < SEGLEN; i++) {
- uint8_t index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN);
- fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4
+ nblend(fastled_col, newcolor, 128);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ SEGENV.step = sPseudotime;
+ SEGENV.aux0 = sHue16;
+ return FRAMETIME;
+}
- return FRAMETIME;
+// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
+uint16_t WS2812FX::mode_bpm() {
+ CRGB fastled_col;
+ uint32_t stp = (now / 20) & 0xFF;
+ uint8_t beat = beatsin8(SEGMENT.speed, 64, 255);
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ fastled_col = ColorFromPalette(currentPalette, stp + (i * 2), beat - stp + (i * 10));
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ return FRAMETIME;
}
-uint16_t WS2812FX::mode_noise16_1()
-{
- uint16_t scale = 320; // the "zoom factor" for the noise
- CRGB fastled_col;
- SEGENV.step += (1 + SEGMENT.speed/16);
+uint16_t WS2812FX::mode_fillnoise8() {
+ if (SEGENV.call == 0) {
+ SEGENV.step = random16(12345);
+ }
+ CRGB fastled_col;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint8_t index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN);
+ fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4
- for (uint16_t i = 0; i < SEGLEN; i++) {
+ return FRAMETIME;
+}
- uint16_t shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm
- uint16_t shift_y = SEGENV.step/42; // the y position becomes slowly incremented
+uint16_t WS2812FX::mode_noise16_1() {
+ uint16_t scale = 320; // the "zoom factor" for the noise
+ CRGB fastled_col;
+ SEGENV.step += (1 + SEGMENT.speed / 16);
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint16_t shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm
+ uint16_t shift_y = SEGENV.step / 42; // the y position becomes slowly incremented
- uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm
- uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented
- uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented
+ uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm
+ uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented
+ uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented
- uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
+ uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
- uint8_t index = sin8(noise * 3); // map LED color based on noise data
+ uint8_t index = sin8(noise * 3); // map LED color based on noise data
- fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
+ fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
+uint16_t WS2812FX::mode_noise16_2() {
+ uint16_t scale = 1000; // the "zoom factor" for the noise
+ CRGB fastled_col;
+ SEGENV.step += (1 + (SEGMENT.speed >> 1));
-uint16_t WS2812FX::mode_noise16_2()
-{
- uint16_t scale = 1000; // the "zoom factor" for the noise
- CRGB fastled_col;
- SEGENV.step += (1 + (SEGMENT.speed >> 1));
-
- for (uint16_t i = 0; i < SEGLEN; i++) {
-
- uint16_t shift_x = SEGENV.step >> 6; // x as a function of time
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint16_t shift_x = SEGENV.step >> 6; // x as a function of time
- uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
+ uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
- uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down
+ uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down
- uint8_t index = sin8(noise * 3); // map led color based on noise data
+ uint8_t index = sin8(noise * 3); // map led color based on noise data
- fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
+ fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
+uint16_t WS2812FX::mode_noise16_3() {
+ uint16_t scale = 800; // the "zoom factor" for the noise
+ CRGB fastled_col;
+ SEGENV.step += (1 + SEGMENT.speed);
-uint16_t WS2812FX::mode_noise16_3()
-{
- uint16_t scale = 800; // the "zoom factor" for the noise
- CRGB fastled_col;
- SEGENV.step += (1 + SEGMENT.speed);
-
- for (uint16_t i = 0; i < SEGLEN; i++) {
-
- uint16_t shift_x = 4223; // no movement along x and y
- uint16_t shift_y = 1234;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ uint16_t shift_x = 4223; // no movement along x and y
+ uint16_t shift_y = 1234;
- uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
- uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions
- uint32_t real_z = SEGENV.step*8;
+ uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
+ uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions
+ uint32_t real_z = SEGENV.step * 8;
- uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
+ uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
- uint8_t index = sin8(noise * 3); // map led color based on noise data
+ uint8_t index = sin8(noise * 3); // map led color based on noise data
- fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
+ fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
-
//https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino
-uint16_t WS2812FX::mode_noise16_4()
-{
- CRGB fastled_col;
- uint32_t stp = (now * SEGMENT.speed) >> 7;
- for (uint16_t i = 0; i < SEGLEN; i++) {
- int16_t index = inoise16(uint32_t(i) << 12, stp);
- fastled_col = ColorFromPalette(currentPalette, index);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- return FRAMETIME;
+uint16_t WS2812FX::mode_noise16_4() {
+ CRGB fastled_col;
+ uint32_t stp = (now * SEGMENT.speed) >> 7;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ int16_t index = inoise16(uint32_t(i) << 12, stp);
+ fastled_col = ColorFromPalette(currentPalette, index);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ return FRAMETIME;
}
-
//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e
-uint16_t WS2812FX::mode_colortwinkle()
-{
- uint16_t dataSize = (SEGLEN+7) >> 3; //1 bit per LED
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- CRGB fastled_col, prev;
- fract8 fadeUpAmount = _brightness>28 ? 8 + (SEGMENT.speed>>2) : 68-_brightness, fadeDownAmount = _brightness>28 ? 8 + (SEGMENT.speed>>3) : 68-_brightness;
- for (uint16_t i = 0; i < SEGLEN; i++) {
- fastled_col = col_to_crgb(getPixelColor(i));
- prev = fastled_col;
- uint16_t index = i >> 3;
- uint8_t bitNum = i & 0x07;
- bool fadeUp = bitRead(SEGENV.data[index], bitNum);
-
- if (fadeUp) {
- CRGB incrementalColor = fastled_col;
- incrementalColor.nscale8_video(fadeUpAmount);
- fastled_col += incrementalColor;
-
- if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
- bitWrite(SEGENV.data[index], bitNum, false);
- }
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+uint16_t WS2812FX::mode_colortwinkle() {
+ uint16_t dataSize = (SEGLEN + 7) >> 3; //1 bit per LED
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
- if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
- fastled_col += fastled_col;
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- } else {
- fastled_col.nscale8(255 - fadeDownAmount);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- }
-
- for (uint16_t j = 0; j <= SEGLEN / 50; j++) {
- if (random8() <= SEGMENT.intensity) {
- for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
- int i = random16(SEGLEN);
- if (getPixelColor(i) == 0) {
- fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
- uint16_t index = i >> 3;
- uint8_t bitNum = i & 0x07;
- bitWrite(SEGENV.data[index], bitNum, true);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- break; //only spawn 1 new pixel per frame per 50 LEDs
+ CRGB fastled_col, prev;
+ fract8 fadeUpAmount = _brightness > 28 ? 8 + (SEGMENT.speed >> 2) : 68 - _brightness, fadeDownAmount = _brightness > 28 ? 8 + (SEGMENT.speed >> 3) : 68 - _brightness;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ fastled_col = col_to_crgb(getPixelColor(i));
+ prev = fastled_col;
+ uint16_t index = i >> 3;
+ uint8_t bitNum = i & 0x07;
+ bool fadeUp = bitRead(SEGENV.data[index], bitNum);
+
+ if (fadeUp) {
+ CRGB incrementalColor = fastled_col;
+ incrementalColor.nscale8_video(fadeUpAmount);
+ fastled_col += incrementalColor;
+
+ if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
+ bitWrite(SEGENV.data[index], bitNum, false);
+ }
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+
+ if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
+ fastled_col += fastled_col;
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ } else {
+ fastled_col.nscale8(255 - fadeDownAmount);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
}
- }
}
- }
- return FRAMETIME;
-}
+ for (uint16_t j = 0; j <= SEGLEN / 50; j++) {
+ if (random8() <= SEGMENT.intensity) {
+ for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
+ int i = random16(SEGLEN);
+ if (getPixelColor(i) == 0) {
+ fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
+ uint16_t index = i >> 3;
+ uint8_t bitNum = i & 0x07;
+ bitWrite(SEGENV.data[index], bitNum, true);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ break; //only spawn 1 new pixel per frame per 50 LEDs
+ }
+ }
+ }
+ }
+ return FRAMETIME;
+}
//Calm effect, like a lake at night
uint16_t WS2812FX::mode_lake() {
- uint8_t sp = SEGMENT.speed/10;
- int wave1 = beatsin8(sp +2, -64,64);
- int wave2 = beatsin8(sp +1, -64,64);
- uint8_t wave3 = beatsin8(sp +2, 0,80);
- CRGB fastled_col;
+ uint8_t sp = SEGMENT.speed / 10;
+ int wave1 = beatsin8(sp + 2, -64, 64);
+ int wave2 = beatsin8(sp + 1, -64, 64);
+ uint8_t wave3 = beatsin8(sp + 2, 0, 80);
+ CRGB fastled_col;
- for (uint16_t i = 0; i < SEGLEN; i++)
- {
- int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2;
- uint8_t lum = (index > wave3) ? index - wave3 : 0;
- fastled_col = ColorFromPalette(currentPalette, map(index,0,255,0,240), lum, LINEARBLEND);
- setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- }
- return FRAMETIME;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ int index = cos8((i * 15) + wave1) / 2 + cubicwave8((i * 23) + wave2) / 2;
+ uint8_t lum = (index > wave3) ? index - wave3 : 0;
+ fastled_col = ColorFromPalette(currentPalette, map(index, 0, 255, 0, 240), lum, LINEARBLEND);
+ setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
+ }
+ return FRAMETIME;
}
-
// meteor effect
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX::mode_meteor() {
- if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
+ if (!SEGENV.allocateData(SEGLEN)) {
+ return mode_static(); //allocation failed
+ }
- byte* trail = SEGENV.data;
-
- byte meteorSize= 1+ SEGLEN / 10;
- uint16_t counter = now * ((SEGMENT.speed >> 2) +8);
- uint16_t in = counter * SEGLEN >> 16;
+ byte *trail = SEGENV.data;
- // fade all leds to colors[1] in LEDs one step
- for (uint16_t i = 0; i < SEGLEN; i++) {
- if (random8() <= 255 - SEGMENT.intensity)
- {
- byte meteorTrailDecay = 128 + random8(127);
- trail[i] = scale8(trail[i], meteorTrailDecay);
- setPixelColor(i, color_from_palette(trail[i], false, true, 255));
- }
- }
+ byte meteorSize = 1 + SEGLEN / 10;
+ uint16_t counter = now * ((SEGMENT.speed >> 2) + 8);
+ uint16_t in = counter * SEGLEN >> 16;
- // draw meteor
- for(int j = 0; j < meteorSize; j++) {
- uint16_t index = in + j;
- if(index >= SEGLEN) {
- index = (in + j - SEGLEN);
+ // fade all leds to colors[1] in LEDs one step
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (random8() <= 255 - SEGMENT.intensity) {
+ byte meteorTrailDecay = 128 + random8(127);
+ trail[i] = scale8(trail[i], meteorTrailDecay);
+ setPixelColor(i, color_from_palette(trail[i], false, true, 255));
+ }
}
- trail[index] = 240;
- setPixelColor(index, color_from_palette(trail[index], false, true, 255));
- }
+ // draw meteor
+ for (int j = 0; j < meteorSize; j++) {
+ uint16_t index = in + j;
+ if (index >= SEGLEN) {
+ index = (in + j - SEGLEN);
+ }
- return FRAMETIME;
-}
+ trail[index] = 240;
+ setPixelColor(index, color_from_palette(trail[index], false, true, 255));
+ }
+ return FRAMETIME;
+}
// smooth meteor effect
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX::mode_meteor_smooth() {
- if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
+ if (!SEGENV.allocateData(SEGLEN)) {
+ return mode_static(); //allocation failed
+ }
+ byte *trail = SEGENV.data;
- byte* trail = SEGENV.data;
-
- byte meteorSize= 1+ SEGLEN / 10;
- uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1);
+ byte meteorSize = 1 + SEGLEN / 10;
+ uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN - 1);
- // fade all leds to colors[1] in LEDs one step
- for (uint16_t i = 0; i < SEGLEN; i++) {
- if (trail[i] != 0 && random8() <= 255 - SEGMENT.intensity)
- {
- int change = 3 - random8(12); //change each time between -8 and +3
- trail[i] += change;
- if (trail[i] > 245) trail[i] = 0;
- if (trail[i] > 240) trail[i] = 240;
- setPixelColor(i, color_from_palette(trail[i], false, true, 255));
+ // fade all leds to colors[1] in LEDs one step
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (trail[i] != 0 && random8() <= 255 - SEGMENT.intensity) {
+ int change = 3 - random8(12); //change each time between -8 and +3
+ trail[i] += change;
+ if (trail[i] > 245) {
+ trail[i] = 0;
+ }
+ if (trail[i] > 240) {
+ trail[i] = 240;
+ }
+ setPixelColor(i, color_from_palette(trail[i], false, true, 255));
+ }
}
- }
-
- // draw meteor
- for(int j = 0; j < meteorSize; j++) {
- uint16_t index = in + j;
- if(in + j >= SEGLEN) {
- index = (in + j - SEGLEN);
+
+ // draw meteor
+ for (int j = 0; j < meteorSize; j++) {
+ uint16_t index = in + j;
+ if (in + j >= SEGLEN) {
+ index = (in + j - SEGLEN);
+ }
+ setPixelColor(index, color_blend(getPixelColor(index), color_from_palette(240, false, true, 255), 48));
+ trail[index] = 240;
}
- setPixelColor(index, color_blend(getPixelColor(index), color_from_palette(240, false, true, 255), 48));
- trail[index] = 240;
- }
- SEGENV.step += SEGMENT.speed +1;
- return FRAMETIME;
+ SEGENV.step += SEGMENT.speed + 1;
+ return FRAMETIME;
}
-
//Railway Crossing / Christmas Fairy lights
-uint16_t WS2812FX::mode_railway()
-{
- uint16_t dur = 40 + (255 - SEGMENT.speed) * 10;
- uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
- if (SEGENV.step > dur)
- {
- //reverse direction
- SEGENV.step = 0;
- SEGENV.aux0 = !SEGENV.aux0;
- }
- uint8_t pos = 255;
- if (rampdur != 0)
- {
- uint16_t p0 = (SEGENV.step * 255) / rampdur;
- if (p0 < 255) pos = p0;
- }
- if (SEGENV.aux0) pos = 255 - pos;
- for (uint16_t i = 0; i < SEGLEN; i += 2)
- {
- setPixelColor(i, color_from_palette(255 - pos, false, false, 255));
- if (i < SEGLEN -1)
- {
- setPixelColor(i + 1, color_from_palette(pos, false, false, 255));
+uint16_t WS2812FX::mode_railway() {
+ uint16_t dur = 40 + (255 - SEGMENT.speed) * 10;
+ uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
+ if (SEGENV.step > dur) {
+ //reverse direction
+ SEGENV.step = 0;
+ SEGENV.aux0 = !SEGENV.aux0;
+ }
+ uint8_t pos = 255;
+ if (rampdur != 0) {
+ uint16_t p0 = (SEGENV.step * 255) / rampdur;
+ if (p0 < 255) {
+ pos = p0;
+ }
}
- }
- SEGENV.step += FRAMETIME;
- return FRAMETIME;
+ if (SEGENV.aux0) {
+ pos = 255 - pos;
+ }
+ for (uint16_t i = 0; i < SEGLEN; i += 2) {
+ setPixelColor(i, color_from_palette(255 - pos, false, false, 255));
+ if (i < SEGLEN - 1) {
+ setPixelColor(i + 1, color_from_palette(pos, false, false, 255));
+ }
+ }
+ SEGENV.step += FRAMETIME;
+ return FRAMETIME;
}
-
//Water ripple
//propagation velocity from speed
//drop rate from intensity
//4 bytes
typedef struct Ripple {
- uint8_t state;
- uint8_t color;
- uint16_t pos;
+ uint8_t state;
+ uint8_t color;
+ uint16_t pos;
} ripple;
#ifdef ESP8266
- #define MAX_RIPPLES 56
+#define MAX_RIPPLES 56
#else
- #define MAX_RIPPLES 100
+#define MAX_RIPPLES 100
#endif
-uint16_t WS2812FX::ripple_base(bool rainbow)
-{
- uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 18 segment ESP8266
- uint16_t dataSize = sizeof(ripple) * maxRipples;
-
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- Ripple* ripples = reinterpret_cast(SEGENV.data);
-
- // ranbow background or chosen background, all very dim.
- if (rainbow) {
- if (SEGENV.call ==0) {
- SEGENV.aux0 = random8();
- SEGENV.aux1 = random8();
- }
- if (SEGENV.aux0 == SEGENV.aux1) {
- SEGENV.aux1 = random8();
- }
- else if (SEGENV.aux1 > SEGENV.aux0) {
- SEGENV.aux0++;
- } else {
- SEGENV.aux0--;
+uint16_t WS2812FX::ripple_base(bool rainbow) {
+ uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 18 segment ESP8266
+ uint16_t dataSize = sizeof(ripple) * maxRipples;
+
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
}
- fill(color_blend(color_wheel(SEGENV.aux0),BLACK,235));
- } else {
- fill(SEGCOLOR(1));
- }
-
- //draw wave
- for (uint16_t i = 0; i < maxRipples; i++)
- {
- uint16_t ripplestate = ripples[i].state;
- if (ripplestate)
- {
- uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation
- uint16_t rippleorigin = ripples[i].pos;
- uint32_t col = color_from_palette(ripples[i].color, false, false, 255);
- uint16_t propagation = ((ripplestate/rippledecay -1) * SEGMENT.speed);
- int16_t propI = propagation >> 8;
- uint8_t propF = propagation & 0xFF;
- int16_t left = rippleorigin - propI -1;
- uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2);
-
- for (int16_t v = left; v < left +4; v++)
- {
- uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
- if (v < SEGLEN && v >= 0)
- {
- setPixelColor(v, color_blend(getPixelColor(v), col, mag));
+
+ Ripple *ripples = reinterpret_cast(SEGENV.data);
+
+ // ranbow background or chosen background, all very dim.
+ if (rainbow) {
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = random8();
+ SEGENV.aux1 = random8();
}
- int16_t w = left + propI*2 + 3 -(v-left);
- if (w < SEGLEN && w >= 0)
+ if (SEGENV.aux0 == SEGENV.aux1) {
+ SEGENV.aux1 = random8();
+ } else if (SEGENV.aux1 > SEGENV.aux0) {
+ SEGENV.aux0++;
+ } else {
+ SEGENV.aux0--;
+ }
+ fill(color_blend(color_wheel(SEGENV.aux0), BLACK, 235));
+ } else {
+ fill(SEGCOLOR(1));
+ }
+
+ //draw wave
+ for (uint16_t i = 0; i < maxRipples; i++) {
+ uint16_t ripplestate = ripples[i].state;
+ if (ripplestate) {
+ uint8_t rippledecay = (SEGMENT.speed >> 4) + 1; //faster decay if faster propagation
+ uint16_t rippleorigin = ripples[i].pos;
+ uint32_t col = color_from_palette(ripples[i].color, false, false, 255);
+ uint16_t propagation = ((ripplestate / rippledecay - 1) * SEGMENT.speed);
+ int16_t propI = propagation >> 8;
+ uint8_t propF = propagation & 0xFF;
+ int16_t left = rippleorigin - propI - 1;
+ uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate - 1) * 8) : map(ripplestate, 17, 255, 255, 2);
+
+ for (int16_t v = left; v < left + 4; v++) {
+ uint8_t mag = scale8(cubicwave8((propF >> 2) + (v - left) * 64), amp);
+ if (v < SEGLEN && v >= 0) {
+ setPixelColor(v, color_blend(getPixelColor(v), col, mag));
+ }
+ int16_t w = left + propI * 2 + 3 - (v - left);
+ if (w < SEGLEN && w >= 0) {
+ setPixelColor(w, color_blend(getPixelColor(w), col, mag));
+ }
+ }
+ ripplestate += rippledecay;
+ ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
+ } else //randomly create new wave
{
- setPixelColor(w, color_blend(getPixelColor(w), col, mag));
+ if (random16(IBN + 10000) <= SEGMENT.intensity) {
+ ripples[i].state = 1;
+ ripples[i].pos = random16(SEGLEN);
+ ripples[i].color = random8(); //color
+ }
}
- }
- ripplestate += rippledecay;
- ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
- } else //randomly create new wave
- {
- if (random16(IBN + 10000) <= SEGMENT.intensity)
- {
- ripples[i].state = 1;
- ripples[i].pos = random16(SEGLEN);
- ripples[i].color = random8(); //color
- }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
#undef MAX_RIPPLES
uint16_t WS2812FX::mode_ripple(void) {
- return ripple_base(false);
+ return ripple_base(false);
}
uint16_t WS2812FX::mode_ripple_rainbow(void) {
- return ripple_base(true);
+ return ripple_base(true);
}
-
-
// TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
//
// TwinkleFOX: Twinkling 'holiday' lights that fade in and out.
@@ -2207,59 +2190,57 @@ uint16_t WS2812FX::mode_ripple_rainbow(void) {
// incandescent bulbs change color as they get dim down.
#define COOL_LIKE_INCANDESCENT 1
-CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
-{
- // Overall twinkle speed (changed)
- uint16_t ticks = ms / SEGENV.aux0;
- uint8_t fastcycle8 = ticks;
- uint16_t slowcycle16 = (ticks >> 8) + salt;
- slowcycle16 += sin8(slowcycle16);
- slowcycle16 = (slowcycle16 * 2053) + 1384;
- uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
-
- // Overall twinkle density.
- // 0 (NONE lit) to 8 (ALL lit at once).
- // Default is 5.
- uint8_t twinkleDensity = (SEGMENT.intensity >> 5) +1;
-
- uint8_t bright = 0;
- if (((slowcycle8 & 0x0E)/2) < twinkleDensity) {
- uint8_t ph = fastcycle8;
- // This is like 'triwave8', which produces a
- // symmetrical up-and-down triangle sawtooth waveform, except that this
- // function produces a triangle wave with a faster attack and a slower decay
- if (cat) //twinklecat, variant where the leds instantly turn on
- {
- bright = 255 - ph;
- } else { //vanilla twinklefox
- if (ph < 86) {
- bright = ph * 3;
- } else {
- ph -= 86;
- bright = 255 - (ph + (ph/2));
- }
+CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) {
+ // Overall twinkle speed (changed) {
+ uint16_t ticks = ms / SEGENV.aux0;
+ uint8_t fastcycle8 = ticks;
+ uint16_t slowcycle16 = (ticks >> 8) + salt;
+ slowcycle16 += sin8(slowcycle16);
+ slowcycle16 = (slowcycle16 * 2053) + 1384;
+ uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
+
+ // Overall twinkle density.
+ // 0 (NONE lit) to 8 (ALL lit at once).
+ // Default is 5.
+ uint8_t twinkleDensity = (SEGMENT.intensity >> 5) + 1;
+
+ uint8_t bright = 0;
+ if (((slowcycle8 & 0x0E) / 2) < twinkleDensity) {
+ uint8_t ph = fastcycle8;
+ // This is like 'triwave8', which produces a
+ // symmetrical up-and-down triangle sawtooth waveform, except that this
+ // function produces a triangle wave with a faster attack and a slower decay
+ if (cat) //twinklecat, variant where the leds instantly turn on
+ {
+ bright = 255 - ph;
+ } else { //vanilla twinklefox
+ if (ph < 86) {
+ bright = ph * 3;
+ } else {
+ ph -= 86;
+ bright = 255 - (ph + (ph / 2));
+ }
+ }
}
- }
-
- uint8_t hue = slowcycle8 - salt;
- CRGB c;
- if (bright > 0) {
- c = ColorFromPalette(currentPalette, hue, bright, NOBLEND);
- if(COOL_LIKE_INCANDESCENT == 1) {
- // This code takes a pixel, and if its in the 'fading down'
- // part of the cycle, it adjusts the color a little bit like the
- // way that incandescent bulbs fade toward 'red' as they dim.
- if (fastcycle8 >= 128)
- {
- uint8_t cooling = (fastcycle8 - 128) >> 4;
- c.g = qsub8(c.g, cooling);
- c.b = qsub8(c.b, cooling * 2);
- }
+
+ uint8_t hue = slowcycle8 - salt;
+ CRGB c;
+ if (bright > 0) {
+ c = ColorFromPalette(currentPalette, hue, bright, NOBLEND);
+ if (COOL_LIKE_INCANDESCENT == 1) {
+ // This code takes a pixel, and if its in the 'fading down'
+ // part of the cycle, it adjusts the color a little bit like the
+ // way that incandescent bulbs fade toward 'red' as they dim.
+ if (fastcycle8 >= 128) {
+ uint8_t cooling = (fastcycle8 - 128) >> 4;
+ c.g = qsub8(c.g, cooling);
+ c.b = qsub8(c.b, cooling * 2);
+ }
+ }
+ } else {
+ c = CRGB::Black;
}
- } else {
- c = CRGB::Black;
- }
- return c;
+ return c;
}
// This function loops over each pixel, calculates the
@@ -2267,360 +2248,358 @@ CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
// "CalculateOneTwinkle" on each pixel. It then displays
// either the twinkle color of the background color,
// whichever is brighter.
-uint16_t WS2812FX::twinklefox_base(bool cat)
-{
- // "PRNG16" is the pseudorandom number generator
- // It MUST be reset to the same starting value each time
- // this function is called, so that the sequence of 'random'
- // numbers that it generates is (paradoxically) stable.
- uint16_t PRNG16 = 11337;
-
- // Calculate speed
- if (SEGMENT.speed > 100) SEGENV.aux0 = 3 + ((255 - SEGMENT.speed) >> 3);
- else SEGENV.aux0 = 22 + ((100 - SEGMENT.speed) >> 1);
-
- // Set up the background color, "bg".
- CRGB bg;
- bg = col_to_crgb(SEGCOLOR(1));
- uint8_t bglight = bg.getAverageLight();
- if (bglight > 64) {
- bg.nscale8_video(16); // very bright, so scale to 1/16th
- } else if (bglight > 16) {
- bg.nscale8_video(64); // not that bright, so scale to 1/4th
- } else {
- bg.nscale8_video(86); // dim, scale to 1/3rd.
- }
-
- uint8_t backgroundBrightness = bg.getAverageLight();
-
- for (uint16_t i = 0; i < SEGLEN; i++) {
-
- PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
- uint16_t myclockoffset16= PRNG16; // use that number as clock offset
- PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
- // use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
- uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
- uint32_t myclock30 = (uint32_t)((now * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
- uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
-
- // We now have the adjusted 'clock' for this pixel, now we call
- // the function that computes what color the pixel should be based
- // on the "brightness = f( time )" idea.
- CRGB c = twinklefox_one_twinkle(myclock30, myunique8, cat);
-
- uint8_t cbright = c.getAverageLight();
- int16_t deltabright = cbright - backgroundBrightness;
- if (deltabright >= 32 || (!bg)) {
- // If the new pixel is significantly brighter than the background color,
- // use the new color.
- setPixelColor(i, c.red, c.green, c.blue);
- } else if (deltabright > 0) {
- // If the new pixel is just slightly brighter than the background color,
- // mix a blend of the new color and the background color
- setPixelColor(i, color_blend(crgb_to_col(bg), crgb_to_col(c), deltabright * 8));
+uint16_t WS2812FX::twinklefox_base(bool cat) {
+ // "PRNG16" is the pseudorandom number generator
+ // It MUST be reset to the same starting value each time
+ // this function is called, so that the sequence of 'random'
+ // numbers that it generates is (paradoxically) stable.
+ uint16_t PRNG16 = 11337;
+
+ // Calculate speed
+ if (SEGMENT.speed > 100) {
+ SEGENV.aux0 = 3 + ((255 - SEGMENT.speed) >> 3);
} else {
- // if the new pixel is not at all brighter than the background color,
- // just use the background color.
- setPixelColor(i, bg.r, bg.g, bg.b);
+ SEGENV.aux0 = 22 + ((100 - SEGMENT.speed) >> 1);
}
- }
- return FRAMETIME;
-}
-uint16_t WS2812FX::mode_twinklefox()
-{
- return twinklefox_base(false);
+ // Set up the background color, "bg".
+ CRGB bg;
+ bg = col_to_crgb(SEGCOLOR(1));
+ uint8_t bglight = bg.getAverageLight();
+ if (bglight > 64) {
+ bg.nscale8_video(16); // very bright, so scale to 1/16th
+ } else if (bglight > 16) {
+ bg.nscale8_video(64); // not that bright, so scale to 1/4th
+ } else {
+ bg.nscale8_video(86); // dim, scale to 1/3rd.
+ }
+
+ uint8_t backgroundBrightness = bg.getAverageLight();
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
+ uint16_t myclockoffset16 = PRNG16; // use that number as clock offset
+ PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
+ // use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
+ uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF) >> 4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
+ uint32_t myclock30 = (uint32_t)((now * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
+ uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
+
+ // We now have the adjusted 'clock' for this pixel, now we call
+ // the function that computes what color the pixel should be based
+ // on the "brightness = f( time )" idea.
+ CRGB c = twinklefox_one_twinkle(myclock30, myunique8, cat);
+
+ uint8_t cbright = c.getAverageLight();
+ int16_t deltabright = cbright - backgroundBrightness;
+ if (deltabright >= 32 || (!bg)) {
+ // If the new pixel is significantly brighter than the background color,
+ // use the new color.
+ setPixelColor(i, c.red, c.green, c.blue);
+ } else if (deltabright > 0) {
+ // If the new pixel is just slightly brighter than the background color,
+ // mix a blend of the new color and the background color
+ setPixelColor(i, color_blend(crgb_to_col(bg), crgb_to_col(c), deltabright * 8));
+ } else {
+ // if the new pixel is not at all brighter than the background color,
+ // just use the background color.
+ setPixelColor(i, bg.r, bg.g, bg.b);
+ }
+ }
+ return FRAMETIME;
}
-uint16_t WS2812FX::mode_twinklecat()
-{
- return twinklefox_base(true);
+uint16_t WS2812FX::mode_twinklefox() {
+ return twinklefox_base(false);
}
+uint16_t WS2812FX::mode_twinklecat() {
+ return twinklefox_base(true);
+}
//inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes
#define HALLOWEEN_EYE_SPACE 3
#define HALLOWEEN_EYE_WIDTH 1
-uint16_t WS2812FX::mode_halloween_eyes()
-{
- uint16_t eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE;
- if (eyeLength > SEGLEN) return mode_static(); //bail if segment too short
-
- fill(SEGCOLOR(1)); //fill background
-
- uint8_t state = SEGENV.aux1 >> 8;
- uint16_t stateTime = SEGENV.call;
- if (stateTime == 0) stateTime = 2000;
-
- if (state == 0) { //spawn eyes
- SEGENV.aux0 = random16(0, SEGLEN - eyeLength); //start pos
- SEGENV.aux1 = random8(); //color
- state = 1;
- }
-
- if (state < 2) { //fade eyes
- uint16_t startPos = SEGENV.aux0;
- uint16_t start2ndEye = startPos + HALLOWEEN_EYE_WIDTH + HALLOWEEN_EYE_SPACE;
-
- uint32_t fadestage = (now - SEGENV.step)*255 / stateTime;
- if (fadestage > 255) fadestage = 255;
- uint32_t c = color_blend(color_from_palette(SEGENV.aux1 & 0xFF, false, false, 0), SEGCOLOR(1), fadestage);
-
- for (uint16_t i = 0; i < HALLOWEEN_EYE_WIDTH; i++)
- {
- setPixelColor(startPos + i, c);
- setPixelColor(start2ndEye + i, c);
+uint16_t WS2812FX::mode_halloween_eyes() {
+ uint16_t eyeLength = (2 * HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE;
+ if (eyeLength > SEGLEN) {
+ return mode_static(); //bail if segment too short
}
- }
- if (now - SEGENV.step > stateTime)
- {
- state++;
- if (state > 2) state = 0;
-
- if (state < 2)
- {
- stateTime = 100 + (255 - SEGMENT.intensity)*10; //eye fade time
- } else {
- uint16_t eyeOffTimeBase = (255 - SEGMENT.speed)*10;
- stateTime = eyeOffTimeBase + random16(eyeOffTimeBase);
+ fill(SEGCOLOR(1)); //fill background
+
+ uint8_t state = SEGENV.aux1 >> 8;
+ uint16_t stateTime = SEGENV.call;
+ if (stateTime == 0) {
+ stateTime = 2000;
}
- SEGENV.step = now;
- SEGENV.call = stateTime;
- }
- SEGENV.aux1 = (SEGENV.aux1 & 0xFF) + (state << 8); //save state
-
- return FRAMETIME;
-}
+ if (state == 0) { //spawn eyes
+ SEGENV.aux0 = random16(0, SEGLEN - eyeLength); //start pos
+ SEGENV.aux1 = random8(); //color
+ state = 1;
+ }
+ if (state < 2) { //fade eyes
+ uint16_t startPos = SEGENV.aux0;
+ uint16_t start2ndEye = startPos + HALLOWEEN_EYE_WIDTH + HALLOWEEN_EYE_SPACE;
-//Speed slider sets amount of LEDs lit, intensity sets unlit
-uint16_t WS2812FX::mode_static_pattern()
-{
- uint16_t lit = 1 + SEGMENT.speed;
- uint16_t unlit = 1 + SEGMENT.intensity;
- bool drawingLit = true;
- uint16_t cnt = 0;
-
- for (uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, (drawingLit) ? color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(1));
- cnt++;
- if (cnt >= ((drawingLit) ? lit : unlit)) {
- cnt = 0;
- drawingLit = !drawingLit;
- }
- }
-
- return FRAMETIME;
-}
-
-uint16_t WS2812FX::mode_tri_static_pattern()
-{
- uint8_t segSize = (SEGMENT.intensity >> 5) +1;
- uint8_t currSeg = 0;
- uint16_t currSegCount = 0;
-
- for (uint16_t i = 0; i < SEGLEN; i++) {
- if ( currSeg % 3 == 0 ) {
- setPixelColor(i, SEGCOLOR(0));
- } else if( currSeg % 3 == 1) {
- setPixelColor(i, SEGCOLOR(1));
- } else {
- setPixelColor(i, (SEGCOLOR(2) > 0 ? SEGCOLOR(2) : WHITE));
+ uint32_t fadestage = (now - SEGENV.step) * 255 / stateTime;
+ if (fadestage > 255) {
+ fadestage = 255;
+ }
+ uint32_t c = color_blend(color_from_palette(SEGENV.aux1 & 0xFF, false, false, 0), SEGCOLOR(1), fadestage);
+
+ for (uint16_t i = 0; i < HALLOWEEN_EYE_WIDTH; i++) {
+ setPixelColor(startPos + i, c);
+ setPixelColor(start2ndEye + i, c);
+ }
}
- currSegCount += 1;
- if (currSegCount >= segSize) {
- currSeg +=1;
- currSegCount = 0;
+
+ if (now - SEGENV.step > stateTime) {
+ state++;
+ if (state > 2) {
+ state = 0;
+ }
+
+ if (state < 2) {
+ stateTime = 100 + (255 - SEGMENT.intensity) * 10; //eye fade time
+ } else {
+ uint16_t eyeOffTimeBase = (255 - SEGMENT.speed) * 10;
+ stateTime = eyeOffTimeBase + random16(eyeOffTimeBase);
+ }
+ SEGENV.step = now;
+ SEGENV.call = stateTime;
}
- }
- return FRAMETIME;
+ SEGENV.aux1 = (SEGENV.aux1 & 0xFF) + (state << 8); //save state
+
+ return FRAMETIME;
}
+//Speed slider sets amount of LEDs lit, intensity sets unlit
+uint16_t WS2812FX::mode_static_pattern() {
+ uint16_t lit = 1 + SEGMENT.speed;
+ uint16_t unlit = 1 + SEGMENT.intensity;
+ bool drawingLit = true;
+ uint16_t cnt = 0;
-uint16_t WS2812FX::spots_base(uint16_t threshold)
-{
- fill(SEGCOLOR(1));
-
- uint16_t maxZones = SEGLEN >> 2;
- uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8);
- uint16_t zoneLen = SEGLEN / zones;
- uint16_t offset = (SEGLEN - zones * zoneLen) >> 1;
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, (drawingLit) ? color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(1));
+ cnt++;
+ if (cnt >= ((drawingLit) ? lit : unlit)) {
+ cnt = 0;
+ drawingLit = !drawingLit;
+ }
+ }
- for (uint16_t z = 0; z < zones; z++)
- {
- uint16_t pos = offset + z * zoneLen;
- for (uint16_t i = 0; i < zoneLen; i++)
- {
- uint16_t wave = triwave16((i * 0xFFFF) / zoneLen);
- if (wave > threshold) {
- uint16_t index = 0 + pos + i;
- uint8_t s = (wave - threshold)*255 / (0xFFFF - threshold);
- setPixelColor(index, color_blend(color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255-s));
- }
+ return FRAMETIME;
+}
+
+uint16_t WS2812FX::mode_tri_static_pattern() {
+ uint8_t segSize = (SEGMENT.intensity >> 5) + 1;
+ uint8_t currSeg = 0;
+ uint16_t currSegCount = 0;
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (currSeg % 3 == 0) {
+ setPixelColor(i, SEGCOLOR(0));
+ } else if (currSeg % 3 == 1) {
+ setPixelColor(i, SEGCOLOR(1));
+ } else {
+ setPixelColor(i, (SEGCOLOR(2) > 0 ? SEGCOLOR(2) : WHITE));
+ }
+ currSegCount += 1;
+ if (currSegCount >= segSize) {
+ currSeg += 1;
+ currSegCount = 0;
+ }
}
- }
-
- return FRAMETIME;
+
+ return FRAMETIME;
}
+uint16_t WS2812FX::spots_base(uint16_t threshold) {
+ fill(SEGCOLOR(1));
+
+ uint16_t maxZones = SEGLEN >> 2;
+ uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8);
+ uint16_t zoneLen = SEGLEN / zones;
+ uint16_t offset = (SEGLEN - zones * zoneLen) >> 1;
+
+ for (uint16_t z = 0; z < zones; z++) {
+ uint16_t pos = offset + z * zoneLen;
+ for (uint16_t i = 0; i < zoneLen; i++) {
+ uint16_t wave = triwave16((i * 0xFFFF) / zoneLen);
+ if (wave > threshold) {
+ uint16_t index = 0 + pos + i;
+ uint8_t s = (wave - threshold) * 255 / (0xFFFF - threshold);
+ setPixelColor(index, color_blend(color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - s));
+ }
+ }
+ }
-//Intensity slider sets number of "lights", speed sets LEDs per light
-uint16_t WS2812FX::mode_spots()
-{
- return spots_base((255 - SEGMENT.speed) << 8);
+ return FRAMETIME;
}
+//Intensity slider sets number of "lights", speed sets LEDs per light
+uint16_t WS2812FX::mode_spots() {
+ return spots_base((255 - SEGMENT.speed) << 8);
+}
//Intensity slider sets number of "lights", LEDs per light fade in and out
-uint16_t WS2812FX::mode_spots_fade()
-{
- uint16_t counter = now * ((SEGMENT.speed >> 2) +8);
- uint16_t t = triwave16(counter);
- uint16_t tr = (t >> 1) + (t >> 2);
- return spots_base(tr);
+uint16_t WS2812FX::mode_spots_fade() {
+ uint16_t counter = now * ((SEGMENT.speed >> 2) + 8);
+ uint16_t t = triwave16(counter);
+ uint16_t tr = (t >> 1) + (t >> 2);
+ return spots_base(tr);
}
-
//each needs 12 bytes
typedef struct Ball {
- unsigned long lastBounceTime;
- float impactVelocity;
- float height;
+ unsigned long lastBounceTime;
+ float impactVelocity;
+ float height;
} ball;
/*
* Bouncing Balls Effect
*/
uint16_t WS2812FX::mode_bouncing_balls(void) {
- //allocate segment data
- uint16_t maxNumBalls = 16;
- uint16_t dataSize = sizeof(ball) * maxNumBalls;
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- Ball* balls = reinterpret_cast(SEGENV.data);
-
- // number of balls based on intensity setting to max of 7 (cycles colors)
- // non-chosen color is a random color
- uint8_t numBalls = int(((SEGMENT.intensity * (maxNumBalls - 0.8f)) / 255) + 1);
-
- float gravity = -9.81; // standard value of gravity
- float impactVelocityStart = sqrt( -2 * gravity);
-
- unsigned long time = millis();
-
- if (SEGENV.call == 0) {
- for (uint8_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time;
- }
-
- bool hasCol2 = SEGCOLOR(2);
- fill(hasCol2 ? BLACK : SEGCOLOR(1));
-
- for (uint8_t i = 0; i < numBalls; i++) {
- float timeSinceLastBounce = (time - balls[i].lastBounceTime)/((255-SEGMENT.speed)*8/256 +1);
- balls[i].height = 0.5 * gravity * pow(timeSinceLastBounce/1000 , 2.0) + balls[i].impactVelocity * timeSinceLastBounce/1000;
-
- if (balls[i].height < 0) { //start bounce
- balls[i].height = 0;
- //damping for better effect using multiple balls
- float dampening = 0.90 - float(i)/pow(numBalls,2);
- balls[i].impactVelocity = dampening * balls[i].impactVelocity;
- balls[i].lastBounceTime = time;
-
- if (balls[i].impactVelocity < 0.015) {
- balls[i].impactVelocity = impactVelocityStart;
- }
+ //allocate segment data
+ uint16_t maxNumBalls = 16;
+ uint16_t dataSize = sizeof(ball) * maxNumBalls;
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
}
-
- uint32_t color = SEGCOLOR(0);
- if (SEGMENT.palette) {
- color = color_wheel(i*(256/MAX(numBalls, 8)));
- } else if (hasCol2) {
- color = SEGCOLOR(i % NUM_COLORS);
+
+ Ball *balls = reinterpret_cast(SEGENV.data);
+
+ // number of balls based on intensity setting to max of 7 (cycles colors)
+ // non-chosen color is a random color
+ uint8_t numBalls = int(((SEGMENT.intensity * (maxNumBalls - 0.8f)) / 255) + 1);
+
+ float gravity = -9.81; // standard value of gravity
+ float impactVelocityStart = sqrt(-2 * gravity);
+
+ unsigned long time = millis();
+
+ if (SEGENV.call == 0) {
+ for (uint8_t i = 0; i < maxNumBalls; i++) {
+ balls[i].lastBounceTime = time;
+ }
}
- uint16_t pos = round(balls[i].height * (SEGLEN - 1));
- setPixelColor(pos, color);
- }
+ bool hasCol2 = SEGCOLOR(2);
+ fill(hasCol2 ? BLACK : SEGCOLOR(1));
- return FRAMETIME;
-}
+ for (uint8_t i = 0; i < numBalls; i++) {
+ float timeSinceLastBounce = (time - balls[i].lastBounceTime) / ((255 - SEGMENT.speed) * 8 / 256 + 1);
+ balls[i].height = 0.5 * gravity * pow(timeSinceLastBounce / 1000, 2.0) + balls[i].impactVelocity * timeSinceLastBounce / 1000;
+
+ if (balls[i].height < 0) { //start bounce
+ balls[i].height = 0;
+ //damping for better effect using multiple balls
+ float dampening = 0.90 - float(i) / pow(numBalls, 2);
+ balls[i].impactVelocity = dampening * balls[i].impactVelocity;
+ balls[i].lastBounceTime = time;
+
+ if (balls[i].impactVelocity < 0.015) {
+ balls[i].impactVelocity = impactVelocityStart;
+ }
+ }
+
+ uint32_t color = SEGCOLOR(0);
+ if (SEGMENT.palette) {
+ color = color_wheel(i * (256 / MAX(numBalls, 8)));
+ } else if (hasCol2) {
+ color = SEGCOLOR(i % NUM_COLORS);
+ }
+
+ uint16_t pos = round(balls[i].height * (SEGLEN - 1));
+ setPixelColor(pos, color);
+ }
+ return FRAMETIME;
+}
/*
* Sinelon stolen from FASTLED examples
*/
-uint16_t WS2812FX::sinelon_base(bool dual, bool rainbow=false) {
- fade_out(SEGMENT.intensity);
- uint16_t pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1);
- if (SEGENV.call == 0) SEGENV.aux0 = pos;
- uint32_t color1 = color_from_palette(pos, true, false, 0);
- uint32_t color2 = SEGCOLOR(2);
- if (rainbow) {
- color1 = color_wheel((pos & 0x07) * 32);
- }
- setPixelColor(pos, color1);
- if (dual) {
- if (!color2) color2 = color_from_palette(pos, true, false, 0);
- if (rainbow) color2 = color1; //rainbow
- setPixelColor(SEGLEN-1-pos, color2);
- }
- if (SEGENV.aux0 != pos) {
- if (SEGENV.aux0 < pos) {
- for (uint16_t i = SEGENV.aux0; i < pos ; i++) {
- setPixelColor(i, color1);
- if (dual) setPixelColor(SEGLEN-1-i, color2);
- }
- } else {
- for (uint16_t i = SEGENV.aux0; i > pos ; i--) {
- setPixelColor(i, color1);
- if (dual) setPixelColor(SEGLEN-1-i, color2);
- }
+uint16_t WS2812FX::sinelon_base(bool dual, bool rainbow = false) {
+ fade_out(SEGMENT.intensity);
+ uint16_t pos = beatsin16(SEGMENT.speed / 10, 0, SEGLEN - 1);
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = pos;
+ }
+ uint32_t color1 = color_from_palette(pos, true, false, 0);
+ uint32_t color2 = SEGCOLOR(2);
+ if (rainbow) {
+ color1 = color_wheel((pos & 0x07) * 32);
+ }
+ setPixelColor(pos, color1);
+ if (dual) {
+ if (!color2) {
+ color2 = color_from_palette(pos, true, false, 0);
+ }
+ if (rainbow) {
+ color2 = color1; //rainbow
+ }
+ setPixelColor(SEGLEN - 1 - pos, color2);
+ }
+ if (SEGENV.aux0 != pos) {
+ if (SEGENV.aux0 < pos) {
+ for (uint16_t i = SEGENV.aux0; i < pos; i++) {
+ setPixelColor(i, color1);
+ if (dual) {
+ setPixelColor(SEGLEN - 1 - i, color2);
+ }
+ }
+ } else {
+ for (uint16_t i = SEGENV.aux0; i > pos; i--) {
+ setPixelColor(i, color1);
+ if (dual) {
+ setPixelColor(SEGLEN - 1 - i, color2);
+ }
+ }
+ }
+ SEGENV.aux0 = pos;
}
- SEGENV.aux0 = pos;
- }
- return FRAMETIME;
+ return FRAMETIME;
}
uint16_t WS2812FX::mode_sinelon(void) {
- return sinelon_base(false);
+ return sinelon_base(false);
}
uint16_t WS2812FX::mode_sinelon_dual(void) {
- return sinelon_base(true);
+ return sinelon_base(true);
}
uint16_t WS2812FX::mode_sinelon_rainbow(void) {
- return sinelon_base(false, true);
+ return sinelon_base(false, true);
}
-
//Rainbow with glitter, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6
-uint16_t WS2812FX::mode_glitter()
-{
- mode_palette();
-
- if (SEGMENT.intensity > random8())
- {
- setPixelColor(random16(SEGLEN), ULTRAWHITE);
- }
-
- return FRAMETIME;
-}
+uint16_t WS2812FX::mode_glitter() {
+ mode_palette();
+ if (SEGMENT.intensity > random8()) {
+ setPixelColor(random16(SEGLEN), ULTRAWHITE);
+ }
+ return FRAMETIME;
+}
//each needs 12 bytes
//Spark type is used for popcorn, 1D fireworks, and drip
typedef struct Spark {
- float pos;
- float vel;
- uint16_t col;
- uint8_t colIndex;
+ float pos;
+ float vel;
+ uint16_t col;
+ uint8_t colIndex;
} spark;
/*
@@ -2628,276 +2607,311 @@ typedef struct Spark {
* modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h
*/
uint16_t WS2812FX::mode_popcorn(void) {
- //allocate segment data
- uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266
- uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- Spark* popcorn = reinterpret_cast(SEGENV.data);
-
- float gravity = -0.0001 - (SEGMENT.speed/200000.0); // m/s/s
- gravity *= SEGLEN;
-
- bool hasCol2 = SEGCOLOR(2);
- fill(hasCol2 ? BLACK : SEGCOLOR(1));
-
- uint8_t numPopcorn = SEGMENT.intensity*maxNumPopcorn/255;
- if (numPopcorn == 0) numPopcorn = 1;
-
- for(uint8_t i = 0; i < numPopcorn; i++) {
- bool isActive = popcorn[i].pos >= 0.0f;
-
- if (isActive) { // if kernel is active, update its position
- popcorn[i].pos += popcorn[i].vel;
- popcorn[i].vel += gravity;
- uint32_t col = color_wheel(popcorn[i].colIndex);
- if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex);
-
- uint16_t ledIndex = popcorn[i].pos;
- if (ledIndex < SEGLEN) setPixelColor(ledIndex, col);
- } else { // if kernel is inactive, randomly pop it
- if (random8() < 2) { // POP!!!
- popcorn[i].pos = 0.01f;
-
- uint16_t peakHeight = 128 + random8(128); //0-255
- peakHeight = (peakHeight * (SEGLEN -1)) >> 8;
- popcorn[i].vel = sqrt(-2.0 * gravity * peakHeight);
-
- if (SEGMENT.palette)
- {
- popcorn[i].colIndex = random8();
- } else {
- byte col = random8(0, NUM_COLORS);
- if (!hasCol2 || !SEGCOLOR(col)) col = 0;
- popcorn[i].colIndex = col;
+ //allocate segment data
+ uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266
+ uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
+
+ Spark *popcorn = reinterpret_cast(SEGENV.data);
+
+ float gravity = -0.0001 - (SEGMENT.speed / 200000.0); // m/s/s
+ gravity *= SEGLEN;
+
+ bool hasCol2 = SEGCOLOR(2);
+ fill(hasCol2 ? BLACK : SEGCOLOR(1));
+
+ uint8_t numPopcorn = SEGMENT.intensity * maxNumPopcorn / 255;
+ if (numPopcorn == 0) {
+ numPopcorn = 1;
+ }
+
+ for (uint8_t i = 0; i < numPopcorn; i++) {
+ bool isActive = popcorn[i].pos >= 0.0f;
+
+ if (isActive) { // if kernel is active, update its position
+ popcorn[i].pos += popcorn[i].vel;
+ popcorn[i].vel += gravity;
+ uint32_t col = color_wheel(popcorn[i].colIndex);
+ if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) {
+ col = SEGCOLOR(popcorn[i].colIndex);
+ }
+
+ uint16_t ledIndex = popcorn[i].pos;
+ if (ledIndex < SEGLEN) {
+ setPixelColor(ledIndex, col);
+ }
+ } else { // if kernel is inactive, randomly pop it
+ if (random8() < 2) { // POP!!!
+ popcorn[i].pos = 0.01f;
+
+ uint16_t peakHeight = 128 + random8(128); //0-255
+ peakHeight = (peakHeight * (SEGLEN - 1)) >> 8;
+ popcorn[i].vel = sqrt(-2.0 * gravity * peakHeight);
+
+ if (SEGMENT.palette) {
+ popcorn[i].colIndex = random8();
+ } else {
+ byte col = random8(0, NUM_COLORS);
+ if (!hasCol2 || !SEGCOLOR(col)) {
+ col = 0;
+ }
+ popcorn[i].colIndex = col;
+ }
+ }
}
- }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-
//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/
-uint16_t WS2812FX::candle(bool multi)
-{
- if (multi)
- {
- //allocate segment data
- uint16_t dataSize = (SEGLEN -1) *3; //max. 1365 pixels (ESP8266)
- if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed
- }
-
- //max. flicker range controlled by intensity
- uint8_t valrange = SEGMENT.intensity;
- uint8_t rndval = valrange >> 1; //max 127
-
- //step (how much to move closer to target per frame) coarsely set by speed
- uint8_t speedFactor = 4;
- if (SEGMENT.speed > 252) { //epilepsy
- speedFactor = 1;
- } else if (SEGMENT.speed > 99) { //regular candle (mode called every ~25 ms, so 4 frames to have a new target every 100ms)
- speedFactor = 2;
- } else if (SEGMENT.speed > 49) { //slower fade
- speedFactor = 3;
- } //else 4 (slowest)
-
- uint16_t numCandles = (multi) ? SEGLEN : 1;
-
- for (uint16_t i = 0; i < numCandles; i++)
- {
- uint16_t d = 0; //data location
-
- uint8_t s = SEGENV.aux0, s_target = SEGENV.aux1, fadeStep = SEGENV.step;
- if (i > 0) {
- d = (i-1) *3;
- s = SEGENV.data[d]; s_target = SEGENV.data[d+1]; fadeStep = SEGENV.data[d+2];
- }
- if (fadeStep == 0) { //init vals
- s = 128; s_target = 130 + random8(4); fadeStep = 1;
- }
-
- bool newTarget = false;
- if (s_target > s) { //fade up
- s = qadd8(s, fadeStep);
- if (s >= s_target) newTarget = true;
- } else {
- s = qsub8(s, fadeStep);
- if (s <= s_target) newTarget = true;
+uint16_t WS2812FX::candle(bool multi) {
+ if (multi) {
+ //allocate segment data
+ uint16_t dataSize = (SEGLEN - 1) * 3; //max. 1365 pixels (ESP8266)
+ if (!SEGENV.allocateData(dataSize)) {
+ return candle(false); //allocation failed
+ }
}
- if (newTarget) {
- s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
- if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval);
- uint8_t offset = (255 - valrange);
- s_target += offset;
+ //max. flicker range controlled by intensity
+ uint8_t valrange = SEGMENT.intensity;
+ uint8_t rndval = valrange >> 1; //max 127
+
+ //step (how much to move closer to target per frame) coarsely set by speed
+ uint8_t speedFactor = 4;
+ if (SEGMENT.speed > 252) { //epilepsy
+ speedFactor = 1;
+ } else if (SEGMENT.speed > 99) { //regular candle (mode called every ~25 ms, so 4 frames to have a new target every 100ms)
+ speedFactor = 2;
+ } else if (SEGMENT.speed > 49) { //slower fade
+ speedFactor = 3;
+ } //else 4 (slowest)
+
+ uint16_t numCandles = (multi) ? SEGLEN : 1;
+
+ for (uint16_t i = 0; i < numCandles; i++) {
+ uint16_t d = 0; //data location
+
+ uint8_t s = SEGENV.aux0, s_target = SEGENV.aux1, fadeStep = SEGENV.step;
+ if (i > 0) {
+ d = (i - 1) * 3;
+ s = SEGENV.data[d];
+ s_target = SEGENV.data[d + 1];
+ fadeStep = SEGENV.data[d + 2];
+ }
+ if (fadeStep == 0) { //init vals
+ s = 128;
+ s_target = 130 + random8(4);
+ fadeStep = 1;
+ }
- uint8_t dif = (s_target > s) ? s_target - s : s - s_target;
-
- fadeStep = dif >> speedFactor;
- if (fadeStep == 0) fadeStep = 1;
- }
+ bool newTarget = false;
+ if (s_target > s) { //fade up
+ s = qadd8(s, fadeStep);
+ if (s >= s_target) {
+ newTarget = true;
+ }
+ } else {
+ s = qsub8(s, fadeStep);
+ if (s <= s_target) {
+ newTarget = true;
+ }
+ }
+
+ if (newTarget) {
+ s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
+ if (s_target < (rndval >> 1)) {
+ s_target = (rndval >> 1) + random8(rndval);
+ }
+ uint8_t offset = (255 - valrange);
+ s_target += offset;
- if (i > 0) {
- setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s));
+ uint8_t dif = (s_target > s) ? s_target - s : s - s_target;
- SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep;
- } else {
- for (uint16_t j = 0; j < SEGLEN; j++) {
- setPixelColor(j, color_blend(SEGCOLOR(1), color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), s));
- }
+ fadeStep = dif >> speedFactor;
+ if (fadeStep == 0) {
+ fadeStep = 1;
+ }
+ }
- SEGENV.aux0 = s; SEGENV.aux1 = s_target; SEGENV.step = fadeStep;
+ if (i > 0) {
+ setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s));
+
+ SEGENV.data[d] = s;
+ SEGENV.data[d + 1] = s_target;
+ SEGENV.data[d + 2] = fadeStep;
+ } else {
+ for (uint16_t j = 0; j < SEGLEN; j++) {
+ setPixelColor(j, color_blend(SEGCOLOR(1), color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), s));
+ }
+
+ SEGENV.aux0 = s;
+ SEGENV.aux1 = s_target;
+ SEGENV.step = fadeStep;
+ }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-uint16_t WS2812FX::mode_candle()
-{
- return candle(false);
+uint16_t WS2812FX::mode_candle() {
+ return candle(false);
}
-
-uint16_t WS2812FX::mode_candle_multi()
-{
- return candle(true);
+uint16_t WS2812FX::mode_candle_multi() {
+ return candle(true);
}
-
/*
/ Fireworks in starburst effect
/ based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/
/ Speed sets frequency of new starbursts, intensity is the intensity of the burst
*/
#ifdef ESP8266
- #define STARBURST_MAX_FRAG 8 //52 bytes / star
+#define STARBURST_MAX_FRAG 8 //52 bytes / star
#else
- #define STARBURST_MAX_FRAG 10 //60 bytes / star
+#define STARBURST_MAX_FRAG 10 //60 bytes / star
#endif
//each needs 20+STARBURST_MAX_FRAG*4 bytes
typedef struct particle {
- CRGB color;
- uint32_t birth =0;
- uint32_t last =0;
- float vel =0;
- uint16_t pos =-1;
- float fragment[STARBURST_MAX_FRAG];
+ CRGB color;
+ uint32_t birth = 0;
+ uint32_t last = 0;
+ float vel = 0;
+ uint16_t pos = -1;
+ float fragment[STARBURST_MAX_FRAG];
} star;
uint16_t WS2812FX::mode_starburst(void) {
- uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
- uint8_t segs = getActiveSegmentsNum();
- if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
- if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
- uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg
-
- uint8_t numStars = 1 + (SEGLEN >> 3);
- if (numStars > maxStars) numStars = maxStars;
- uint16_t dataSize = sizeof(star) * numStars;
-
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- uint32_t it = millis();
-
- star* stars = reinterpret_cast(SEGENV.data);
-
- float maxSpeed = 375.0f; // Max velocity
- float particleIgnition = 250.0f; // How long to "flash"
- float particleFadeTime = 1500.0f; // Fade out time
-
- for (int j = 0; j < numStars; j++)
- {
- // speed to adjust chance of a burst, max is nearly always.
- if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0)
- {
- // Pick a random color and location.
- uint16_t startPos = random16(SEGLEN-1);
- float multiplier = (float)(random8())/255.0 * 1.0;
-
- stars[j].color = col_to_crgb(color_wheel(random8()));
- stars[j].pos = startPos;
- stars[j].vel = maxSpeed * (float)(random8())/255.0 * multiplier;
- stars[j].birth = it;
- stars[j].last = it;
- // more fragments means larger burst effect
- int num = random8(3,6 + (SEGMENT.intensity >> 5));
-
- for (int i=0; i < STARBURST_MAX_FRAG; i++) {
- if (i < num) stars[j].fragment[i] = startPos;
- else stars[j].fragment[i] = -1;
- }
+ uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
+ uint8_t segs = getActiveSegmentsNum();
+ if (segs <= (MAX_NUM_SEGMENTS / 2)) {
+ maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
}
- }
-
- fill(SEGCOLOR(1));
-
- for (int j=0; j> 1;
-
- if (stars[j].fragment[i] > 0) {
- //all fragments travel right, will be mirrored on other side
- stars[j].fragment[i] += stars[j].vel * dt * (float)var/3.0;
- }
- }
- stars[j].last = it;
- stars[j].vel -= 3*stars[j].vel*dt;
+ if (segs <= (MAX_NUM_SEGMENTS / 4)) {
+ maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
}
-
- CRGB c = stars[j].color;
+ uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg
- // If the star is brand new, it flashes white briefly.
- // Otherwise it just fades over time.
- float fade = 0.0f;
- float age = it-stars[j].birth;
+ uint8_t numStars = 1 + (SEGLEN >> 3);
+ if (numStars > maxStars) {
+ numStars = maxStars;
+ }
+ uint16_t dataSize = sizeof(star) * numStars;
- if (age < particleIgnition) {
- c = col_to_crgb(color_blend(WHITE, crgb_to_col(c), 254.5f*((age / particleIgnition))));
- } else {
- // Figure out how much to fade and shrink the star based on
- // its age relative to its lifetime
- if (age > particleIgnition + particleFadeTime) {
- fade = 1.0f; // Black hole, all faded out
- stars[j].birth = 0;
- c = col_to_crgb(SEGCOLOR(1));
- } else {
- age -= particleIgnition;
- fade = (age / particleFadeTime); // Fading star
- byte f = 254.5f*fade;
- c = col_to_crgb(color_blend(crgb_to_col(c), SEGCOLOR(1), f));
- }
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
}
-
- float particleSize = (1.0 - fade) * 2;
-
- for (uint8_t index=0; index < STARBURST_MAX_FRAG*2; index++) {
- bool mirrored = index & 0x1;
- uint8_t i = index >> 1;
- if (stars[j].fragment[i] > 0) {
- float loc = stars[j].fragment[i];
- if (mirrored) loc -= (loc-stars[j].pos)*2;
- int start = loc - particleSize;
- int end = loc + particleSize;
- if (start < 0) start = 0;
- if (start == end) end++;
- if (end > SEGLEN) end = SEGLEN;
- for (int p = start; p < end; p++) {
- setPixelColor(p, c.r, c.g, c.b);
+
+ uint32_t it = millis();
+
+ star *stars = reinterpret_cast(SEGENV.data);
+
+ float maxSpeed = 375.0f; // Max velocity
+ float particleIgnition = 250.0f; // How long to "flash"
+ float particleFadeTime = 1500.0f; // Fade out time
+
+ for (int j = 0; j < numStars; j++) {
+ // speed to adjust chance of a burst, max is nearly always.
+ if (random8((144 - (SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) {
+ // Pick a random color and location.
+ uint16_t startPos = random16(SEGLEN - 1);
+ float multiplier = (float)(random8()) / 255.0 * 1.0;
+
+ stars[j].color = col_to_crgb(color_wheel(random8()));
+ stars[j].pos = startPos;
+ stars[j].vel = maxSpeed * (float)(random8()) / 255.0 * multiplier;
+ stars[j].birth = it;
+ stars[j].last = it;
+ // more fragments means larger burst effect
+ int num = random8(3, 6 + (SEGMENT.intensity >> 5));
+
+ for (int i = 0; i < STARBURST_MAX_FRAG; i++) {
+ if (i < num) {
+ stars[j].fragment[i] = startPos;
+ } else {
+ stars[j].fragment[i] = -1;
+ }
+ }
+ }
+ }
+
+ fill(SEGCOLOR(1));
+
+ for (int j = 0; j < numStars; j++) {
+ if (stars[j].birth != 0) {
+ float dt = (it - stars[j].last) / 1000.0;
+
+ for (int i = 0; i < STARBURST_MAX_FRAG; i++) {
+ int var = i >> 1;
+
+ if (stars[j].fragment[i] > 0) {
+ //all fragments travel right, will be mirrored on other side
+ stars[j].fragment[i] += stars[j].vel * dt * (float)var / 3.0;
+ }
+ }
+ stars[j].last = it;
+ stars[j].vel -= 3 * stars[j].vel * dt;
+ }
+
+ CRGB c = stars[j].color;
+
+ // If the star is brand new, it flashes white briefly.
+ // Otherwise it just fades over time.
+ float fade = 0.0f;
+ float age = it - stars[j].birth;
+
+ if (age < particleIgnition) {
+ c = col_to_crgb(color_blend(WHITE, crgb_to_col(c), 254.5f * ((age / particleIgnition))));
+ } else {
+ // Figure out how much to fade and shrink the star based on
+ // its age relative to its lifetime
+ if (age > particleIgnition + particleFadeTime) {
+ fade = 1.0f; // Black hole, all faded out
+ stars[j].birth = 0;
+ c = col_to_crgb(SEGCOLOR(1));
+ } else {
+ age -= particleIgnition;
+ fade = (age / particleFadeTime); // Fading star
+ byte f = 254.5f * fade;
+ c = col_to_crgb(color_blend(crgb_to_col(c), SEGCOLOR(1), f));
+ }
+ }
+
+ float particleSize = (1.0 - fade) * 2;
+
+ for (uint8_t index = 0; index < STARBURST_MAX_FRAG * 2; index++) {
+ bool mirrored = index & 0x1;
+ uint8_t i = index >> 1;
+ if (stars[j].fragment[i] > 0) {
+ float loc = stars[j].fragment[i];
+ if (mirrored) {
+ loc -= (loc - stars[j].pos) * 2;
+ }
+ int start = loc - particleSize;
+ int end = loc + particleSize;
+ if (start < 0) {
+ start = 0;
+ }
+ if (start == end) {
+ end++;
+ }
+ if (end > SEGLEN) {
+ end = SEGLEN;
+ }
+ for (int p = start; p < end; p++) {
+ setPixelColor(p, c.r, c.g, c.b);
+ }
+ }
}
- }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
#undef STARBURST_MAX_FRAG
#undef STARBURST_MAX_STARS
@@ -2906,371 +2920,390 @@ uint16_t WS2812FX::mode_starburst(void) {
* Exploding fireworks effect
* adapted from: http://www.anirama.com/1000leds/1d-fireworks/
*/
-uint16_t WS2812FX::mode_exploding_fireworks(void)
-{
- //allocate segment data
- uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
- uint8_t segs = getActiveSegmentsNum();
- if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
- if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
- int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg
-
- uint16_t numSparks = min(2 + (SEGLEN >> 1), maxSparks);
- uint16_t dataSize = sizeof(spark) * numSparks;
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated
- SEGENV.aux0 = 0;
- SEGENV.aux1 = dataSize;
- }
-
- fill(BLACK);
-
- bool actuallyReverse = SEGMENT.getOption(SEG_OPTION_REVERSED);
- //have fireworks start in either direction based on intensity
- SEGMENT.setOption(SEG_OPTION_REVERSED, SEGENV.step);
-
- Spark* sparks = reinterpret_cast(SEGENV.data);
- Spark* flare = sparks; //first spark is flare data
-
- float gravity = -0.0004 - (SEGMENT.speed/800000.0); // m/s/s
- gravity *= SEGLEN;
-
- if (SEGENV.aux0 < 2) { //FLARE
- if (SEGENV.aux0 == 0) { //init flare
- flare->pos = 0;
- uint16_t peakHeight = 75 + random8(180); //0-255
- peakHeight = (peakHeight * (SEGLEN -1)) >> 8;
- flare->vel = sqrt(-2.0 * gravity * peakHeight);
- flare->col = 255; //brightness
-
- SEGENV.aux0 = 1;
- }
-
- // launch
- if (flare->vel > 12 * gravity) {
- // flare
- setPixelColor(int(flare->pos),flare->col,flare->col,flare->col);
-
- flare->pos += flare->vel;
- flare->pos = constrain(flare->pos, 0, SEGLEN-1);
- flare->vel += gravity;
- flare->col -= 2;
- } else {
- SEGENV.aux0 = 2; // ready to explode
+uint16_t WS2812FX::mode_exploding_fireworks(void) {
+ //allocate segment data
+ uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
+ uint8_t segs = getActiveSegmentsNum();
+ if (segs <= (MAX_NUM_SEGMENTS / 2)) {
+ maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
+ }
+ if (segs <= (MAX_NUM_SEGMENTS / 4)) {
+ maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
}
- } else if (SEGENV.aux0 < 4) {
- /*
+ int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg
+
+ uint16_t numSparks = min(2 + (SEGLEN >> 1), maxSparks);
+ uint16_t dataSize = sizeof(spark) * numSparks;
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
+
+ if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated
+ SEGENV.aux0 = 0;
+ SEGENV.aux1 = dataSize;
+ }
+
+ fill(BLACK);
+
+ bool actuallyReverse = SEGMENT.getOption(SEG_OPTION_REVERSED);
+ //have fireworks start in either direction based on intensity
+ SEGMENT.setOption(SEG_OPTION_REVERSED, SEGENV.step);
+
+ Spark *sparks = reinterpret_cast(SEGENV.data);
+ Spark *flare = sparks; //first spark is flare data
+
+ float gravity = -0.0004 - (SEGMENT.speed / 800000.0); // m/s/s
+ gravity *= SEGLEN;
+
+ if (SEGENV.aux0 < 2) { //FLARE
+ if (SEGENV.aux0 == 0) { //init flare
+ flare->pos = 0;
+ uint16_t peakHeight = 75 + random8(180); //0-255
+ peakHeight = (peakHeight * (SEGLEN - 1)) >> 8;
+ flare->vel = sqrt(-2.0 * gravity * peakHeight);
+ flare->col = 255; //brightness
+
+ SEGENV.aux0 = 1;
+ }
+
+ // launch
+ if (flare->vel > 12 * gravity) {
+ // flare
+ setPixelColor(int(flare->pos), flare->col, flare->col, flare->col);
+
+ flare->pos += flare->vel;
+ flare->pos = constrain(flare->pos, 0, SEGLEN - 1);
+ flare->vel += gravity;
+ flare->col -= 2;
+ } else {
+ SEGENV.aux0 = 2; // ready to explode
+ }
+ } else if (SEGENV.aux0 < 4) {
+ /*
* Explode!
*
* Explosion happens where the flare ended.
* Size is proportional to the height.
*/
- int nSparks = flare->pos;
- nSparks = constrain(nSparks, 0, numSparks);
- static float dying_gravity;
-
- // initialize sparks
- if (SEGENV.aux0 == 2) {
- for (int i = 1; i < nSparks; i++) {
- sparks[i].pos = flare->pos;
- sparks[i].vel = (float(random16(0, 20000)) / 10000.0) - 0.9; // from -0.9 to 1.1
- sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
- //sparks[i].col = constrain(sparks[i].col, 0, 345);
- sparks[i].colIndex = random8();
- sparks[i].vel *= flare->pos/SEGLEN; // proportional to height
- sparks[i].vel *= -gravity *50;
- }
- //sparks[1].col = 345; // this will be our known spark
- dying_gravity = gravity/2;
- SEGENV.aux0 = 3;
- }
-
- if (sparks[1].col > 4) {//&& sparks[1].pos > 0) { // as long as our known spark is lit, work with all the sparks
- for (int i = 1; i < nSparks; i++) {
- sparks[i].pos += sparks[i].vel;
- sparks[i].vel += dying_gravity;
- if (sparks[i].col > 3) sparks[i].col -= 4;
-
- if (sparks[i].pos > 0 && sparks[i].pos < SEGLEN) {
- uint16_t prog = sparks[i].col;
- uint32_t spColor = (SEGMENT.palette) ? color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
- CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
- if (prog > 300) { //fade from white to spark color
- c = col_to_crgb(color_blend(spColor, WHITE, (prog - 300)*5));
- } else if (prog > 45) { //fade from spark color to black
- c = col_to_crgb(color_blend(BLACK, spColor, prog - 45));
- uint8_t cooling = (300 - prog) >> 5;
- c.g = qsub8(c.g, cooling);
- c.b = qsub8(c.b, cooling * 2);
- }
- setPixelColor(int(sparks[i].pos), c.red, c.green, c.blue);
+ int nSparks = flare->pos;
+ nSparks = constrain(nSparks, 0, numSparks);
+ static float dying_gravity;
+
+ // initialize sparks
+ if (SEGENV.aux0 == 2) {
+ for (int i = 1; i < nSparks; i++) {
+ sparks[i].pos = flare->pos;
+ sparks[i].vel = (float(random16(0, 20000)) / 10000.0) - 0.9; // from -0.9 to 1.1
+ sparks[i].col = 345; //abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
+ //sparks[i].col = constrain(sparks[i].col, 0, 345);
+ sparks[i].colIndex = random8();
+ sparks[i].vel *= flare->pos / SEGLEN; // proportional to height
+ sparks[i].vel *= -gravity * 50;
+ }
+ //sparks[1].col = 345; // this will be our known spark
+ dying_gravity = gravity / 2;
+ SEGENV.aux0 = 3;
+ }
+
+ if (sparks[1].col > 4) { //&& sparks[1].pos > 0) // as long as our known spark is lit, work with all the sparks
+ for (int i = 1; i < nSparks; i++) {
+ sparks[i].pos += sparks[i].vel;
+ sparks[i].vel += dying_gravity;
+ if (sparks[i].col > 3) {
+ sparks[i].col -= 4;
+ }
+
+ if (sparks[i].pos > 0 && sparks[i].pos < SEGLEN) {
+ uint16_t prog = sparks[i].col;
+ uint32_t spColor = (SEGMENT.palette) ? color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
+ CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
+ if (prog > 300) { //fade from white to spark color
+ c = col_to_crgb(color_blend(spColor, WHITE, (prog - 300) * 5));
+ } else if (prog > 45) { //fade from spark color to black
+ c = col_to_crgb(color_blend(BLACK, spColor, prog - 45));
+ uint8_t cooling = (300 - prog) >> 5;
+ c.g = qsub8(c.g, cooling);
+ c.b = qsub8(c.b, cooling * 2);
+ }
+ setPixelColor(int(sparks[i].pos), c.red, c.green, c.blue);
+ }
+ }
+ dying_gravity *= .99; // as sparks burn out they fall slower
+ } else {
+ SEGENV.aux0 = 6 + random8(10); //wait for this many frames
}
- }
- dying_gravity *= .99; // as sparks burn out they fall slower
} else {
- SEGENV.aux0 = 6 + random8(10); //wait for this many frames
- }
- } else {
- SEGENV.aux0--;
- if (SEGENV.aux0 < 4) {
- SEGENV.aux0 = 0; //back to flare
- SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
+ SEGENV.aux0--;
+ if (SEGENV.aux0 < 4) {
+ SEGENV.aux0 = 0; //back to flare
+ SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
+ }
}
- }
- SEGMENT.setOption(SEG_OPTION_REVERSED, actuallyReverse);
-
- return FRAMETIME;
+ SEGMENT.setOption(SEG_OPTION_REVERSED, actuallyReverse);
+
+ return FRAMETIME;
}
#undef MAX_SPARKS
-
/*
* Drip Effect
* ported of: https://www.youtube.com/watch?v=sru2fXh4r7k
*/
-uint16_t WS2812FX::mode_drip(void)
-{
- //allocate segment data
- uint8_t numDrops = 4;
- uint16_t dataSize = sizeof(spark) * numDrops;
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
-
- fill(SEGCOLOR(1));
-
- Spark* drops = reinterpret_cast(SEGENV.data);
-
- numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
-
- float gravity = -0.0005 - (SEGMENT.speed/50000.0);
- gravity *= SEGLEN;
- int sourcedrop = 12;
-
- for (uint8_t j=0;j255) drops[j].col=255;
- setPixelColor(uint16_t(drops[j].pos),color_blend(BLACK,SEGCOLOR(0),drops[j].col));
-
- drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
-
- if (random8() < drops[j].col/10) { // random drop
- drops[j].colIndex=2; //fall
- drops[j].col=255;
- }
- }
- if (drops[j].colIndex > 1) { // falling
- if (drops[j].pos > 0) { // fall until end of segment
- drops[j].pos += drops[j].vel;
- if (drops[j].pos < 0) drops[j].pos = 0;
- drops[j].vel += gravity; // gravity is negative
-
- for (uint16_t i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
- uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
- setPixelColor(pos,color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling
- }
-
- if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
- setPixelColor(0,color_blend(SEGCOLOR(0),BLACK,drops[j].col));
- }
- } else { // we hit bottom
- if (drops[j].colIndex > 2) { // already hit once, so back to forming
- drops[j].colIndex = 0;
- drops[j].col = sourcedrop;
-
- } else {
+uint16_t WS2812FX::mode_drip(void) {
+ //allocate segment data
+ uint8_t numDrops = 4;
+ uint16_t dataSize = sizeof(spark) * numDrops;
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
+
+ fill(SEGCOLOR(1));
+
+ Spark *drops = reinterpret_cast(SEGENV.data);
+
+ numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
- if (drops[j].colIndex==2) { // init bounce
- drops[j].vel = -drops[j].vel/4;// reverse velocity with damping
- drops[j].pos += drops[j].vel;
- }
- drops[j].col = sourcedrop*2;
- drops[j].colIndex = 5; // bouncing
+ float gravity = -0.0005 - (SEGMENT.speed / 50000.0);
+ gravity *= SEGLEN;
+ int sourcedrop = 12;
+
+ for (uint8_t j = 0; j < numDrops; j++) {
+ if (drops[j].colIndex == 0) { //init
+ drops[j].pos = SEGLEN - 1; // start at end
+ drops[j].vel = 0; // speed
+ drops[j].col = sourcedrop; // brightness
+ drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing)
+ }
+
+ setPixelColor(SEGLEN - 1, color_blend(BLACK, SEGCOLOR(0), sourcedrop)); // water source
+ if (drops[j].colIndex == 1) {
+ if (drops[j].col > 255) {
+ drops[j].col = 255;
+ }
+ setPixelColor(uint16_t(drops[j].pos), color_blend(BLACK, SEGCOLOR(0), drops[j].col));
+
+ drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
+
+ if (random8() < drops[j].col / 10) { // random drop
+ drops[j].colIndex = 2; //fall
+ drops[j].col = 255;
+ }
+ }
+ if (drops[j].colIndex > 1) { // falling
+ if (drops[j].pos > 0) { // fall until end of segment
+ drops[j].pos += drops[j].vel;
+ if (drops[j].pos < 0) {
+ drops[j].pos = 0;
+ }
+ drops[j].vel += gravity; // gravity is negative
+
+ for (uint16_t i = 1; i < 7 - drops[j].colIndex; i++) { // some minor math so we don't expand bouncing droplets
+ uint16_t pos = constrain(uint16_t(drops[j].pos) + i, 0, SEGLEN - 1); //this is BAD, returns a pos >= SEGLEN occasionally
+ setPixelColor(pos, color_blend(BLACK, SEGCOLOR(0), drops[j].col / i)); //spread pixel with fade while falling
+ }
+
+ if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
+ setPixelColor(0, color_blend(SEGCOLOR(0), BLACK, drops[j].col));
+ }
+ } else { // we hit bottom
+ if (drops[j].colIndex > 2) { // already hit once, so back to forming
+ drops[j].colIndex = 0;
+ drops[j].col = sourcedrop;
+ } else {
+ if (drops[j].colIndex == 2) { // init bounce
+ drops[j].vel = -drops[j].vel / 4; // reverse velocity with damping
+ drops[j].pos += drops[j].vel;
+ }
+ drops[j].col = sourcedrop * 2;
+ drops[j].colIndex = 5; // bouncing
+ }
+ }
}
- }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
-
/*
* Tetris or Stacking (falling bricks) Effect
* by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home)
*/
//12 bytes
typedef struct Tetris {
- float pos;
- float speed;
- uint32_t col;
+ float pos;
+ float speed;
+ uint32_t col;
} tetris;
uint16_t WS2812FX::mode_tetrix(void) {
+ uint16_t dataSize = sizeof(tetris);
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
+ Tetris *drop = reinterpret_cast(SEGENV.data);
+
+ // initialize dropping on first call or segment full
+ if (SEGENV.call == 0 || SEGENV.aux1 >= SEGLEN) {
+ SEGENV.aux1 = 0; // reset brick stack size
+ SEGENV.step = 0;
+ fill(SEGCOLOR(1));
+ return 250; // short wait
+ }
- uint16_t dataSize = sizeof(tetris);
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
- Tetris* drop = reinterpret_cast(SEGENV.data);
+ if (SEGENV.step == 0) { //init
+ drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed >> 2) + 1 : random8(6, 64)); // set speed
+ drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
+ drop->col = color_from_palette(random8(0, 15) << 4, false, false, 0); // limit color choices so there is enough HUE gap
+ SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
+ SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity >> 5) + 1 : random8(1, 5)) * (1 + (SEGLEN >> 6)); // size of brick
+ }
- // initialize dropping on first call or segment full
- if (SEGENV.call == 0 || SEGENV.aux1 >= SEGLEN) {
- SEGENV.aux1 = 0; // reset brick stack size
- SEGENV.step = 0;
- fill(SEGCOLOR(1));
- return 250; // short wait
- }
-
- if (SEGENV.step == 0) { //init
- drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>2)+1 : random8(6,64)); // set speed
- drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
- drop->col = color_from_palette(random8(0,15)<<4,false,false,0); // limit color choices so there is enough HUE gap
- SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
- SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
- }
-
- if (SEGENV.step == 1) { // forming
- if (random8()>>6) { // random drop
- SEGENV.step = 2; // fall
- }
- }
-
- if (SEGENV.step > 1) { // falling
- if (drop->pos > SEGENV.aux1) { // fall until top of stack
- drop->pos -= drop->speed; // may add gravity as: speed += gravity
- if (int(drop->pos) < SEGENV.aux1) drop->pos = SEGENV.aux1;
- for (uint16_t i=int(drop->pos); ipos)+SEGENV.aux0 ? drop->col : SEGCOLOR(1));
- } else { // we hit bottom
- SEGENV.step = 0; // go back to init
- SEGENV.aux1 += SEGENV.aux0; // increase the stack size
- if (SEGENV.aux1 >= SEGLEN) return 1000; // wait for a second
- }
- }
- return FRAMETIME;
-}
+ if (SEGENV.step == 1) { // forming
+ if (random8() >> 6) { // random drop
+ SEGENV.step = 2; // fall
+ }
+ }
+ if (SEGENV.step > 1) { // falling
+ if (drop->pos > SEGENV.aux1) { // fall until top of stack
+ drop->pos -= drop->speed; // may add gravity as: speed += gravity
+ if (int(drop->pos) < SEGENV.aux1) {
+ drop->pos = SEGENV.aux1;
+ }
+ for (uint16_t i = int(drop->pos); i < SEGLEN; i++) {
+ setPixelColor(i, i < int(drop->pos) + SEGENV.aux0 ? drop->col : SEGCOLOR(1));
+ }
+ } else { // we hit bottom
+ SEGENV.step = 0; // go back to init
+ SEGENV.aux1 += SEGENV.aux0; // increase the stack size
+ if (SEGENV.aux1 >= SEGLEN) {
+ return 1000; // wait for a second
+ }
+ }
+ }
+ return FRAMETIME;
+}
/*
/ Plasma Effect
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
*/
uint16_t WS2812FX::mode_plasma(void) {
- // initialize phases on start
- if (SEGENV.call == 0) {
- SEGENV.aux0 = random8(0,2); // add a bit of randomness
- }
- uint8_t thisPhase = beatsin8(6+SEGENV.aux0,-64,64);
- uint8_t thatPhase = beatsin8(7+SEGENV.aux0,-64,64);
-
- for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
- uint8_t colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
- + cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish.
- uint8_t thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1))));
- CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
- setPixelColor(i, color.red, color.green, color.blue);
- }
-
- return FRAMETIME;
-}
+ // initialize phases on start
+ if (SEGENV.call == 0) {
+ SEGENV.aux0 = random8(0, 2); // add a bit of randomness
+ }
+ uint8_t thisPhase = beatsin8(6 + SEGENV.aux0, -64, 64);
+ uint8_t thatPhase = beatsin8(7 + SEGENV.aux0, -64, 64);
+
+ for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
+ uint8_t colorIndex = cubicwave8((i * (2 + 3 * (SEGMENT.speed >> 5)) + thisPhase) & 0xFF) / 2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
+ + cos8((i * (1 + 2 * (SEGMENT.speed >> 5)) + thatPhase) & 0xFF) / 2; // factor=15 // Hey, you can even change the frequencies if you wish.
+ uint8_t thisBright = qsub8(colorIndex, beatsin8(7, 0, (128 - (SEGMENT.intensity >> 1))));
+ CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
+ setPixelColor(i, color.red, color.green, color.blue);
+ }
+ return FRAMETIME;
+}
/*
* Percentage display
* Intesity values from 0-100 turn on the leds.
*/
uint16_t WS2812FX::mode_percent(void) {
+ uint8_t percent = MAX(0, MIN(200, SEGMENT.intensity));
+ uint16_t active_leds = (percent < 100) ? SEGLEN * percent / 100.0
+ : SEGLEN * (200 - percent) / 100.0;
- uint8_t percent = MAX(0, MIN(200, SEGMENT.intensity));
- uint16_t active_leds = (percent < 100) ? SEGLEN * percent / 100.0
- : SEGLEN * (200 - percent) / 100.0;
-
- uint8_t size = (1 + ((SEGMENT.speed * SEGLEN) >> 11));
- if (SEGMENT.speed == 255) size = 255;
-
- if (percent < 100) {
- for (uint16_t i = 0; i < SEGLEN; i++) {
- if (i < SEGENV.step) {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- }
- else {
- setPixelColor(i, SEGCOLOR(1));
- }
- }
- } else {
- for (uint16_t i = 0; i < SEGLEN; i++) {
- if (i < (SEGLEN - SEGENV.step)) {
- setPixelColor(i, SEGCOLOR(1));
- }
- else {
- setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- }
- }
- }
+ uint8_t size = (1 + ((SEGMENT.speed * SEGLEN) >> 11));
+ if (SEGMENT.speed == 255) {
+ size = 255;
+ }
- if(active_leds > SEGENV.step) { // smooth transition to the target value
- SEGENV.step += size;
- if (SEGENV.step > active_leds) SEGENV.step = active_leds;
- } else if (active_leds < SEGENV.step) {
- if (SEGENV.step > size) SEGENV.step -= size; else SEGENV.step = 0;
- if (SEGENV.step < active_leds) SEGENV.step = active_leds;
- }
+ if (percent < 100) {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (i < SEGENV.step) {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ } else {
+ setPixelColor(i, SEGCOLOR(1));
+ }
+ }
+ } else {
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ if (i < (SEGLEN - SEGENV.step)) {
+ setPixelColor(i, SEGCOLOR(1));
+ } else {
+ setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+ }
+ }
+ }
+
+ if (active_leds > SEGENV.step) { // smooth transition to the target value
+ SEGENV.step += size;
+ if (SEGENV.step > active_leds) {
+ SEGENV.step = active_leds;
+ }
+ } else if (active_leds < SEGENV.step) {
+ if (SEGENV.step > size) {
+ SEGENV.step -= size;
+ } else {
+ SEGENV.step = 0;
+ }
+ if (SEGENV.step < active_leds) {
+ SEGENV.step = active_leds;
+ }
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
/*
/ Modulates the brightness similar to a heartbeat
*/
uint16_t WS2812FX::mode_heartbeat(void) {
- uint8_t bpm = 40 + (SEGMENT.speed >> 4);
- uint32_t msPerBeat = (60000 / bpm);
- uint32_t secondBeat = (msPerBeat / 3);
-
- uint32_t bri_lower = SEGENV.aux1;
- bri_lower = bri_lower * 2042 / (2048 + SEGMENT.intensity);
- SEGENV.aux1 = bri_lower;
-
- unsigned long beatTimer = millis() - SEGENV.step;
- if((beatTimer > secondBeat) && !SEGENV.aux0) { // time for the second beat?
- SEGENV.aux1 = UINT16_MAX; //full bri
- SEGENV.aux0 = 1;
- }
- if(beatTimer > msPerBeat) { // time to reset the beat timer?
- SEGENV.aux1 = UINT16_MAX; //full bri
- SEGENV.aux0 = 0;
- SEGENV.step = millis();
- }
+ uint8_t bpm = 40 + (SEGMENT.speed >> 4);
+ uint32_t msPerBeat = (60000 / bpm);
+ uint32_t secondBeat = (msPerBeat / 3);
+
+ uint32_t bri_lower = SEGENV.aux1;
+ bri_lower = bri_lower * 2042 / (2048 + SEGMENT.intensity);
+ SEGENV.aux1 = bri_lower;
+
+ unsigned long beatTimer = millis() - SEGENV.step;
+ if ((beatTimer > secondBeat) && !SEGENV.aux0) { // time for the second beat?
+ SEGENV.aux1 = UINT16_MAX; //full bri
+ SEGENV.aux0 = 1;
+ }
+ if (beatTimer > msPerBeat) { // time to reset the beat timer?
+ SEGENV.aux1 = UINT16_MAX; //full bri
+ SEGENV.aux0 = 0;
+ SEGENV.step = millis();
+ }
- for (uint16_t i = 0; i < SEGLEN; i++) {
- setPixelColor(i, color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - (SEGENV.aux1 >> 8)));
- }
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - (SEGENV.aux1 >> 8)));
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
-
// "Pacifica"
// Gentle, blue-green ocean waves.
// December 2019, Mark Kriegsman and Mary Corey March.
// For Dan.
//
//
-// In this animation, there are four "layers" of waves of light.
+// In this animation, there are four "layers" of waves of light.
//
// Each layer moves independently, and each is scaled separately.
//
-// All four wave layers are added together on top of each other, and then
-// another filter is applied that adds "whitecaps" of brightness where the
+// All four wave layers are added together on top of each other, and then
+// another filter is applied that adds "whitecaps" of brightness where the
// waves line up with each other more. Finally, another pass is taken
// over the led array to 'deepen' (dim) the blues and greens.
//
-// The speed and scale and motion each layer varies slowly within independent
+// The speed and scale and motion each layer varies slowly within independent
// hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions
// with a lot of oddly specific numeric ranges.
//
@@ -3279,361 +3312,363 @@ uint16_t WS2812FX::mode_heartbeat(void) {
//
// Modified for WLED, based on https://github.com/FastLED/FastLED/blob/master/examples/Pacifica/Pacifica.ino
//
-uint16_t WS2812FX::mode_pacifica()
-{
- uint32_t nowOld = now;
-
- CRGBPalette16 pacifica_palette_1 =
- { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
- 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
- CRGBPalette16 pacifica_palette_2 =
- { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
- 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F };
- CRGBPalette16 pacifica_palette_3 =
- { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33,
- 0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF };
-
- if (SEGMENT.palette) {
- pacifica_palette_1 = currentPalette;
- pacifica_palette_2 = currentPalette;
- pacifica_palette_3 = currentPalette;
- }
-
- // Increment the four "color index start" counters, one for each wave layer.
- // Each is incremented at a different speed, and the speeds vary over time.
- uint16_t sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step, sCIStart4 = SEGENV.step >> 16;
- //static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
- //uint32_t deltams = 26 + (SEGMENT.speed >> 3);
- uint32_t deltams = (FRAMETIME >> 2) + ((FRAMETIME * SEGMENT.speed) >> 7);
- uint64_t deltat = (now >> 2) + ((now * SEGMENT.speed) >> 7);
- now = deltat;
-
- uint16_t speedfactor1 = beatsin16(3, 179, 269);
- uint16_t speedfactor2 = beatsin16(4, 179, 269);
- uint32_t deltams1 = (deltams * speedfactor1) / 256;
- uint32_t deltams2 = (deltams * speedfactor2) / 256;
- uint32_t deltams21 = (deltams1 + deltams2) / 2;
- sCIStart1 += (deltams1 * beatsin88(1011,10,13));
- sCIStart2 -= (deltams21 * beatsin88(777,8,11));
- sCIStart3 -= (deltams1 * beatsin88(501,5,7));
- sCIStart4 -= (deltams2 * beatsin88(257,4,6));
- SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2;
- SEGENV.step = sCIStart4; SEGENV.step = (SEGENV.step << 16) + sCIStart3;
-
- // Clear out the LED array to a dim background blue-green
- //fill(132618);
-
- uint8_t basethreshold = beatsin8( 9, 55, 65);
- uint8_t wave = beat8( 7 );
-
- for( uint16_t i = 0; i < SEGLEN; i++) {
- CRGB c = CRGB(2, 6, 10);
- // Render each of four layers, with different scales and speeds, that vary over time
- c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301));
- c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401));
- c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8(9, 10,38) , 0-beat16(503));
- c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8(8, 10,28) , beat16(601));
-
- // Add extra 'white' to areas where the four layers of light have lined up brightly
- uint8_t threshold = scale8( sin8( wave), 20) + basethreshold;
- wave += 7;
- uint8_t l = c.getAverageLight();
- if (l > threshold) {
- uint8_t overage = l - threshold;
- uint8_t overage2 = qadd8(overage, overage);
- c += CRGB(overage, overage2, qadd8(overage2, overage2));
- }
-
- //deepen the blues and greens
- c.blue = scale8(c.blue, 145);
- c.green = scale8(c.green, 200);
- c |= CRGB( 2, 5, 7);
-
- setPixelColor(i, c.red, c.green, c.blue);
- }
-
- now = nowOld;
- return FRAMETIME;
+uint16_t WS2812FX::mode_pacifica() {
+ uint32_t nowOld = now;
+
+ CRGBPalette16 pacifica_palette_1 =
+ {0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
+ 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50};
+ CRGBPalette16 pacifica_palette_2 =
+ {0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
+ 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F};
+ CRGBPalette16 pacifica_palette_3 =
+ {0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33,
+ 0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF};
+
+ if (SEGMENT.palette) {
+ pacifica_palette_1 = currentPalette;
+ pacifica_palette_2 = currentPalette;
+ pacifica_palette_3 = currentPalette;
+ }
+
+ // Increment the four "color index start" counters, one for each wave layer.
+ // Each is incremented at a different speed, and the speeds vary over time.
+ uint16_t sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step, sCIStart4 = SEGENV.step >> 16;
+ //static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
+ //uint32_t deltams = 26 + (SEGMENT.speed >> 3);
+ uint32_t deltams = (FRAMETIME >> 2) + ((FRAMETIME * SEGMENT.speed) >> 7);
+ uint64_t deltat = (now >> 2) + ((now * SEGMENT.speed) >> 7);
+ now = deltat;
+
+ uint16_t speedfactor1 = beatsin16(3, 179, 269);
+ uint16_t speedfactor2 = beatsin16(4, 179, 269);
+ uint32_t deltams1 = (deltams * speedfactor1) / 256;
+ uint32_t deltams2 = (deltams * speedfactor2) / 256;
+ uint32_t deltams21 = (deltams1 + deltams2) / 2;
+ sCIStart1 += (deltams1 * beatsin88(1011, 10, 13));
+ sCIStart2 -= (deltams21 * beatsin88(777, 8, 11));
+ sCIStart3 -= (deltams1 * beatsin88(501, 5, 7));
+ sCIStart4 -= (deltams2 * beatsin88(257, 4, 6));
+ SEGENV.aux0 = sCIStart1;
+ SEGENV.aux1 = sCIStart2;
+ SEGENV.step = sCIStart4;
+ SEGENV.step = (SEGENV.step << 16) + sCIStart3;
+
+ // Clear out the LED array to a dim background blue-green
+ //fill(132618);
+
+ uint8_t basethreshold = beatsin8(9, 55, 65);
+ uint8_t wave = beat8(7);
+
+ for (uint16_t i = 0; i < SEGLEN; i++) {
+ CRGB c = CRGB(2, 6, 10);
+ // Render each of four layers, with different scales and speeds, that vary over time
+ c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0 - beat16(301));
+ c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401));
+ c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256, beatsin8(9, 10, 38), 0 - beat16(503));
+ c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256, beatsin8(8, 10, 28), beat16(601));
+
+ // Add extra 'white' to areas where the four layers of light have lined up brightly
+ uint8_t threshold = scale8(sin8(wave), 20) + basethreshold;
+ wave += 7;
+ uint8_t l = c.getAverageLight();
+ if (l > threshold) {
+ uint8_t overage = l - threshold;
+ uint8_t overage2 = qadd8(overage, overage);
+ c += CRGB(overage, overage2, qadd8(overage2, overage2));
+ }
+
+ //deepen the blues and greens
+ c.blue = scale8(c.blue, 145);
+ c.green = scale8(c.green, 200);
+ c |= CRGB(2, 5, 7);
+
+ setPixelColor(i, c.red, c.green, c.blue);
+ }
+
+ now = nowOld;
+ return FRAMETIME;
}
// Add one layer of waves into the led array
-CRGB WS2812FX::pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
-{
- uint16_t ci = cistart;
- uint16_t waveangle = ioff;
- uint16_t wavescale_half = (wavescale >> 1) + 20;
-
- waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i
- uint16_t s16 = sin16(waveangle) + 32768;
- uint16_t cs = scale16(s16, wavescale_half) + wavescale_half;
- ci += (cs * i);
- uint16_t sindex16 = sin16(ci) + 32768;
- uint8_t sindex8 = scale16(sindex16, 240);
- return ColorFromPalette(p, sindex8, bri, LINEARBLEND);
+CRGB WS2812FX::pacifica_one_layer(uint16_t i, CRGBPalette16 &p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) {
+ uint16_t ci = cistart;
+ uint16_t waveangle = ioff;
+ uint16_t wavescale_half = (wavescale >> 1) + 20;
+
+ waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i
+ uint16_t s16 = sin16(waveangle) + 32768;
+ uint16_t cs = scale16(s16, wavescale_half) + wavescale_half;
+ ci += (cs * i);
+ uint16_t sindex16 = sin16(ci) + 32768;
+ uint8_t sindex8 = scale16(sindex16, 240);
+ return ColorFromPalette(p, sindex8, bri, LINEARBLEND);
}
//Solid colour background with glitter
-uint16_t WS2812FX::mode_solid_glitter()
-{
- fill(SEGCOLOR(0));
+uint16_t WS2812FX::mode_solid_glitter() {
+ fill(SEGCOLOR(0));
- if (SEGMENT.intensity > random8())
- {
- setPixelColor(random16(SEGLEN), ULTRAWHITE);
- }
- return FRAMETIME;
+ if (SEGMENT.intensity > random8()) {
+ setPixelColor(random16(SEGLEN), ULTRAWHITE);
+ }
+ return FRAMETIME;
}
-
/*
* Mode simulates a gradual sunrise
*/
uint16_t WS2812FX::mode_sunrise() {
- //speed 0 - static sun
- //speed 1 - 60: sunrise time in minutes
- //speed 60 - 120 : sunset time in minutes - 60;
- //speed above: "breathing" rise and set
- if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) {
- SEGENV.step = millis(); //save starting time, millis() because now can change from sync
- SEGENV.aux0 = SEGMENT.speed;
- }
-
- fill(0);
- uint16_t stage = 0xFFFF;
-
- uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds
-
- if (SEGMENT.speed > 120) { //quick sunrise and sunset
- uint16_t counter = (now >> 1) * (((SEGMENT.speed -120) >> 1) +1);
- stage = triwave16(counter);
- } else if (SEGMENT.speed) { //sunrise
- uint8_t durMins = SEGMENT.speed;
- if (durMins > 60) durMins -= 60;
- uint32_t s10Target = durMins * 600;
- if (s10SinceStart > s10Target) s10SinceStart = s10Target;
- stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF);
- if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset
- }
-
- for (uint16_t i = 0; i <= SEGLEN/2; i++)
- {
- //default palette is Fire
- uint32_t c = color_from_palette(0, false, true, 255); //background
-
- uint16_t wave = triwave16((i * stage) / SEGLEN);
-
- wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15);
-
- if (wave > 240) { //clipped, full white sun
- c = color_from_palette( 240, false, true, 255);
- } else { //transition
- c = color_from_palette(wave, false, true, 255);
- }
- setPixelColor(i, c);
- setPixelColor(SEGLEN - i - 1, c);
- }
-
- return FRAMETIME;
-}
+ //speed 0 - static sun
+ //speed 1 - 60: sunrise time in minutes
+ //speed 60 - 120 : sunset time in minutes - 60;
+ //speed above: "breathing" rise and set
+ if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) {
+ SEGENV.step = millis(); //save starting time, millis() because now can change from sync
+ SEGENV.aux0 = SEGMENT.speed;
+ }
+
+ fill(0);
+ uint16_t stage = 0xFFFF;
+ uint32_t s10SinceStart = (millis() - SEGENV.step) / 100; //tenths of seconds
+
+ if (SEGMENT.speed > 120) { //quick sunrise and sunset
+ uint16_t counter = (now >> 1) * (((SEGMENT.speed - 120) >> 1) + 1);
+ stage = triwave16(counter);
+ } else if (SEGMENT.speed) { //sunrise
+ uint8_t durMins = SEGMENT.speed;
+ if (durMins > 60) {
+ durMins -= 60;
+ }
+ uint32_t s10Target = durMins * 600;
+ if (s10SinceStart > s10Target) {
+ s10SinceStart = s10Target;
+ }
+ stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF);
+ if (SEGMENT.speed > 60) {
+ stage = 0xFFFF - stage; //sunset
+ }
+ }
+
+ for (uint16_t i = 0; i <= SEGLEN / 2; i++) {
+ //default palette is Fire
+ uint32_t c = color_from_palette(0, false, true, 255); //background
+
+ uint16_t wave = triwave16((i * stage) / SEGLEN);
+
+ wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15);
+
+ if (wave > 240) { //clipped, full white sun
+ c = color_from_palette(240, false, true, 255);
+ } else { //transition
+ c = color_from_palette(wave, false, true, 255);
+ }
+ setPixelColor(i, c);
+ setPixelColor(SEGLEN - i - 1, c);
+ }
+
+ return FRAMETIME;
+}
/*
* Effects by Andrew Tuline
*/
-uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline.
+uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline.
- uint8_t allfreq = 16; // Base frequency.
- //float* phasePtr = reinterpret_cast(SEGENV.step); // Phase change value gets calculated.
- static float phase = 0;//phasePtr[0];
- uint8_t cutOff = (255-SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192).
- uint8_t modVal = 5;//SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5).
+ uint8_t allfreq = 16; // Base frequency.
+ //float* phasePtr = reinterpret_cast(SEGENV.step); // Phase change value gets calculated.
+ static float phase = 0; //phasePtr[0];
+ uint8_t cutOff = (255 - SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192).
+ uint8_t modVal = 5; //SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5).
- uint8_t index = now/64; // Set color rotation speed
- phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4)
- //phasePtr[0] = phase;
+ uint8_t index = now / 64; // Set color rotation speed
+ phase += SEGMENT.speed / 32.0; // You can change the speed of the wave. AKA SPEED (was .4)
+ //phasePtr[0] = phase;
- for (int i = 0; i < SEGLEN; i++) {
- if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise.
- uint16_t val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used.
- if (modVal == 0) modVal = 1;
- val += phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline.
- uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave.
- b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
- setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b));
- index += 256 / SEGLEN;
- if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs
- }
+ for (int i = 0; i < SEGLEN; i++) {
+ if (moder == 1) {
+ modVal = (inoise8(i * 10 + i * 10) / 16); // Let's randomize our mod length with some Perlin noise.
+ }
+ uint16_t val = (i + 1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used.
+ if (modVal == 0) {
+ modVal = 1;
+ }
+ val += phase * (i % modVal + 1) / 2; // This sets the varying phase change of the waves. By Andrew Tuline.
+ uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave.
+ b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
+ setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b));
+ index += 256 / SEGLEN;
+ if (SEGLEN > 256) {
+ index++; // Correction for segments longer than 256 LEDs
+ }
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
-
-
uint16_t WS2812FX::mode_phased(void) {
- return phased_base(0);
+ return phased_base(0);
}
-
-
uint16_t WS2812FX::mode_phased_noise(void) {
- return phased_base(1);
+ return phased_base(1);
}
+uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
+ random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
+ for (int i = 0; i < SEGLEN; i++) {
+ uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work.
+ uint8_t pixBri = sin8(ranstart + 16 * now / (256 - SEGMENT.speed));
+ if (random8() > SEGMENT.intensity) {
+ pixBri = 0;
+ }
+ setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(random8() + now / 100, false, PALETTE_SOLID_WRAP, 0), pixBri));
+ }
-uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
- random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
-
- for (int i = 0; i SEGMENT.intensity) pixBri = 0;
- setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(random8()+now/100, false, PALETTE_SOLID_WRAP, 0), pixBri));
- }
-
- return FRAMETIME;
+ return FRAMETIME;
}
-
// Peaceful noise that's slow and with gradually changing palettes. Does not support WLED palettes or default colours or controls.
-uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline.
- uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
- //#define scale 30
+uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline.
+ uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
+ //#define scale 30
- uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes)
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
+ uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes)
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
- CRGBPalette16* palettes = reinterpret_cast(SEGENV.data);
+ CRGBPalette16 *palettes = reinterpret_cast(SEGENV.data);
- uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec
- if (millis() - SEGENV.step > changePaletteMs)
- {
- SEGENV.step = millis();
+ uint16_t changePaletteMs = 4000 + SEGMENT.speed * 10; //between 4 - 6.5sec
+ if (millis() - SEGENV.step > changePaletteMs) {
+ SEGENV.step = millis();
- uint8_t baseI = random8();
- palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255)));
- }
+ uint8_t baseI = random8();
+ palettes[1] = CRGBPalette16(CHSV(baseI + random8(64), 255, random8(128, 255)), CHSV(baseI + 128, 255, random8(128, 255)), CHSV(baseI + random8(92), 192, random8(128, 255)), CHSV(baseI + random8(92), 255, random8(128, 255)));
+ }
- CRGB color;
+ CRGB color;
- //EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms)
- nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations.
+ //EVERY_N_MILLIS(10) //(don't have to time this, effect function is only called every 24ms)
+ nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations.
- if (SEGMENT.palette > 0) palettes[0] = currentPalette;
+ if (SEGMENT.palette > 0) {
+ palettes[0] = currentPalette;
+ }
- for(int i = 0; i < SEGLEN; i++) {
- uint8_t index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis.
- color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette.
- setPixelColor(i, color.red, color.green, color.blue);
- }
+ for (int i = 0; i < SEGLEN; i++) {
+ uint8_t index = inoise8(i * scale, SEGENV.aux0 + i * scale); // Get a value from the noise function. I'm using both x and y axis.
+ color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette.
+ setPixelColor(i, color.red, color.green, color.blue);
+ }
- SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave.
+ SEGENV.aux0 += beatsin8(10, 1, 4); // Moving along the distance. Vary it a bit with a sine wave.
- return FRAMETIME;
+ return FRAMETIME;
}
-
// Sine waves that have controllable phase change speed, frequency and cutoff. By Andrew Tuline.
// SEGMENT.speed ->Speed, SEGMENT.intensity -> Frequency (SEGMENT.fft1 -> Color change, SEGMENT.fft2 -> PWM cutoff)
//
-uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline
- //#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0
+uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline
+ //#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0
- uint16_t colorIndex = now /32;//(256 - SEGMENT.fft1); // Amount of colour change.
+ uint16_t colorIndex = now / 32; //(256 - SEGMENT.fft1); // Amount of colour change.
- SEGENV.step += SEGMENT.speed/16; // Speed of animation.
- uint16_t freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal.
+ SEGENV.step += SEGMENT.speed / 16; // Speed of animation.
+ uint16_t freq = SEGMENT.intensity / 4; //SEGMENT.fft2/8; // Frequency of the signal.
- for (int i=0; i> 2) +1);
- counter = counter >> 8;
- }
-
- uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs
- uint16_t zones = (SEGMENT.intensity * maxZones) >> 8;
- if (zones & 0x01) zones++; //zones must be even
- if (zones < 2) zones = 2;
- uint16_t zoneLen = SEGLEN / zones;
- uint16_t offset = (SEGLEN - zones * zoneLen) >> 1;
-
- fill(color_from_palette(-counter, false, true, 255));
-
- for (uint16_t z = 0; z < zones; z++)
- {
- uint16_t pos = offset + z * zoneLen;
- for (uint16_t i = 0; i < zoneLen; i++)
- {
- uint8_t colorIndex = (i * 255 / zoneLen) - counter;
- uint16_t led = (z & 0x01) ? i : (zoneLen -1) -i;
- if (IS_REVERSE) led = (zoneLen -1) -led;
- setPixelColor(pos + led, color_from_palette(colorIndex, false, true, 255));
+uint16_t WS2812FX::mode_flow(void) {
+ uint16_t counter = 0;
+ if (SEGMENT.speed != 0) {
+ counter = now * ((SEGMENT.speed >> 2) + 1);
+ counter = counter >> 8;
}
- }
- return FRAMETIME;
-}
+ uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs
+ uint16_t zones = (SEGMENT.intensity * maxZones) >> 8;
+ if (zones & 0x01) {
+ zones++; //zones must be even
+ }
+ if (zones < 2) {
+ zones = 2;
+ }
+ uint16_t zoneLen = SEGLEN / zones;
+ uint16_t offset = (SEGLEN - zones * zoneLen) >> 1;
+
+ fill(color_from_palette(-counter, false, true, 255));
+
+ for (uint16_t z = 0; z < zones; z++) {
+ uint16_t pos = offset + z * zoneLen;
+ for (uint16_t i = 0; i < zoneLen; i++) {
+ uint8_t colorIndex = (i * 255 / zoneLen) - counter;
+ uint16_t led = (z & 0x01) ? i : (zoneLen - 1) - i;
+ if (IS_REVERSE) {
+ led = (zoneLen - 1) - led;
+ }
+ setPixelColor(pos + led, color_from_palette(colorIndex, false, true, 255));
+ }
+ }
+ return FRAMETIME;
+}
/*
* Dots waving around in a sine/pendulum motion.
* Little pixel birds flying in a circle. By Aircoookie
*/
-uint16_t WS2812FX::mode_chunchun(void)
-{
- fill(SEGCOLOR(1));
- uint16_t counter = now*(6 + (SEGMENT.speed >> 4));
- uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
- uint16_t span = (SEGMENT.intensity << 8) / numBirds;
-
- for (uint16_t i = 0; i < numBirds; i++)
- {
- counter -= span;
- uint16_t megumin = sin16(counter) + 0x8000;
- uint32_t bird = (megumin * SEGLEN) >> 16;
- uint32_t c = color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping
- setPixelColor(bird, c);
- }
- return FRAMETIME;
+uint16_t WS2812FX::mode_chunchun(void) {
+ fill(SEGCOLOR(1));
+ uint16_t counter = now * (6 + (SEGMENT.speed >> 4));
+ uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
+ uint16_t span = (SEGMENT.intensity << 8) / numBirds;
+
+ for (uint16_t i = 0; i < numBirds; i++) {
+ counter -= span;
+ uint16_t megumin = sin16(counter) + 0x8000;
+ uint32_t bird = (megumin * SEGLEN) >> 16;
+ uint32_t c = color_from_palette((i * 255) / numBirds, false, false, 0); // no palette wrapping
+ setPixelColor(bird, c);
+ }
+ return FRAMETIME;
}
//13 bytes
typedef struct Spotlight {
- float speed;
- uint8_t colorIdx;
- int16_t position;
- unsigned long lastUpdateTime;
- uint8_t width;
- uint8_t type;
+ float speed;
+ uint8_t colorIdx;
+ int16_t position;
+ unsigned long lastUpdateTime;
+ uint8_t width;
+ uint8_t type;
} spotlight;
-#define SPOT_TYPE_SOLID 0
-#define SPOT_TYPE_GRADIENT 1
+#define SPOT_TYPE_SOLID 0
+#define SPOT_TYPE_GRADIENT 1
#define SPOT_TYPE_2X_GRADIENT 2
-#define SPOT_TYPE_2X_DOT 3
-#define SPOT_TYPE_3X_DOT 4
-#define SPOT_TYPE_4X_DOT 5
-#define SPOT_TYPES_COUNT 6
+#define SPOT_TYPE_2X_DOT 3
+#define SPOT_TYPE_3X_DOT 4
+#define SPOT_TYPE_4X_DOT 5
+#define SPOT_TYPES_COUNT 6
#ifdef ESP8266
- #define SPOT_MAX_COUNT 17 //Number of simultaneous waves
+#define SPOT_MAX_COUNT 17 //Number of simultaneous waves
#else
- #define SPOT_MAX_COUNT 49 //Number of simultaneous waves
+#define SPOT_MAX_COUNT 49 //Number of simultaneous waves
#endif
/*
@@ -3643,121 +3678,121 @@ typedef struct Spotlight {
*
* By Steve Pomeroy @xxv
*/
-uint16_t WS2812FX::mode_dancing_shadows(void)
-{
- uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 18 segment ESP8266
- bool initialize = SEGENV.aux0 != numSpotlights;
- SEGENV.aux0 = numSpotlights;
-
- uint16_t dataSize = sizeof(spotlight) * numSpotlights;
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
- Spotlight* spotlights = reinterpret_cast(SEGENV.data);
-
- fill(BLACK);
-
- unsigned long time = millis();
- bool respawn = false;
-
- for (uint8_t i = 0; i < numSpotlights; i++) {
- if (!initialize) {
- // advance the position of the spotlight
- int16_t delta = (float)(time - spotlights[i].lastUpdateTime) *
- (spotlights[i].speed * ((1.0 + SEGMENT.speed)/100.0));
-
- if (abs(delta) >= 1) {
- spotlights[i].position += delta;
- spotlights[i].lastUpdateTime = time;
- }
-
- respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (SEGLEN + 2))
- || (spotlights[i].speed < 0.0 && spotlights[i].position < -(spotlights[i].width + 2));
+uint16_t WS2812FX::mode_dancing_shadows(void) {
+ uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 18 segment ESP8266
+ bool initialize = SEGENV.aux0 != numSpotlights;
+ SEGENV.aux0 = numSpotlights;
+
+ uint16_t dataSize = sizeof(spotlight) * numSpotlights;
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
}
+ Spotlight *spotlights = reinterpret_cast(SEGENV.data);
- if (initialize || respawn) {
- spotlights[i].colorIdx = random8();
- spotlights[i].width = random8(1, 10);
+ fill(BLACK);
- spotlights[i].speed = 1.0/random8(4, 50);
+ unsigned long time = millis();
+ bool respawn = false;
- if (initialize) {
- spotlights[i].position = random16(SEGLEN);
- spotlights[i].speed *= random8(2) ? 1.0 : -1.0;
- } else {
- if (random8(2)) {
- spotlights[i].position = SEGLEN + spotlights[i].width;
- spotlights[i].speed *= -1.0;
- }else {
- spotlights[i].position = -spotlights[i].width;
- }
- }
+ for (uint8_t i = 0; i < numSpotlights; i++) {
+ if (!initialize) {
+ // advance the position of the spotlight
+ int16_t delta = (float)(time - spotlights[i].lastUpdateTime) *
+ (spotlights[i].speed * ((1.0 + SEGMENT.speed) / 100.0));
- spotlights[i].lastUpdateTime = time;
- spotlights[i].type = random8(SPOT_TYPES_COUNT);
- }
+ if (abs(delta) >= 1) {
+ spotlights[i].position += delta;
+ spotlights[i].lastUpdateTime = time;
+ }
- uint32_t color = color_from_palette(spotlights[i].colorIdx, false, false, 0);
- int start = spotlights[i].position;
+ respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (SEGLEN + 2)) || (spotlights[i].speed < 0.0 && spotlights[i].position < -(spotlights[i].width + 2));
+ }
- if (spotlights[i].width <= 1) {
- if (start >= 0 && start < SEGLEN) {
- blendPixelColor(start, color, 128);
- }
- } else {
- switch (spotlights[i].type) {
- case SPOT_TYPE_SOLID:
- for (uint8_t j = 0; j < spotlights[i].width; j++) {
- if ((start + j) >= 0 && (start + j) < SEGLEN) {
- blendPixelColor(start + j, color, 128);
- }
- }
- break;
-
- case SPOT_TYPE_GRADIENT:
- for (uint8_t j = 0; j < spotlights[i].width; j++) {
- if ((start + j) >= 0 && (start + j) < SEGLEN) {
- blendPixelColor(start + j, color,
- cubicwave8(map(j, 0, spotlights[i].width - 1, 0, 255)));
+ if (initialize || respawn) {
+ spotlights[i].colorIdx = random8();
+ spotlights[i].width = random8(1, 10);
+
+ spotlights[i].speed = 1.0 / random8(4, 50);
+
+ if (initialize) {
+ spotlights[i].position = random16(SEGLEN);
+ spotlights[i].speed *= random8(2) ? 1.0 : -1.0;
+ } else {
+ if (random8(2)) {
+ spotlights[i].position = SEGLEN + spotlights[i].width;
+ spotlights[i].speed *= -1.0;
+ } else {
+ spotlights[i].position = -spotlights[i].width;
+ }
}
- }
- break;
-
- case SPOT_TYPE_2X_GRADIENT:
- for (uint8_t j = 0; j < spotlights[i].width; j++) {
- if ((start + j) >= 0 && (start + j) < SEGLEN) {
- blendPixelColor(start + j, color,
- cubicwave8(2 * map(j, 0, spotlights[i].width - 1, 0, 255)));
- }
- }
- break;
- case SPOT_TYPE_2X_DOT:
- for (uint8_t j = 0; j < spotlights[i].width; j += 2) {
- if ((start + j) >= 0 && (start + j) < SEGLEN) {
- blendPixelColor(start + j, color, 128);
- }
- }
- break;
+ spotlights[i].lastUpdateTime = time;
+ spotlights[i].type = random8(SPOT_TYPES_COUNT);
+ }
- case SPOT_TYPE_3X_DOT:
- for (uint8_t j = 0; j < spotlights[i].width; j += 3) {
- if ((start + j) >= 0 && (start + j) < SEGLEN) {
- blendPixelColor(start + j, color, 128);
- }
- }
- break;
+ uint32_t color = color_from_palette(spotlights[i].colorIdx, false, false, 0);
+ int start = spotlights[i].position;
- case SPOT_TYPE_4X_DOT:
- for (uint8_t j = 0; j < spotlights[i].width; j += 4) {
- if ((start + j) >= 0 && (start + j) < SEGLEN) {
- blendPixelColor(start + j, color, 128);
+ if (spotlights[i].width <= 1) {
+ if (start >= 0 && start < SEGLEN) {
+ blendPixelColor(start, color, 128);
}
- }
- break;
- }
+ } else {
+ switch (spotlights[i].type) {
+ case SPOT_TYPE_SOLID:
+ for (uint8_t j = 0; j < spotlights[i].width; j++) {
+ if ((start + j) >= 0 && (start + j) < SEGLEN) {
+ blendPixelColor(start + j, color, 128);
+ }
+ }
+ break;
+
+ case SPOT_TYPE_GRADIENT:
+ for (uint8_t j = 0; j < spotlights[i].width; j++) {
+ if ((start + j) >= 0 && (start + j) < SEGLEN) {
+ blendPixelColor(start + j, color,
+ cubicwave8(map(j, 0, spotlights[i].width - 1, 0, 255)));
+ }
+ }
+ break;
+
+ case SPOT_TYPE_2X_GRADIENT:
+ for (uint8_t j = 0; j < spotlights[i].width; j++) {
+ if ((start + j) >= 0 && (start + j) < SEGLEN) {
+ blendPixelColor(start + j, color,
+ cubicwave8(2 * map(j, 0, spotlights[i].width - 1, 0, 255)));
+ }
+ }
+ break;
+
+ case SPOT_TYPE_2X_DOT:
+ for (uint8_t j = 0; j < spotlights[i].width; j += 2) {
+ if ((start + j) >= 0 && (start + j) < SEGLEN) {
+ blendPixelColor(start + j, color, 128);
+ }
+ }
+ break;
+
+ case SPOT_TYPE_3X_DOT:
+ for (uint8_t j = 0; j < spotlights[i].width; j += 3) {
+ if ((start + j) >= 0 && (start + j) < SEGLEN) {
+ blendPixelColor(start + j, color, 128);
+ }
+ }
+ break;
+
+ case SPOT_TYPE_4X_DOT:
+ for (uint8_t j = 0; j < spotlights[i].width; j += 4) {
+ if ((start + j) >= 0 && (start + j) < SEGLEN) {
+ blendPixelColor(start + j, color, 128);
+ }
+ }
+ break;
+ }
+ }
}
- }
- return FRAMETIME;
+ return FRAMETIME;
}
/*
@@ -3765,18 +3800,18 @@ uint16_t WS2812FX::mode_dancing_shadows(void)
By Stefan Seegel
*/
uint16_t WS2812FX::mode_washing_machine(void) {
- float speed = tristate_square8(now >> 7, 90, 15);
- float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
- speed /= quot;
+ float speed = tristate_square8(now >> 7, 90, 15);
+ float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
+ speed /= quot;
- SEGENV.step += (speed * 128.0f);
-
- for (int i=0; i> 7));
- setPixelColor(i, color_from_palette(col, false, PALETTE_SOLID_WRAP, 3));
- }
+ SEGENV.step += (speed * 128.0f);
- return FRAMETIME;
+ for (int i = 0; i < SEGLEN; i++) {
+ uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
+ setPixelColor(i, color_from_palette(col, false, PALETTE_SOLID_WRAP, 3));
+ }
+
+ return FRAMETIME;
}
/*
@@ -3784,19 +3819,21 @@ uint16_t WS2812FX::mode_washing_machine(void) {
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
*/
uint16_t WS2812FX::mode_blends(void) {
- uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 18 segment ESP8266
- if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
- uint32_t* pixels = reinterpret_cast(SEGENV.data);
- uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
- uint8_t shift = (now * ((SEGMENT.speed >> 3) +1)) >> 8;
-
- for (int i = 0; i < SEGLEN; i++) {
- pixels[i] = color_blend(pixels[i], color_from_palette(shift + quadwave8((i + 1) * 16), false, PALETTE_SOLID_WRAP, 255), blendSpeed);
- setPixelColor(i, pixels[i]);
- shift += 3;
- }
+ uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 18 segment ESP8266
+ if (!SEGENV.allocateData(dataSize)) {
+ return mode_static(); //allocation failed
+ }
+ uint32_t *pixels = reinterpret_cast(SEGENV.data);
+ uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
+ uint8_t shift = (now * ((SEGMENT.speed >> 3) + 1)) >> 8;
+
+ for (int i = 0; i < SEGLEN; i++) {
+ pixels[i] = color_blend(pixels[i], color_from_palette(shift + quadwave8((i + 1) * 16), false, PALETTE_SOLID_WRAP, 255), blendSpeed);
+ setPixelColor(i, pixels[i]);
+ shift += 3;
+ }
- return FRAMETIME;
+ return FRAMETIME;
}
/*
@@ -3805,125 +3842,129 @@ uint16_t WS2812FX::mode_blends(void) {
*/
//43 bytes
typedef struct TvSim {
- uint32_t totalTime = 0;
- uint32_t fadeTime = 0;
- uint32_t startTime = 0;
- uint32_t elapsed = 0;
- uint32_t pixelNum = 0;
- uint16_t sliderValues = 0;
- uint32_t sceeneStart = 0;
- uint32_t sceeneDuration = 0;
- uint16_t sceeneColorHue = 0;
- uint8_t sceeneColorSat = 0;
- uint8_t sceeneColorBri = 0;
- uint8_t actualColorR = 0;
- uint8_t actualColorG = 0;
- uint8_t actualColorB = 0;
- uint16_t pr = 0; // Prev R, G, B
- uint16_t pg = 0;
- uint16_t pb = 0;
+ uint32_t totalTime = 0;
+ uint32_t fadeTime = 0;
+ uint32_t startTime = 0;
+ uint32_t elapsed = 0;
+ uint32_t pixelNum = 0;
+ uint16_t sliderValues = 0;
+ uint32_t sceeneStart = 0;
+ uint32_t sceeneDuration = 0;
+ uint16_t sceeneColorHue = 0;
+ uint8_t sceeneColorSat = 0;
+ uint8_t sceeneColorBri = 0;
+ uint8_t actualColorR = 0;
+ uint8_t actualColorG = 0;
+ uint8_t actualColorB = 0;
+ uint16_t pr = 0; // Prev R, G, B
+ uint16_t pg = 0;
+ uint16_t pb = 0;
} tvSim;
uint16_t WS2812FX::mode_tv_simulator(void) {
- uint16_t nr, ng, nb, r, g, b, i, hue;
- uint8_t sat, bri, j;
+ uint16_t nr, ng, nb, r, g, b, i, hue;
+ uint8_t sat, bri, j;
- if (!SEGENV.allocateData(sizeof(tvSim))) return mode_static(); //allocation failed
- TvSim* tvSimulator = reinterpret_cast(SEGENV.data);
+ if (!SEGENV.allocateData(sizeof(tvSim))) {
+ return mode_static(); //allocation failed
+ }
+ TvSim *tvSimulator = reinterpret_cast(SEGENV.data);
- uint8_t colorSpeed = map(SEGMENT.speed, 0, UINT8_MAX, 1, 20);
- uint8_t colorIntensity = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 30);
+ uint8_t colorSpeed = map(SEGMENT.speed, 0, UINT8_MAX, 1, 20);
+ uint8_t colorIntensity = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 30);
- i = SEGMENT.speed << 8 | SEGMENT.intensity;
- if (i != tvSimulator->sliderValues) {
- tvSimulator->sliderValues = i;
- SEGENV.aux1 = 0;
- }
+ i = SEGMENT.speed << 8 | SEGMENT.intensity;
+ if (i != tvSimulator->sliderValues) {
+ tvSimulator->sliderValues = i;
+ SEGENV.aux1 = 0;
+ }
// create a new sceene
if (((millis() - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) {
- tvSimulator->sceeneStart = millis(); // remember the start of the new sceene
- tvSimulator->sceeneDuration = random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider)
- tvSimulator->sceeneColorHue = random16( 0, 768); // random start color-tone for the sceene
- tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene
- tvSimulator->sceeneColorBri = random8 ( 200, 240); // random start color-brightness for the sceene
- SEGENV.aux1 = 1;
- SEGENV.aux0 = 0;
- }
-
+ tvSimulator->sceeneStart = millis(); // remember the start of the new sceene
+ tvSimulator->sceeneDuration = random16(60 * 250 * colorSpeed, 60 * 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider)
+ tvSimulator->sceeneColorHue = random16(0, 768); // random start color-tone for the sceene
+ tvSimulator->sceeneColorSat = random8(100, 130 + colorIntensity); // random start color-saturation for the sceene
+ tvSimulator->sceeneColorBri = random8(200, 240); // random start color-brightness for the sceene
+ SEGENV.aux1 = 1;
+ SEGENV.aux0 = 0;
+ }
+
// slightly change the color-tone in this sceene
- if ( SEGENV.aux0 == 0) {
- // hue change in both directions
- j = random8(4 * colorIntensity);
- hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative
- ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767) ; // positive
-
- // saturation
- j = random8(2 * colorIntensity);
- sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j;
-
- // brightness
- j = random8(100);
- bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j;
-
- // calculate R,G,B from HSV
- // Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
- { // just to create a local scope for the variables
- uint8_t temp[5], n = (hue >> 8) % 3;
- uint8_t x = ((((hue & 255) * sat) >> 8) * bri) >> 8;
- uint8_t s = ( (256 - sat) * bri) >> 8;
- temp[0] = temp[3] = s;
- temp[1] = temp[4] = x + s;
- temp[2] = bri - x;
- tvSimulator->actualColorR = temp[n + 2];
- tvSimulator->actualColorG = temp[n + 1];
- tvSimulator->actualColorB = temp[n ];
- }
+ if (SEGENV.aux0 == 0) {
+ // hue change in both directions
+ j = random8(4 * colorIntensity);
+ hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative
+ ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767); // positive
+
+ // saturation
+ j = random8(2 * colorIntensity);
+ sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j;
+
+ // brightness
+ j = random8(100);
+ bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j;
+
+ // calculate R,G,B from HSV
+ // Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
+ { // just to create a local scope for the variables
+ uint8_t temp[5], n = (hue >> 8) % 3;
+ uint8_t x = ((((hue & 255) * sat) >> 8) * bri) >> 8;
+ uint8_t s = ((256 - sat) * bri) >> 8;
+ temp[0] = temp[3] = s;
+ temp[1] = temp[4] = x + s;
+ temp[2] = bri - x;
+ tvSimulator->actualColorR = temp[n + 2];
+ tvSimulator->actualColorG = temp[n + 1];
+ tvSimulator->actualColorB = temp[n];
+ }
}
// Apply gamma correction, further expand to 16/16/16
nr = (uint8_t)gamma8(tvSimulator->actualColorR) * 257; // New R/G/B
ng = (uint8_t)gamma8(tvSimulator->actualColorG) * 257;
nb = (uint8_t)gamma8(tvSimulator->actualColorB) * 257;
- if (SEGENV.aux0 == 0) { // initialize next iteration
- SEGENV.aux0 = 1;
-
- // randomize total duration and fade duration for the actual color
- tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time
- tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
- if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time
-
- tvSimulator->startTime = millis();
- } // end of initialization
-
- // how much time is elapsed ?
- tvSimulator->elapsed = millis() - tvSimulator->startTime;
-
- // fade from prev volor to next color
- if (tvSimulator->elapsed < tvSimulator->fadeTime) {
- r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr);
- g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng);
- b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb);
- } else { // Avoid divide-by-zero in map()
- r = nr;
- g = ng;
- b = nb;
- }
-
- // set strip color
- for (i = 0; i < SEGLEN; i++) {
- setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit
- }
-
- // if total duration has passed, remember last color and restart the loop
- if ( tvSimulator->elapsed >= tvSimulator->totalTime) {
- tvSimulator->pr = nr; // Prev RGB = new RGB
- tvSimulator->pg = ng;
- tvSimulator->pb = nb;
- SEGENV.aux0 = 0;
- }
-
- return FRAMETIME;
+ if (SEGENV.aux0 == 0) { // initialize next iteration
+ SEGENV.aux0 = 1;
+
+ // randomize total duration and fade duration for the actual color
+ tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time
+ tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
+ if (random8(10) < 3) {
+ tvSimulator->fadeTime = 0; // Force scene cut 30% of time
+ }
+
+ tvSimulator->startTime = millis();
+ } // end of initialization
+
+ // how much time is elapsed ?
+ tvSimulator->elapsed = millis() - tvSimulator->startTime;
+
+ // fade from prev volor to next color
+ if (tvSimulator->elapsed < tvSimulator->fadeTime) {
+ r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr);
+ g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng);
+ b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb);
+ } else { // Avoid divide-by-zero in map()
+ r = nr;
+ g = ng;
+ b = nb;
+ }
+
+ // set strip color
+ for (i = 0; i < SEGLEN; i++) {
+ setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit
+ }
+
+ // if total duration has passed, remember last color and restart the loop
+ if (tvSimulator->elapsed >= tvSimulator->totalTime) {
+ tvSimulator->pr = nr; // Prev RGB = new RGB
+ tvSimulator->pg = ng;
+ tvSimulator->pb = nb;
+ SEGENV.aux0 = 0;
+ }
+
+ return FRAMETIME;
}
/*
@@ -3932,16 +3973,16 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
//CONFIG
#ifdef ESP8266
- #define W_MAX_COUNT 9 //Number of simultaneous waves
+#define W_MAX_COUNT 9 //Number of simultaneous waves
#else
- #define W_MAX_COUNT 20 //Number of simultaneous waves
+#define W_MAX_COUNT 20 //Number of simultaneous waves
#endif
-#define W_MAX_SPEED 6 //Higher number, higher speed
-#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
+#define W_MAX_SPEED 6 //Higher number, higher speed
+#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
//24 bytes
class AuroraWave {
- private:
+ private:
uint16_t ttl;
CRGB basecolor;
float basealpha;
@@ -3952,136 +3993,148 @@ class AuroraWave {
float speed_factor;
bool alive = true;
- public:
+ public:
void init(uint32_t segment_length, CRGB color) {
- ttl = random(500, 1501);
- basecolor = color;
- basealpha = random(60, 101) / (float)100;
- age = 0;
- width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
- if (!width) width = 1;
- center = random(101) / (float)100 * segment_length;
- goingleft = random(0, 2) == 0;
- speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
- alive = true;
- }
-
- CRGB getColorForLED(int ledIndex) {
- if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave
-
- CRGB rgb;
-
- //Offset of this led from center of wave
- //The further away from the center, the dimmer the LED
- float offset = ledIndex - center;
- if (offset < 0) offset = -offset;
- float offsetFactor = offset / width;
-
- //The age of the wave determines it brightness.
- //At half its maximum age it will be the brightest.
- float ageFactor = 0.1;
- if((float)age / ttl < 0.5) {
- ageFactor = (float)age / (ttl / 2);
- } else {
- ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
- }
+ ttl = random(500, 1501);
+ basecolor = color;
+ basealpha = random(60, 101) / (float)100;
+ age = 0;
+ width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
+ if (!width) {
+ width = 1;
+ }
+ center = random(101) / (float)100 * segment_length;
+ goingleft = random(0, 2) == 0;
+ speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
+ alive = true;
+ }
+
+ CRGB getColorForLED(int ledIndex) {
+ if (ledIndex < center - width || ledIndex > center + width) {
+ return 0; //Position out of range of this wave
+ }
+
+ CRGB rgb;
+
+ //Offset of this led from center of wave
+ //The further away from the center, the dimmer the LED
+ float offset = ledIndex - center;
+ if (offset < 0) {
+ offset = -offset;
+ }
+ float offsetFactor = offset / width;
+
+ //The age of the wave determines it brightness.
+ //At half its maximum age it will be the brightest.
+ float ageFactor = 0.1;
+ if ((float)age / ttl < 0.5) {
+ ageFactor = (float)age / (ttl / 2);
+ } else {
+ ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
+ }
- //Calculate color based on above factors and basealpha value
- float factor = (1 - offsetFactor) * ageFactor * basealpha;
- rgb.r = basecolor.r * factor;
- rgb.g = basecolor.g * factor;
- rgb.b = basecolor.b * factor;
-
- return rgb;
+ //Calculate color based on above factors and basealpha value
+ float factor = (1 - offsetFactor) * ageFactor * basealpha;
+ rgb.r = basecolor.r * factor;
+ rgb.g = basecolor.g * factor;
+ rgb.b = basecolor.b * factor;
+
+ return rgb;
};
//Change position and age of wave
//Determine if its sill "alive"
void update(uint32_t segment_length, uint32_t speed) {
- if(goingleft) {
- center -= speed_factor * speed;
- } else {
- center += speed_factor * speed;
- }
+ if (goingleft) {
+ center -= speed_factor * speed;
+ } else {
+ center += speed_factor * speed;
+ }
- age++;
+ age++;
- if(age > ttl) {
- alive = false;
- } else {
- if(goingleft) {
- if(center + width < 0) {
+ if (age > ttl) {
alive = false;
- }
} else {
- if(center - width > segment_length) {
- alive = false;
- }
+ if (goingleft) {
+ if (center + width < 0) {
+ alive = false;
+ }
+ } else {
+ if (center - width > segment_length) {
+ alive = false;
+ }
+ }
}
- }
};
bool stillAlive() {
- return alive;
+ return alive;
};
};
uint16_t WS2812FX::mode_aurora(void) {
- //aux1 = Wavecount
- //aux2 = Intensity in last loop
+ //aux1 = Wavecount
+ //aux2 = Intensity in last loop
- AuroraWave* waves;
+ AuroraWave *waves;
- if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
- //Intensity slider changed or first call
- SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
- SEGENV.aux0 = SEGMENT.intensity;
+ if (SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
+ //Intensity slider changed or first call
+ SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
+ SEGENV.aux0 = SEGMENT.intensity;
- if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 18 segment ESP8266
- return mode_static(); //allocation failed
- }
+ if (!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 18 segment ESP8266
+ return mode_static(); //allocation failed
+ }
- waves = reinterpret_cast(SEGENV.data);
+ waves = reinterpret_cast(SEGENV.data);
- for(int i = 0; i < SEGENV.aux1; i++) {
- waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
+ for (int i = 0; i < SEGENV.aux1; i++) {
+ waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
+ }
+ } else {
+ waves = reinterpret_cast(SEGENV.data);
}
- } else {
- waves = reinterpret_cast(SEGENV.data);
- }
- for(int i = 0; i < SEGENV.aux1; i++) {
- //Update values of wave
- waves[i].update(SEGLEN, SEGMENT.speed);
+ for (int i = 0; i < SEGENV.aux1; i++) {
+ //Update values of wave
+ waves[i].update(SEGLEN, SEGMENT.speed);
- if(!(waves[i].stillAlive())) {
- //If a wave dies, reinitialize it starts over.
- waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
+ if (!(waves[i].stillAlive())) {
+ //If a wave dies, reinitialize it starts over.
+ waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
+ }
}
- }
- uint8_t backlight = 1; //dimmer backlight if less active colors
- if (SEGCOLOR(0)) backlight++;
- if (SEGCOLOR(1)) backlight++;
- if (SEGCOLOR(2)) backlight++;
- //Loop through LEDs to determine color
- for(int i = 0; i < SEGLEN; i++) {
- CRGB mixedRgb = CRGB(backlight, backlight, backlight);
+ uint8_t backlight = 1; //dimmer backlight if less active colors
+ if (SEGCOLOR(0)) {
+ backlight++;
+ }
+ if (SEGCOLOR(1)) {
+ backlight++;
+ }
+ if (SEGCOLOR(2)) {
+ backlight++;
+ }
+ //Loop through LEDs to determine color
+ for (int i = 0; i < SEGLEN; i++) {
+ CRGB mixedRgb = CRGB(backlight, backlight, backlight);
- //For each LED we must check each wave if it is "active" at this position.
- //If there are multiple waves active on a LED we multiply their values.
- for(int j = 0; j < SEGENV.aux1; j++) {
- CRGB rgb = waves[j].getColorForLED(i);
-
- if(rgb != CRGB(0)) {
- mixedRgb += rgb;
- }
+ //For each LED we must check each wave if it is "active" at this position.
+ //If there are multiple waves active on a LED we multiply their values.
+ for (int j = 0; j < SEGENV.aux1; j++) {
+ CRGB rgb = waves[j].getColorForLED(i);
+
+ if (rgb != CRGB(0)) {
+ mixedRgb += rgb;
+ }
+ }
+
+ setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2]);
}
- setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2]);
- }
-
- return FRAMETIME;
+ return FRAMETIME;
}
/*
@@ -4089,73 +4142,98 @@ uint16_t WS2812FX::mode_aurora(void) {
* Random Strobing Segments
*/
uint16_t WS2812FX::mode_hive_51(void) {
- const uint8_t N_LEDS_PER_EDGE = 10;
-
- uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; // total cycle time in ms
- uint32_t perc = now % cycleTime; // current time step in active cycle in ms
- uint16_t prog = (perc * 10) / cycleTime; // current progress in active cycle (0 = start, 65535 = end)
-
- uint8_t nActiveEdges = SEGLEN / N_LEDS_PER_EDGE / 3; // set 1/3 of the edges to active
- // check if active edges are set
- if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
- if(!SEGENV.allocateData(nActiveEdges)) {
- // return if memory cannot be allocated
- return 0;
- }
- }
-
- bool isValidData = true;
- if (SEGENV.step == prog) {
- // do not update LEDs
- for (uint8_t ii = 0; ii < nActiveEdges; ii ++) {
- if (SEGENV.data[ii] > SEGLEN / N_LEDS_PER_EDGE - 1) {
- isValidData = false;
- ii = nActiveEdges;
- break;
- }
- for (uint8_t jj = 0; jj < nActiveEdges; jj ++) {
- if (ii != jj) {
- if (SEGENV.data[ii] == SEGENV.data[jj]) {
- isValidData = false;
- ii = jj = nActiveEdges;
- break;
- }
+ const uint8_t N_LEDS_PER_EDGE = 10;
+
+ uint32_t cycleTime = 750 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint16_t prog = (perc * 10) / cycleTime; // current progress in active cycle (0 = start, 65535 = end)
+
+ uint8_t nActiveEdges = SEGLEN / N_LEDS_PER_EDGE / 3; // set 1/3 of the edges to active
+ // check if active edges are set
+ if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
+ if (!SEGENV.allocateData(nActiveEdges)) {
+ // return static effect if memory cannot be allocated
+ return mode_static();
+ }
+ }
+
+ bool isValidData = true;
+ if (SEGENV.step == prog) {
+ // do not update LEDs and use old states saved to SEGENV.data
+ for (uint8_t ii = 0; ii < nActiveEdges; ii++) {
+ if (SEGENV.data[ii] > SEGLEN / N_LEDS_PER_EDGE - 1) {
+ isValidData = false;
+ ii = nActiveEdges;
+ break;
+ }
+ for (uint8_t jj = 0; jj < nActiveEdges; jj++) {
+ if (ii != jj) {
+ if (SEGENV.data[ii] == SEGENV.data[jj]) {
+ isValidData = false;
+ ii = jj = nActiveEdges;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (SEGENV.step == (uint8_t)(prog - 1) || !isValidData) {
+ // update active segments to next random value
+ for (uint8_t ii = 0; ii < nActiveEdges; ii++) {
+ bool duplicates;
+ do {
+ duplicates = false;
+ SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE - 1);
+ for (uint8_t jj = 0; jj < ii; jj++) {
+ if (SEGENV.data[ii] == SEGENV.data[jj]) {
+ duplicates = true;
+ break;
+ }
+ }
+ } while (duplicates);
}
+ } else {
+ // this should not happen
+ return 0;
+ }
+
+ // set LED colors
+ for (uint16_t ii = 0; ii < SEGLEN; ii++) {
+ // set all LEDs to secondary color
+ if (ii % N_LEDS_PER_EDGE == 0) {
+ bool isActiveEdge = false;
+ for (uint8_t jj = 0; jj < sizeof(SEGENV.data); jj++) {
+ if (SEGENV.data[jj] == ii / N_LEDS_PER_EDGE) {
+ isActiveEdge = true;
+ break;
+ }
+ }
+ if (isActiveEdge) {
+ // set LED colors on active edge to white
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(jj, WHITE);
+ }
+ ii += N_LEDS_PER_EDGE - 1;
+ continue;
+ } else {
+ // set LED colors on inactive edge to black
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(jj, BLACK);
+ }
+ ii += N_LEDS_PER_EDGE - 1;
+ continue;
+ }
+ } else {
+ setPixelColor(ii, BLACK);
+ }
+ }
+ for (uint8_t ii = 0; ii < sizeof(SEGENV.data); ii++) {
+ // cycle through active edges
+ for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(SEGENV.data[ii] * N_LEDS_PER_EDGE + jj, WHITE);
}
}
- }
- if (SEGENV.step == (uint8_t) (prog - 1) || !isValidData) {
- // update active segments to next random value
- for (uint8_t ii = 0; ii < nActiveEdges ; ii++) {
- bool duplicates;
- do {
- duplicates = false;
- SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE - 1);
- for (uint8_t jj = 0; jj < ii; jj++) {
- if (SEGENV.data[ii] == SEGENV.data[jj]) {
- duplicates = true;
- break;
- }
- }
- } while (duplicates);
- }
- }
- else {
- // this should not happen
- return 0;
- }
-
- // set LED colors
- for (uint16_t ii = 0; ii < SEGLEN; ii++) {
- // set all LEDs to secondary color
- setPixelColor(ii, BLACK);
- }
- for (uint8_t ii = 0; ii < sizeof(SEGENV.data); ii++) { // cycle through active edges
- for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
- setPixelColor(SEGENV.data[ii] * N_LEDS_PER_EDGE + jj, WHITE);
- }
- }
-
- SEGENV.step = prog; // update step counter
- return FRAMETIME;
+
+ SEGENV.step = prog; // update step counter
+ return FRAMETIME;
}
\ No newline at end of file
From d5148ac70140cf7bca22897f42c3748d8edbe342 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 10 Oct 2021 21:24:09 +0200
Subject: [PATCH 04/31] add new hive rotation effect
---
wled00/FX.cpp | 756 +++++++++++++++++++++++++++-----------------------
wled00/FX.h | 13 +-
2 files changed, 421 insertions(+), 348 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index da9fcc8930..6a45dd2b02 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -26,6 +26,9 @@
#include "FX.h"
+#include
+#include
+
#define IBN 5100
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
@@ -34,7 +37,7 @@
*/
uint16_t WS2812FX::mode_static(void) {
fill(SEGCOLOR(0));
- return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
+ return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
}
/*
@@ -51,12 +54,12 @@ uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe, bool do_
uint32_t rem = now % cycleTime;
bool on = false;
- if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief
+ if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief
|| rem <= onTime) {
on = true;
}
- SEGENV.step = it; //save previous iteration
+ SEGENV.step = it; //save previous iteration
uint32_t color = on ? color1 : color2;
if (color == color1 && do_palette) {
@@ -111,11 +114,11 @@ uint16_t WS2812FX::color_wipe(bool rev, bool useRandomColors) {
if (back) {
prog -= 32767;
if (SEGENV.step == 0) {
- SEGENV.step = 1;
+ SEGENV.step = 1;
}
} else {
if (SEGENV.step == 2) {
- SEGENV.step = 3; //trigger color change
+ SEGENV.step = 3; //trigger color change
}
}
@@ -124,7 +127,7 @@ uint16_t WS2812FX::color_wipe(bool rev, bool useRandomColors) {
SEGENV.aux0 = random8();
SEGENV.step = 3;
}
- if (SEGENV.step == 1) { //if flag set, change to new random color
+ if (SEGENV.step == 1) { //if flag set, change to new random color
SEGENV.aux1 = get_random_wheel_index(SEGENV.aux0);
SEGENV.step = 2;
}
@@ -136,7 +139,7 @@ uint16_t WS2812FX::color_wipe(bool rev, bool useRandomColors) {
uint16_t ledIndex = (prog * SEGLEN) >> 15;
uint16_t rem = 0;
- rem = (prog * SEGLEN) * 2; //mod 0xFFFF
+ rem = (prog * SEGLEN) * 2; //mod 0xFFFF
rem /= (SEGMENT.intensity + 1);
if (rem > 255) {
rem = 255;
@@ -210,10 +213,10 @@ uint16_t WS2812FX::mode_random_color(void) {
SEGENV.aux0 = random8();
SEGENV.step = 2;
}
- if (it != SEGENV.step) //new color
+ if (it != SEGENV.step) //new color
{
SEGENV.aux1 = SEGENV.aux0;
- SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
+ SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
SEGENV.step = it;
}
@@ -227,7 +230,7 @@ uint16_t WS2812FX::mode_random_color(void) {
*/
uint16_t WS2812FX::dynamic(boolean smooth = false) {
if (!SEGENV.allocateData(SEGLEN)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
if (SEGENV.call == 0) {
@@ -238,7 +241,7 @@ uint16_t WS2812FX::dynamic(boolean smooth = false) {
uint32_t cycleTime = 50 + (255 - SEGMENT.speed) * 15;
uint32_t it = now / cycleTime;
- if (it != SEGENV.step && SEGMENT.speed != 0) //new color
+ if (it != SEGENV.step && SEGMENT.speed != 0) //new color
{
for (uint16_t i = 0; i < SEGLEN; i++) {
if (random8() <= SEGMENT.intensity) {
@@ -280,12 +283,12 @@ uint16_t WS2812FX::mode_dynamic_smooth(void) {
uint16_t WS2812FX::mode_breath(void) {
uint16_t var = 0;
uint16_t counter = (now * ((SEGMENT.speed >> 3) + 10));
- counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048
+ counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048
if (counter < 16384) {
if (counter > 8192) {
counter = 8192 - (counter - 8192);
}
- var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170
+ var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170
}
uint8_t lum = 30 + var;
@@ -464,10 +467,10 @@ uint16_t WS2812FX::mode_twinkle(void) {
uint32_t cycleTime = 20 + (255 - SEGMENT.speed) * 5;
uint32_t it = now / cycleTime;
if (it != SEGENV.step) {
- uint16_t maxOn = map(SEGMENT.intensity, 0, 255, 1, SEGLEN); // make sure at least one LED is on
+ uint16_t maxOn = map(SEGMENT.intensity, 0, 255, 1, SEGLEN); // make sure at least one LED is on
if (SEGENV.aux0 >= maxOn) {
SEGENV.aux0 = 0;
- SEGENV.aux1 = random16(); //new seed for our PRNG
+ SEGENV.aux1 = random16(); //new seed for our PRNG
}
SEGENV.aux0++;
SEGENV.step = it;
@@ -476,7 +479,7 @@ uint16_t WS2812FX::mode_twinkle(void) {
uint16_t PRNG16 = SEGENV.aux1;
for (uint16_t i = 0; i < SEGENV.aux0; i++) {
- PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next 'random' number
+ PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next 'random' number
uint32_t p = (uint32_t)SEGLEN * (uint32_t)PRNG16;
uint16_t j = p >> 16;
setPixelColor(j, color_from_palette(j, true, PALETTE_SOLID_WRAP, 0));
@@ -489,23 +492,23 @@ uint16_t WS2812FX::mode_twinkle(void) {
* Dissolve function
*/
uint16_t WS2812FX::dissolve(uint32_t color) {
- bool wa = (SEGCOLOR(1) != 0 && _brightness < 255); //workaround, can't compare getPixel to color if not full brightness
+ bool wa = (SEGCOLOR(1) != 0 && _brightness < 255); //workaround, can't compare getPixel to color if not full brightness
for (uint16_t j = 0; j <= SEGLEN / 15; j++) {
if (random8() <= SEGMENT.intensity) {
- for (uint8_t times = 0; times < 10; times++) //attempt to spawn a new pixel 5 times
+ for (uint8_t times = 0; times < 10; times++) //attempt to spawn a new pixel 5 times
{
uint16_t i = random16(SEGLEN);
- if (SEGENV.aux0) { //dissolve to primary/palette
+ if (SEGENV.aux0) { //dissolve to primary/palette
if (getPixelColor(i) == SEGCOLOR(1) || wa) {
if (color == SEGCOLOR(0)) {
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
} else {
setPixelColor(i, color);
}
- break; //only spawn 1 new pixel per frame per 50 LEDs
+ break; //only spawn 1 new pixel per frame per 50 LEDs
}
- } else { //dissolve to secondary
+ } else { //dissolve to secondary
if (getPixelColor(i) != SEGCOLOR(1)) {
setPixelColor(i, SEGCOLOR(1));
break;
@@ -548,7 +551,7 @@ uint16_t WS2812FX::mode_sparkle(void) {
uint32_t cycleTime = 10 + (255 - SEGMENT.speed) * 2;
uint32_t it = now / cycleTime;
if (it != SEGENV.step) {
- SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index
+ SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index
SEGENV.step = it;
}
@@ -567,7 +570,7 @@ uint16_t WS2812FX::mode_flash_sparkle(void) {
if (now - SEGENV.aux0 > SEGENV.step) {
if (random8((255 - SEGMENT.intensity) >> 4) == 0) {
- setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
+ setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
}
SEGENV.step = now;
SEGENV.aux0 = 255 - SEGMENT.speed;
@@ -689,9 +692,9 @@ uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3, bool
bool chase_random = (SEGMENT.mode == FX_MODE_CHASE_RANDOM);
if (chase_random) {
- if (a < SEGENV.step) //we hit the start again, choose new color for Chase random
+ if (a < SEGENV.step) //we hit the start again, choose new color for Chase random
{
- SEGENV.aux1 = SEGENV.aux0; //store previous random color
+ SEGENV.aux1 = SEGENV.aux0; //store previous random color
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
}
color1 = color_wheel(SEGENV.aux0);
@@ -701,7 +704,7 @@ uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3, bool
// Use intensity setting to vary chase up to 1/2 string length
uint8_t size = 1 + (SEGMENT.intensity * SEGLEN >> 10);
- uint16_t b = a + size; //"trail" of chase, filled with color1
+ uint16_t b = a + size; //"trail" of chase, filled with color1
if (b > SEGLEN) {
b -= SEGLEN;
}
@@ -733,9 +736,9 @@ uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3, bool
setPixelColor(i, color2);
}
} else {
- for (uint16_t i = a; i < SEGLEN; i++) //fill until end
+ for (uint16_t i = a; i < SEGLEN; i++) //fill until end
setPixelColor(i, color2);
- for (uint16_t i = 0; i < b; i++) //fill from start until b
+ for (uint16_t i = 0; i < b; i++) //fill from start until b
setPixelColor(i, color2);
}
@@ -745,9 +748,9 @@ uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3, bool
setPixelColor(i, color3);
}
} else {
- for (uint16_t i = b; i < SEGLEN; i++) //fill until end
+ for (uint16_t i = b; i < SEGLEN; i++) //fill until end
setPixelColor(i, color3);
- for (uint16_t i = 0; i < c; i++) //fill from start until c
+ for (uint16_t i = 0; i < c; i++) //fill from start until c
setPixelColor(i, color3);
}
@@ -774,7 +777,7 @@ uint16_t WS2812FX::mode_chase_random(void) {
uint16_t WS2812FX::mode_chase_rainbow(void) {
uint8_t color_sep = 256 / SEGLEN;
if (color_sep == 0) {
- color_sep = 1; // correction for segments longer than 256 LEDs
+ color_sep = 1; // correction for segments longer than 256 LEDs
}
uint8_t color_index = SEGENV.call & 0xFF;
uint32_t color = color_wheel(((SEGENV.step * color_sep) + color_index) & 0xFF);
@@ -798,9 +801,9 @@ uint16_t WS2812FX::mode_chase_rainbow_white(void) {
* Red - Amber - Green - Blue lights running
*/
uint16_t WS2812FX::mode_colorful(void) {
- uint8_t numColors = 4; //3, 4, or 5
+ uint8_t numColors = 4; //3, 4, or 5
uint32_t cols[9]{0x00FF0000, 0x00EEBB00, 0x0000EE00, 0x000077CC};
- if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color
+ if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color
if (!SEGMENT.palette) {
numColors = 3;
for (uint8_t i = 0; i < 3; i++) {
@@ -811,12 +814,12 @@ uint16_t WS2812FX::mode_colorful(void) {
if (SEGMENT.palette == 52) {
numColors = 5;
fac = 61;
- } //C9 2 has 5 colors
+ } //C9 2 has 5 colors
for (uint8_t i = 0; i < numColors; i++) {
cols[i] = color_from_palette(i * fac, false, true, 255);
}
}
- } else if (SEGMENT.intensity < 80) //pastel (easter) colors
+ } else if (SEGMENT.intensity < 80) //pastel (easter) colors
{
cols[0] = 0x00FF8040;
cols[1] = 0x00E5D241;
@@ -881,7 +884,7 @@ uint16_t WS2812FX::mode_traffic_light(void) {
if (now - SEGENV.step > mdelay) {
SEGENV.aux0++;
if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) {
- SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence
+ SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence
}
if (SEGENV.aux0 > 3) {
SEGENV.aux0 = 0;
@@ -957,7 +960,7 @@ uint16_t WS2812FX::mode_chase_flash_random(void) {
* Alternating pixels running function.
*/
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) {
- uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
+ uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
uint32_t it = now / cycleTime;
bool usePalette = color1 == SEGCOLOR(0);
@@ -1179,8 +1182,8 @@ uint16_t WS2812FX::mode_fire_flicker(void) {
byte w = (SEGCOLOR(0) >> 24) & 0xFF;
byte r = (SEGCOLOR(0) >> 16) & 0xFF;
- byte g = (SEGCOLOR(0) >> 8) & 0xFF;
- byte b = (SEGCOLOR(0) & 0xFF);
+ byte g = (SEGCOLOR(0) >> 8) & 0xFF;
+ byte b = (SEGCOLOR(0) & 0xFF);
byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255;
lum /= (((256 - SEGMENT.intensity) / 16) + 1);
for (uint16_t i = 0; i < SEGLEN; i++) {
@@ -1205,7 +1208,7 @@ uint16_t WS2812FX::gradient_base(bool loading) {
if (SEGENV.call == 0) {
pp = 0;
}
- float val; //0.0 = sec 1.0 = pri
+ float val; //0.0 = sec 1.0 = pri
float brd = loading ? SEGMENT.intensity : SEGMENT.intensity / 2;
if (brd < 1.0) {
brd = 1.0;
@@ -1242,7 +1245,7 @@ uint16_t WS2812FX::mode_loading(void) {
//American Police Light with all LEDs Red and Blue
uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, uint16_t width) {
- uint16_t delay = 1 + (FRAMETIME << 3) / SEGLEN; // longer segments should change faster
+ uint16_t delay = 1 + (FRAMETIME << 3) / SEGLEN; // longer segments should change faster
uint32_t it = now / map(SEGMENT.speed, 0, 255, delay << 4, delay);
uint16_t offset = it % SEGLEN;
@@ -1266,13 +1269,13 @@ uint16_t WS2812FX::mode_police_all() {
//Police Lights Red and Blue
uint16_t WS2812FX::mode_police() {
fill(SEGCOLOR(1));
- return police_base(RED, BLUE, ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
+ return police_base(RED, BLUE, ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
}
//Police All with custom colors
uint16_t WS2812FX::mode_two_areas() {
fill(SEGCOLOR(2));
- return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
+ return police_base(SEGCOLOR(0), SEGCOLOR(1), ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
}
//Police Lights with custom colors
@@ -1280,7 +1283,7 @@ uint16_t WS2812FX::mode_two_dots() {
fill(SEGCOLOR(2));
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
- return police_base(SEGCOLOR(0), color2, ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
+ return police_base(SEGCOLOR(0), color2, ((SEGLEN * (SEGMENT.intensity + 1)) >> 9)); // max width is half the strip
}
/*
@@ -1288,8 +1291,8 @@ uint16_t WS2812FX::mode_two_dots() {
*/
uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
uint32_t cycleTime = 50 + ((255 - SEGMENT.speed) << 1);
- uint32_t it = now / cycleTime; // iterator
- uint8_t width = (1 + (SEGMENT.intensity >> 4)); // value of 1-16 for each colour
+ uint32_t it = now / cycleTime; // iterator
+ uint8_t width = (1 + (SEGMENT.intensity >> 4)); // value of 1-16 for each colour
uint8_t index = it % (width * 3);
for (uint16_t i = 0; i < SEGLEN; i++, index++) {
@@ -1299,8 +1302,7 @@ uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2) {
uint32_t color = color1;
if (index > (width << 1) - 1) {
color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 1);
- }
- else if (index > width - 1) {
+ } else if (index > width - 1) {
color = color2;
}
setPixelColor(SEGLEN - i - 1, color);
@@ -1330,8 +1332,8 @@ uint16_t WS2812FX::mode_icu(void) {
setPixelColor(dest, col);
setPixelColor(dest + SEGLEN / space, col);
- if (SEGENV.aux0 == dest) { // pause between eye movements
- if (random8(6) == 0) { // blink once in a while
+ if (SEGENV.aux0 == dest) { // pause between eye movements
+ if (random8(6) == 0) { // blink once in a while
setPixelColor(dest, SEGCOLOR(1));
setPixelColor(dest + SEGLEN / space, SEGCOLOR(1));
return 200;
@@ -1368,16 +1370,16 @@ uint16_t WS2812FX::mode_tricolor_wipe(void) {
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2));
}
- if (ledIndex < SEGLEN) { //wipe from 0 to 1
+ if (ledIndex < SEGLEN) { //wipe from 0 to 1
for (uint16_t i = 0; i < SEGLEN; i++) {
setPixelColor(i, (i > ledOffset) ? SEGCOLOR(0) : SEGCOLOR(1));
}
- } else if (ledIndex < SEGLEN * 2) { //wipe from 1 to 2
+ } else if (ledIndex < SEGLEN * 2) { //wipe from 1 to 2
ledOffset = ledIndex - SEGLEN;
for (uint16_t i = ledOffset + 1; i < SEGLEN; i++) {
setPixelColor(i, SEGCOLOR(1));
}
- } else //wipe from 2 to 0
+ } else //wipe from 2 to 0
{
ledOffset = ledIndex - SEGLEN * 2;
for (uint16_t i = 0; i <= ledOffset; i++) {
@@ -1414,7 +1416,7 @@ uint16_t WS2812FX::mode_tricolor_fade(void) {
stage = 2;
}
- byte stp = prog; // % 256
+ byte stp = prog; // % 256
for (uint16_t i = 0; i < SEGLEN; i++) {
uint32_t color;
if (stage == 2) {
@@ -1441,7 +1443,7 @@ uint16_t WS2812FX::mode_multi_comet(void) {
return FRAMETIME;
}
if (!SEGENV.allocateData(sizeof(uint16_t) * 8)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
fade_out(SEGMENT.intensity);
@@ -1519,7 +1521,7 @@ uint16_t WS2812FX::mode_oscillate(void) {
uint16_t dataSize = sizeof(oscillator) * numOscillators;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
Oscillator *oscillators = reinterpret_cast(SEGENV.data);
@@ -1567,22 +1569,22 @@ uint16_t WS2812FX::mode_oscillate(void) {
}
uint16_t WS2812FX::mode_lightning(void) {
- uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
- uint16_t ledlen = 1 + random16(SEGLEN - ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) {
+ uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
+ uint16_t ledlen = 1 + random16(SEGLEN - ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) {
uint8_t bri = 255 / random8(1, 3);
- if (SEGENV.aux1 == 0) //init, leader flash
+ if (SEGENV.aux1 == 0) //init, leader flash
{
- SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity / 20); //number of flashes
+ SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity / 20); //number of flashes
SEGENV.aux1 *= 2;
- bri = 52; //leader has lower brightness
- SEGENV.aux0 = 200; //200ms delay after leader
+ bri = 52; //leader has lower brightness
+ SEGENV.aux0 = 200; //200ms delay after leader
}
fill(SEGCOLOR(1));
- if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
+ if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
for (int i = ledstart; i < ledstart + ledlen; i++) {
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri));
}
@@ -1597,9 +1599,9 @@ uint16_t WS2812FX::mode_lightning(void) {
SEGENV.aux1 = 0;
}
- SEGENV.aux0 = (50 + random8(100)); //delay between flashes
+ SEGENV.aux0 = (50 + random8(100)); //delay between flashes
if (SEGENV.aux1 == 2) {
- SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
+ SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
}
SEGENV.step = millis();
}
@@ -1620,7 +1622,7 @@ uint16_t WS2812FX::mode_pride_2015(void) {
uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
- uint16_t hue16 = sHue16; //gHue * 256;
+ uint16_t hue16 = sHue16; //gHue * 256;
uint16_t hueinc16 = beatsin88(113, 1, 3000);
sPseudotime += duration * msmultiplier;
@@ -1677,7 +1679,7 @@ uint16_t WS2812FX::mode_palette() {
uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
if (noWrap) {
- colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end"
+ colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end"
}
setPixelColor(i, color_from_palette(colorIndex, false, true, 255));
@@ -1715,26 +1717,26 @@ uint16_t WS2812FX::mode_palette() {
// in step 3 above) (Effect Intensity = Sparking).
uint16_t WS2812FX::mode_fire_2012() {
- uint32_t it = now >> 5; //div 32
+ uint32_t it = now >> 5; //div 32
if (!SEGENV.allocateData(SEGLEN)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
byte *heat = SEGENV.data;
if (it != SEGENV.step) {
- uint8_t ignition = max(7, SEGLEN / 10); // ignition area: 10% of segment length or minimum 7 pixels
+ uint8_t ignition = max(7, SEGLEN / 10); // ignition area: 10% of segment length or minimum 7 pixels
// Step 1. Cool down every cell a little
for (uint16_t i = 0; i < SEGLEN; i++) {
uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed / 3) * 10) / SEGLEN) + 2));
- heat[i] = (temp == 0 && i < ignition) ? 16 : temp; // prevent ignition area from becoming black
+ heat[i] = (temp == 0 && i < ignition) ? 16 : temp; // prevent ignition area from becoming black
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for (uint16_t k = SEGLEN - 1; k > 1; k--) {
- heat[k] = (heat[k - 1] + (heat[k - 2] << 1)) / 3; // heat[k-2] multiplied by 2
+ heat[k] = (heat[k - 1] + (heat[k - 2] << 1)) / 3; // heat[k-2] multiplied by 2
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
@@ -1767,9 +1769,9 @@ uint16_t WS2812FX::mode_colorwaves() {
uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
- uint16_t hue16 = sHue16; //gHue * 256;
+ uint16_t hue16 = sHue16; //gHue * 256;
// uint16_t hueinc16 = beatsin88(113, 300, 1500);
- uint16_t hueinc16 = beatsin88(113, 60, 300) * SEGMENT.intensity * 10 / 255; // Use the Intensity Slider for the hues
+ uint16_t hueinc16 = beatsin88(113, 60, 300) * SEGMENT.intensity * 10 / 255; // Use the Intensity Slider for the hues
sPseudotime += duration * msmultiplier;
sHue16 += duration * beatsin88(400, 5, 9);
@@ -1826,29 +1828,29 @@ uint16_t WS2812FX::mode_fillnoise8() {
fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND);
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
}
- SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4
+ SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4
return FRAMETIME;
}
uint16_t WS2812FX::mode_noise16_1() {
- uint16_t scale = 320; // the "zoom factor" for the noise
+ uint16_t scale = 320; // the "zoom factor" for the noise
CRGB fastled_col;
SEGENV.step += (1 + SEGMENT.speed / 16);
for (uint16_t i = 0; i < SEGLEN; i++) {
- uint16_t shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm
- uint16_t shift_y = SEGENV.step / 42; // the y position becomes slowly incremented
+ uint16_t shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm
+ uint16_t shift_y = SEGENV.step / 42; // the y position becomes slowly incremented
- uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm
- uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented
- uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented
+ uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm
+ uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented
+ uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented
- uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
+ uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
- uint8_t index = sin8(noise * 3); // map LED color based on noise data
+ uint8_t index = sin8(noise * 3); // map LED color based on noise data
- fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
+ fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
}
@@ -1856,20 +1858,20 @@ uint16_t WS2812FX::mode_noise16_1() {
}
uint16_t WS2812FX::mode_noise16_2() {
- uint16_t scale = 1000; // the "zoom factor" for the noise
+ uint16_t scale = 1000; // the "zoom factor" for the noise
CRGB fastled_col;
SEGENV.step += (1 + (SEGMENT.speed >> 1));
for (uint16_t i = 0; i < SEGLEN; i++) {
- uint16_t shift_x = SEGENV.step >> 6; // x as a function of time
+ uint16_t shift_x = SEGENV.step >> 6; // x as a function of time
- uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
+ uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
- uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down
+ uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down
- uint8_t index = sin8(noise * 3); // map led color based on noise data
+ uint8_t index = sin8(noise * 3); // map led color based on noise data
- fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
+ fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
}
@@ -1877,23 +1879,23 @@ uint16_t WS2812FX::mode_noise16_2() {
}
uint16_t WS2812FX::mode_noise16_3() {
- uint16_t scale = 800; // the "zoom factor" for the noise
+ uint16_t scale = 800; // the "zoom factor" for the noise
CRGB fastled_col;
SEGENV.step += (1 + SEGMENT.speed);
for (uint16_t i = 0; i < SEGLEN; i++) {
- uint16_t shift_x = 4223; // no movement along x and y
+ uint16_t shift_x = 4223; // no movement along x and y
uint16_t shift_y = 1234;
- uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
- uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions
+ uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
+ uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions
uint32_t real_z = SEGENV.step * 8;
- uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
+ uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
- uint8_t index = sin8(noise * 3); // map led color based on noise data
+ uint8_t index = sin8(noise * 3); // map led color based on noise data
- fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
+ fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
}
@@ -1914,9 +1916,9 @@ uint16_t WS2812FX::mode_noise16_4() {
//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e
uint16_t WS2812FX::mode_colortwinkle() {
- uint16_t dataSize = (SEGLEN + 7) >> 3; //1 bit per LED
+ uint16_t dataSize = (SEGLEN + 7) >> 3; //1 bit per LED
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
CRGB fastled_col, prev;
@@ -1938,7 +1940,7 @@ uint16_t WS2812FX::mode_colortwinkle() {
}
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
+ if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
fastled_col += fastled_col;
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
}
@@ -1950,7 +1952,7 @@ uint16_t WS2812FX::mode_colortwinkle() {
for (uint16_t j = 0; j <= SEGLEN / 50; j++) {
if (random8() <= SEGMENT.intensity) {
- for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
+ for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
int i = random16(SEGLEN);
if (getPixelColor(i) == 0) {
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
@@ -1958,7 +1960,7 @@ uint16_t WS2812FX::mode_colortwinkle() {
uint8_t bitNum = i & 0x07;
bitWrite(SEGENV.data[index], bitNum, true);
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
- break; //only spawn 1 new pixel per frame per 50 LEDs
+ break; //only spawn 1 new pixel per frame per 50 LEDs
}
}
}
@@ -1988,7 +1990,7 @@ uint16_t WS2812FX::mode_lake() {
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX::mode_meteor() {
if (!SEGENV.allocateData(SEGLEN)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
byte *trail = SEGENV.data;
@@ -2025,7 +2027,7 @@ uint16_t WS2812FX::mode_meteor() {
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
uint16_t WS2812FX::mode_meteor_smooth() {
if (!SEGENV.allocateData(SEGLEN)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
byte *trail = SEGENV.data;
@@ -2035,7 +2037,7 @@ uint16_t WS2812FX::mode_meteor_smooth() {
// fade all leds to colors[1] in LEDs one step
for (uint16_t i = 0; i < SEGLEN; i++) {
if (trail[i] != 0 && random8() <= 255 - SEGMENT.intensity) {
- int change = 3 - random8(12); //change each time between -8 and +3
+ int change = 3 - random8(12); //change each time between -8 and +3
trail[i] += change;
if (trail[i] > 245) {
trail[i] = 0;
@@ -2107,11 +2109,11 @@ typedef struct Ripple {
#define MAX_RIPPLES 100
#endif
uint16_t WS2812FX::ripple_base(bool rainbow) {
- uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 18 segment ESP8266
+ uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 18 segment ESP8266
uint16_t dataSize = sizeof(ripple) * maxRipples;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
Ripple *ripples = reinterpret_cast(SEGENV.data);
@@ -2138,7 +2140,7 @@ uint16_t WS2812FX::ripple_base(bool rainbow) {
for (uint16_t i = 0; i < maxRipples; i++) {
uint16_t ripplestate = ripples[i].state;
if (ripplestate) {
- uint8_t rippledecay = (SEGMENT.speed >> 4) + 1; //faster decay if faster propagation
+ uint8_t rippledecay = (SEGMENT.speed >> 4) + 1; //faster decay if faster propagation
uint16_t rippleorigin = ripples[i].pos;
uint32_t col = color_from_palette(ripples[i].color, false, false, 255);
uint16_t propagation = ((ripplestate / rippledecay - 1) * SEGMENT.speed);
@@ -2159,12 +2161,12 @@ uint16_t WS2812FX::ripple_base(bool rainbow) {
}
ripplestate += rippledecay;
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
- } else //randomly create new wave
+ } else //randomly create new wave
{
if (random16(IBN + 10000) <= SEGMENT.intensity) {
ripples[i].state = 1;
ripples[i].pos = random16(SEGLEN);
- ripples[i].color = random8(); //color
+ ripples[i].color = random8(); //color
}
}
}
@@ -2210,10 +2212,10 @@ CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) {
// This is like 'triwave8', which produces a
// symmetrical up-and-down triangle sawtooth waveform, except that this
// function produces a triangle wave with a faster attack and a slower decay
- if (cat) //twinklecat, variant where the leds instantly turn on
+ if (cat) //twinklecat, variant where the leds instantly turn on
{
bright = 255 - ph;
- } else { //vanilla twinklefox
+ } else { //vanilla twinklefox
if (ph < 86) {
bright = ph * 3;
} else {
@@ -2267,23 +2269,23 @@ uint16_t WS2812FX::twinklefox_base(bool cat) {
bg = col_to_crgb(SEGCOLOR(1));
uint8_t bglight = bg.getAverageLight();
if (bglight > 64) {
- bg.nscale8_video(16); // very bright, so scale to 1/16th
+ bg.nscale8_video(16); // very bright, so scale to 1/16th
} else if (bglight > 16) {
- bg.nscale8_video(64); // not that bright, so scale to 1/4th
+ bg.nscale8_video(64); // not that bright, so scale to 1/4th
} else {
- bg.nscale8_video(86); // dim, scale to 1/3rd.
+ bg.nscale8_video(86); // dim, scale to 1/3rd.
}
uint8_t backgroundBrightness = bg.getAverageLight();
for (uint16_t i = 0; i < SEGLEN; i++) {
- PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
- uint16_t myclockoffset16 = PRNG16; // use that number as clock offset
- PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
+ PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
+ uint16_t myclockoffset16 = PRNG16; // use that number as clock offset
+ PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
// use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF) >> 4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
uint32_t myclock30 = (uint32_t)((now * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
- uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
+ uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
// We now have the adjusted 'clock' for this pixel, now we call
// the function that computes what color the pixel should be based
@@ -2324,10 +2326,10 @@ uint16_t WS2812FX::mode_twinklecat() {
uint16_t WS2812FX::mode_halloween_eyes() {
uint16_t eyeLength = (2 * HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE;
if (eyeLength > SEGLEN) {
- return mode_static(); //bail if segment too short
+ return mode_static(); //bail if segment too short
}
- fill(SEGCOLOR(1)); //fill background
+ fill(SEGCOLOR(1)); //fill background
uint8_t state = SEGENV.aux1 >> 8;
uint16_t stateTime = SEGENV.call;
@@ -2335,13 +2337,13 @@ uint16_t WS2812FX::mode_halloween_eyes() {
stateTime = 2000;
}
- if (state == 0) { //spawn eyes
- SEGENV.aux0 = random16(0, SEGLEN - eyeLength); //start pos
- SEGENV.aux1 = random8(); //color
+ if (state == 0) { //spawn eyes
+ SEGENV.aux0 = random16(0, SEGLEN - eyeLength); //start pos
+ SEGENV.aux1 = random8(); //color
state = 1;
}
- if (state < 2) { //fade eyes
+ if (state < 2) { //fade eyes
uint16_t startPos = SEGENV.aux0;
uint16_t start2ndEye = startPos + HALLOWEEN_EYE_WIDTH + HALLOWEEN_EYE_SPACE;
@@ -2364,7 +2366,7 @@ uint16_t WS2812FX::mode_halloween_eyes() {
}
if (state < 2) {
- stateTime = 100 + (255 - SEGMENT.intensity) * 10; //eye fade time
+ stateTime = 100 + (255 - SEGMENT.intensity) * 10; //eye fade time
} else {
uint16_t eyeOffTimeBase = (255 - SEGMENT.speed) * 10;
stateTime = eyeOffTimeBase + random16(eyeOffTimeBase);
@@ -2373,7 +2375,7 @@ uint16_t WS2812FX::mode_halloween_eyes() {
SEGENV.call = stateTime;
}
- SEGENV.aux1 = (SEGENV.aux1 & 0xFF) + (state << 8); //save state
+ SEGENV.aux1 = (SEGENV.aux1 & 0xFF) + (state << 8); //save state
return FRAMETIME;
}
@@ -2471,7 +2473,7 @@ uint16_t WS2812FX::mode_bouncing_balls(void) {
uint16_t maxNumBalls = 16;
uint16_t dataSize = sizeof(ball) * maxNumBalls;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
Ball *balls = reinterpret_cast(SEGENV.data);
@@ -2480,7 +2482,7 @@ uint16_t WS2812FX::mode_bouncing_balls(void) {
// non-chosen color is a random color
uint8_t numBalls = int(((SEGMENT.intensity * (maxNumBalls - 0.8f)) / 255) + 1);
- float gravity = -9.81; // standard value of gravity
+ float gravity = -9.81; // standard value of gravity
float impactVelocityStart = sqrt(-2 * gravity);
unsigned long time = millis();
@@ -2498,7 +2500,7 @@ uint16_t WS2812FX::mode_bouncing_balls(void) {
float timeSinceLastBounce = (time - balls[i].lastBounceTime) / ((255 - SEGMENT.speed) * 8 / 256 + 1);
balls[i].height = 0.5 * gravity * pow(timeSinceLastBounce / 1000, 2.0) + balls[i].impactVelocity * timeSinceLastBounce / 1000;
- if (balls[i].height < 0) { //start bounce
+ if (balls[i].height < 0) { //start bounce
balls[i].height = 0;
//damping for better effect using multiple balls
float dampening = 0.90 - float(i) / pow(numBalls, 2);
@@ -2544,7 +2546,7 @@ uint16_t WS2812FX::sinelon_base(bool dual, bool rainbow = false) {
color2 = color_from_palette(pos, true, false, 0);
}
if (rainbow) {
- color2 = color1; //rainbow
+ color2 = color1; //rainbow
}
setPixelColor(SEGLEN - 1 - pos, color2);
}
@@ -2608,15 +2610,15 @@ typedef struct Spark {
*/
uint16_t WS2812FX::mode_popcorn(void) {
//allocate segment data
- uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266
+ uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266
uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
Spark *popcorn = reinterpret_cast(SEGENV.data);
- float gravity = -0.0001 - (SEGMENT.speed / 200000.0); // m/s/s
+ float gravity = -0.0001 - (SEGMENT.speed / 200000.0); // m/s/s
gravity *= SEGLEN;
bool hasCol2 = SEGCOLOR(2);
@@ -2630,7 +2632,7 @@ uint16_t WS2812FX::mode_popcorn(void) {
for (uint8_t i = 0; i < numPopcorn; i++) {
bool isActive = popcorn[i].pos >= 0.0f;
- if (isActive) { // if kernel is active, update its position
+ if (isActive) { // if kernel is active, update its position
popcorn[i].pos += popcorn[i].vel;
popcorn[i].vel += gravity;
uint32_t col = color_wheel(popcorn[i].colIndex);
@@ -2642,11 +2644,11 @@ uint16_t WS2812FX::mode_popcorn(void) {
if (ledIndex < SEGLEN) {
setPixelColor(ledIndex, col);
}
- } else { // if kernel is inactive, randomly pop it
- if (random8() < 2) { // POP!!!
+ } else { // if kernel is inactive, randomly pop it
+ if (random8() < 2) { // POP!!!
popcorn[i].pos = 0.01f;
- uint16_t peakHeight = 128 + random8(128); //0-255
+ uint16_t peakHeight = 128 + random8(128); //0-255
peakHeight = (peakHeight * (SEGLEN - 1)) >> 8;
popcorn[i].vel = sqrt(-2.0 * gravity * peakHeight);
@@ -2673,30 +2675,30 @@ uint16_t WS2812FX::mode_popcorn(void) {
uint16_t WS2812FX::candle(bool multi) {
if (multi) {
//allocate segment data
- uint16_t dataSize = (SEGLEN - 1) * 3; //max. 1365 pixels (ESP8266)
+ uint16_t dataSize = (SEGLEN - 1) * 3; //max. 1365 pixels (ESP8266)
if (!SEGENV.allocateData(dataSize)) {
- return candle(false); //allocation failed
+ return candle(false); //allocation failed
}
}
//max. flicker range controlled by intensity
uint8_t valrange = SEGMENT.intensity;
- uint8_t rndval = valrange >> 1; //max 127
+ uint8_t rndval = valrange >> 1; //max 127
//step (how much to move closer to target per frame) coarsely set by speed
uint8_t speedFactor = 4;
- if (SEGMENT.speed > 252) { //epilepsy
+ if (SEGMENT.speed > 252) { //epilepsy
speedFactor = 1;
- } else if (SEGMENT.speed > 99) { //regular candle (mode called every ~25 ms, so 4 frames to have a new target every 100ms)
+ } else if (SEGMENT.speed > 99) { //regular candle (mode called every ~25 ms, so 4 frames to have a new target every 100ms)
speedFactor = 2;
- } else if (SEGMENT.speed > 49) { //slower fade
+ } else if (SEGMENT.speed > 49) { //slower fade
speedFactor = 3;
- } //else 4 (slowest)
+ } //else 4 (slowest)
uint16_t numCandles = (multi) ? SEGLEN : 1;
for (uint16_t i = 0; i < numCandles; i++) {
- uint16_t d = 0; //data location
+ uint16_t d = 0; //data location
uint8_t s = SEGENV.aux0, s_target = SEGENV.aux1, fadeStep = SEGENV.step;
if (i > 0) {
@@ -2705,14 +2707,14 @@ uint16_t WS2812FX::candle(bool multi) {
s_target = SEGENV.data[d + 1];
fadeStep = SEGENV.data[d + 2];
}
- if (fadeStep == 0) { //init vals
+ if (fadeStep == 0) { //init vals
s = 128;
s_target = 130 + random8(4);
fadeStep = 1;
}
bool newTarget = false;
- if (s_target > s) { //fade up
+ if (s_target > s) { //fade up
s = qadd8(s, fadeStep);
if (s >= s_target) {
newTarget = true;
@@ -2725,7 +2727,7 @@ uint16_t WS2812FX::candle(bool multi) {
}
if (newTarget) {
- s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
+ s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
if (s_target < (rndval >> 1)) {
s_target = (rndval >> 1) + random8(rndval);
}
@@ -2774,9 +2776,9 @@ uint16_t WS2812FX::mode_candle_multi() {
/ Speed sets frequency of new starbursts, intensity is the intensity of the burst
*/
#ifdef ESP8266
-#define STARBURST_MAX_FRAG 8 //52 bytes / star
+#define STARBURST_MAX_FRAG 8 //52 bytes / star
#else
-#define STARBURST_MAX_FRAG 10 //60 bytes / star
+#define STARBURST_MAX_FRAG 10 //60 bytes / star
#endif
//each needs 20+STARBURST_MAX_FRAG*4 bytes
typedef struct particle {
@@ -2789,15 +2791,15 @@ typedef struct particle {
} star;
uint16_t WS2812FX::mode_starburst(void) {
- uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
+ uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
uint8_t segs = getActiveSegmentsNum();
if (segs <= (MAX_NUM_SEGMENTS / 2)) {
- maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
+ maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
}
if (segs <= (MAX_NUM_SEGMENTS / 4)) {
- maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
+ maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
}
- uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg
+ uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg
uint8_t numStars = 1 + (SEGLEN >> 3);
if (numStars > maxStars) {
@@ -2806,16 +2808,16 @@ uint16_t WS2812FX::mode_starburst(void) {
uint16_t dataSize = sizeof(star) * numStars;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
uint32_t it = millis();
star *stars = reinterpret_cast(SEGENV.data);
- float maxSpeed = 375.0f; // Max velocity
- float particleIgnition = 250.0f; // How long to "flash"
- float particleFadeTime = 1500.0f; // Fade out time
+ float maxSpeed = 375.0f; // Max velocity
+ float particleIgnition = 250.0f; // How long to "flash"
+ float particleFadeTime = 1500.0f; // Fade out time
for (int j = 0; j < numStars; j++) {
// speed to adjust chance of a burst, max is nearly always.
@@ -2873,12 +2875,12 @@ uint16_t WS2812FX::mode_starburst(void) {
// Figure out how much to fade and shrink the star based on
// its age relative to its lifetime
if (age > particleIgnition + particleFadeTime) {
- fade = 1.0f; // Black hole, all faded out
+ fade = 1.0f; // Black hole, all faded out
stars[j].birth = 0;
c = col_to_crgb(SEGCOLOR(1));
} else {
age -= particleIgnition;
- fade = (age / particleFadeTime); // Fading star
+ fade = (age / particleFadeTime); // Fading star
byte f = 254.5f * fade;
c = col_to_crgb(color_blend(crgb_to_col(c), SEGCOLOR(1), f));
}
@@ -2922,23 +2924,23 @@ uint16_t WS2812FX::mode_starburst(void) {
*/
uint16_t WS2812FX::mode_exploding_fireworks(void) {
//allocate segment data
- uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
+ uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
uint8_t segs = getActiveSegmentsNum();
if (segs <= (MAX_NUM_SEGMENTS / 2)) {
- maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
+ maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
}
if (segs <= (MAX_NUM_SEGMENTS / 4)) {
- maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
+ maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs
}
- int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg
+ int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg
uint16_t numSparks = min(2 + (SEGLEN >> 1), maxSparks);
uint16_t dataSize = sizeof(spark) * numSparks;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
- if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated
+ if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated
SEGENV.aux0 = 0;
SEGENV.aux1 = dataSize;
}
@@ -2950,18 +2952,18 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) {
SEGMENT.setOption(SEG_OPTION_REVERSED, SEGENV.step);
Spark *sparks = reinterpret_cast(SEGENV.data);
- Spark *flare = sparks; //first spark is flare data
+ Spark *flare = sparks; //first spark is flare data
- float gravity = -0.0004 - (SEGMENT.speed / 800000.0); // m/s/s
+ float gravity = -0.0004 - (SEGMENT.speed / 800000.0); // m/s/s
gravity *= SEGLEN;
- if (SEGENV.aux0 < 2) { //FLARE
- if (SEGENV.aux0 == 0) { //init flare
+ if (SEGENV.aux0 < 2) { //FLARE
+ if (SEGENV.aux0 == 0) { //init flare
flare->pos = 0;
- uint16_t peakHeight = 75 + random8(180); //0-255
+ uint16_t peakHeight = 75 + random8(180); //0-255
peakHeight = (peakHeight * (SEGLEN - 1)) >> 8;
flare->vel = sqrt(-2.0 * gravity * peakHeight);
- flare->col = 255; //brightness
+ flare->col = 255; //brightness
SEGENV.aux0 = 1;
}
@@ -2976,7 +2978,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) {
flare->vel += gravity;
flare->col -= 2;
} else {
- SEGENV.aux0 = 2; // ready to explode
+ SEGENV.aux0 = 2; // ready to explode
}
} else if (SEGENV.aux0 < 4) {
/*
@@ -2993,11 +2995,11 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) {
if (SEGENV.aux0 == 2) {
for (int i = 1; i < nSparks; i++) {
sparks[i].pos = flare->pos;
- sparks[i].vel = (float(random16(0, 20000)) / 10000.0) - 0.9; // from -0.9 to 1.1
- sparks[i].col = 345; //abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
+ sparks[i].vel = (float(random16(0, 20000)) / 10000.0) - 0.9; // from -0.9 to 1.1
+ sparks[i].col = 345; //abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
//sparks[i].col = constrain(sparks[i].col, 0, 345);
sparks[i].colIndex = random8();
- sparks[i].vel *= flare->pos / SEGLEN; // proportional to height
+ sparks[i].vel *= flare->pos / SEGLEN; // proportional to height
sparks[i].vel *= -gravity * 50;
}
//sparks[1].col = 345; // this will be our known spark
@@ -3005,7 +3007,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) {
SEGENV.aux0 = 3;
}
- if (sparks[1].col > 4) { //&& sparks[1].pos > 0) // as long as our known spark is lit, work with all the sparks
+ if (sparks[1].col > 4) { //&& sparks[1].pos > 0) // as long as our known spark is lit, work with all the sparks
for (int i = 1; i < nSparks; i++) {
sparks[i].pos += sparks[i].vel;
sparks[i].vel += dying_gravity;
@@ -3016,10 +3018,10 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) {
if (sparks[i].pos > 0 && sparks[i].pos < SEGLEN) {
uint16_t prog = sparks[i].col;
uint32_t spColor = (SEGMENT.palette) ? color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
- CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
- if (prog > 300) { //fade from white to spark color
+ CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
+ if (prog > 300) { //fade from white to spark color
c = col_to_crgb(color_blend(spColor, WHITE, (prog - 300) * 5));
- } else if (prog > 45) { //fade from spark color to black
+ } else if (prog > 45) { //fade from spark color to black
c = col_to_crgb(color_blend(BLACK, spColor, prog - 45));
uint8_t cooling = (300 - prog) >> 5;
c.g = qsub8(c.g, cooling);
@@ -3028,15 +3030,15 @@ uint16_t WS2812FX::mode_exploding_fireworks(void) {
setPixelColor(int(sparks[i].pos), c.red, c.green, c.blue);
}
}
- dying_gravity *= .99; // as sparks burn out they fall slower
+ dying_gravity *= .99; // as sparks burn out they fall slower
} else {
- SEGENV.aux0 = 6 + random8(10); //wait for this many frames
+ SEGENV.aux0 = 6 + random8(10); //wait for this many frames
}
} else {
SEGENV.aux0--;
if (SEGENV.aux0 < 4) {
- SEGENV.aux0 = 0; //back to flare
- SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
+ SEGENV.aux0 = 0; //back to flare
+ SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
}
}
@@ -3055,68 +3057,68 @@ uint16_t WS2812FX::mode_drip(void) {
uint8_t numDrops = 4;
uint16_t dataSize = sizeof(spark) * numDrops;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
fill(SEGCOLOR(1));
Spark *drops = reinterpret_cast(SEGENV.data);
- numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
+ numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
float gravity = -0.0005 - (SEGMENT.speed / 50000.0);
gravity *= SEGLEN;
int sourcedrop = 12;
for (uint8_t j = 0; j < numDrops; j++) {
- if (drops[j].colIndex == 0) { //init
- drops[j].pos = SEGLEN - 1; // start at end
- drops[j].vel = 0; // speed
- drops[j].col = sourcedrop; // brightness
- drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing)
+ if (drops[j].colIndex == 0) { //init
+ drops[j].pos = SEGLEN - 1; // start at end
+ drops[j].vel = 0; // speed
+ drops[j].col = sourcedrop; // brightness
+ drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing)
}
- setPixelColor(SEGLEN - 1, color_blend(BLACK, SEGCOLOR(0), sourcedrop)); // water source
+ setPixelColor(SEGLEN - 1, color_blend(BLACK, SEGCOLOR(0), sourcedrop)); // water source
if (drops[j].colIndex == 1) {
if (drops[j].col > 255) {
drops[j].col = 255;
}
setPixelColor(uint16_t(drops[j].pos), color_blend(BLACK, SEGCOLOR(0), drops[j].col));
- drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
+ drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
- if (random8() < drops[j].col / 10) { // random drop
- drops[j].colIndex = 2; //fall
+ if (random8() < drops[j].col / 10) { // random drop
+ drops[j].colIndex = 2; //fall
drops[j].col = 255;
}
}
- if (drops[j].colIndex > 1) { // falling
- if (drops[j].pos > 0) { // fall until end of segment
+ if (drops[j].colIndex > 1) { // falling
+ if (drops[j].pos > 0) { // fall until end of segment
drops[j].pos += drops[j].vel;
if (drops[j].pos < 0) {
drops[j].pos = 0;
}
- drops[j].vel += gravity; // gravity is negative
+ drops[j].vel += gravity; // gravity is negative
- for (uint16_t i = 1; i < 7 - drops[j].colIndex; i++) { // some minor math so we don't expand bouncing droplets
- uint16_t pos = constrain(uint16_t(drops[j].pos) + i, 0, SEGLEN - 1); //this is BAD, returns a pos >= SEGLEN occasionally
- setPixelColor(pos, color_blend(BLACK, SEGCOLOR(0), drops[j].col / i)); //spread pixel with fade while falling
+ for (uint16_t i = 1; i < 7 - drops[j].colIndex; i++) { // some minor math so we don't expand bouncing droplets
+ uint16_t pos = constrain(uint16_t(drops[j].pos) + i, 0, SEGLEN - 1); //this is BAD, returns a pos >= SEGLEN occasionally
+ setPixelColor(pos, color_blend(BLACK, SEGCOLOR(0), drops[j].col / i)); //spread pixel with fade while falling
}
- if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
+ if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
setPixelColor(0, color_blend(SEGCOLOR(0), BLACK, drops[j].col));
}
- } else { // we hit bottom
- if (drops[j].colIndex > 2) { // already hit once, so back to forming
+ } else { // we hit bottom
+ if (drops[j].colIndex > 2) { // already hit once, so back to forming
drops[j].colIndex = 0;
drops[j].col = sourcedrop;
} else {
- if (drops[j].colIndex == 2) { // init bounce
- drops[j].vel = -drops[j].vel / 4; // reverse velocity with damping
+ if (drops[j].colIndex == 2) { // init bounce
+ drops[j].vel = -drops[j].vel / 4; // reverse velocity with damping
drops[j].pos += drops[j].vel;
}
drops[j].col = sourcedrop * 2;
- drops[j].colIndex = 5; // bouncing
+ drops[j].colIndex = 5; // bouncing
}
}
}
@@ -3138,46 +3140,46 @@ typedef struct Tetris {
uint16_t WS2812FX::mode_tetrix(void) {
uint16_t dataSize = sizeof(tetris);
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
Tetris *drop = reinterpret_cast(SEGENV.data);
// initialize dropping on first call or segment full
if (SEGENV.call == 0 || SEGENV.aux1 >= SEGLEN) {
- SEGENV.aux1 = 0; // reset brick stack size
+ SEGENV.aux1 = 0; // reset brick stack size
SEGENV.step = 0;
fill(SEGCOLOR(1));
- return 250; // short wait
+ return 250; // short wait
}
- if (SEGENV.step == 0) { //init
- drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed >> 2) + 1 : random8(6, 64)); // set speed
- drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
- drop->col = color_from_palette(random8(0, 15) << 4, false, false, 0); // limit color choices so there is enough HUE gap
- SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
- SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity >> 5) + 1 : random8(1, 5)) * (1 + (SEGLEN >> 6)); // size of brick
+ if (SEGENV.step == 0) { //init
+ drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed >> 2) + 1 : random8(6, 64)); // set speed
+ drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
+ drop->col = color_from_palette(random8(0, 15) << 4, false, false, 0); // limit color choices so there is enough HUE gap
+ SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
+ SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity >> 5) + 1 : random8(1, 5)) * (1 + (SEGLEN >> 6)); // size of brick
}
- if (SEGENV.step == 1) { // forming
- if (random8() >> 6) { // random drop
- SEGENV.step = 2; // fall
+ if (SEGENV.step == 1) { // forming
+ if (random8() >> 6) { // random drop
+ SEGENV.step = 2; // fall
}
}
- if (SEGENV.step > 1) { // falling
- if (drop->pos > SEGENV.aux1) { // fall until top of stack
- drop->pos -= drop->speed; // may add gravity as: speed += gravity
+ if (SEGENV.step > 1) { // falling
+ if (drop->pos > SEGENV.aux1) { // fall until top of stack
+ drop->pos -= drop->speed; // may add gravity as: speed += gravity
if (int(drop->pos) < SEGENV.aux1) {
drop->pos = SEGENV.aux1;
}
for (uint16_t i = int(drop->pos); i < SEGLEN; i++) {
setPixelColor(i, i < int(drop->pos) + SEGENV.aux0 ? drop->col : SEGCOLOR(1));
}
- } else { // we hit bottom
- SEGENV.step = 0; // go back to init
- SEGENV.aux1 += SEGENV.aux0; // increase the stack size
+ } else { // we hit bottom
+ SEGENV.step = 0; // go back to init
+ SEGENV.aux1 += SEGENV.aux0; // increase the stack size
if (SEGENV.aux1 >= SEGLEN) {
- return 1000; // wait for a second
+ return 1000; // wait for a second
}
}
}
@@ -3191,14 +3193,14 @@ uint16_t WS2812FX::mode_tetrix(void) {
uint16_t WS2812FX::mode_plasma(void) {
// initialize phases on start
if (SEGENV.call == 0) {
- SEGENV.aux0 = random8(0, 2); // add a bit of randomness
+ SEGENV.aux0 = random8(0, 2); // add a bit of randomness
}
uint8_t thisPhase = beatsin8(6 + SEGENV.aux0, -64, 64);
uint8_t thatPhase = beatsin8(7 + SEGENV.aux0, -64, 64);
- for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
- uint8_t colorIndex = cubicwave8((i * (2 + 3 * (SEGMENT.speed >> 5)) + thisPhase) & 0xFF) / 2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
- + cos8((i * (1 + 2 * (SEGMENT.speed >> 5)) + thatPhase) & 0xFF) / 2; // factor=15 // Hey, you can even change the frequencies if you wish.
+ for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
+ uint8_t colorIndex = cubicwave8((i * (2 + 3 * (SEGMENT.speed >> 5)) + thisPhase) & 0xFF) / 2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
+ + cos8((i * (1 + 2 * (SEGMENT.speed >> 5)) + thatPhase) & 0xFF) / 2; // factor=15 // Hey, you can even change the frequencies if you wish.
uint8_t thisBright = qsub8(colorIndex, beatsin8(7, 0, (128 - (SEGMENT.intensity >> 1))));
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
setPixelColor(i, color.red, color.green, color.blue);
@@ -3239,7 +3241,7 @@ uint16_t WS2812FX::mode_percent(void) {
}
}
- if (active_leds > SEGENV.step) { // smooth transition to the target value
+ if (active_leds > SEGENV.step) { // smooth transition to the target value
SEGENV.step += size;
if (SEGENV.step > active_leds) {
SEGENV.step = active_leds;
@@ -3271,12 +3273,12 @@ uint16_t WS2812FX::mode_heartbeat(void) {
SEGENV.aux1 = bri_lower;
unsigned long beatTimer = millis() - SEGENV.step;
- if ((beatTimer > secondBeat) && !SEGENV.aux0) { // time for the second beat?
- SEGENV.aux1 = UINT16_MAX; //full bri
+ if ((beatTimer > secondBeat) && !SEGENV.aux0) { // time for the second beat?
+ SEGENV.aux1 = UINT16_MAX; //full bri
SEGENV.aux0 = 1;
}
- if (beatTimer > msPerBeat) { // time to reset the beat timer?
- SEGENV.aux1 = UINT16_MAX; //full bri
+ if (beatTimer > msPerBeat) { // time to reset the beat timer?
+ SEGENV.aux1 = UINT16_MAX; //full bri
SEGENV.aux0 = 0;
SEGENV.step = millis();
}
@@ -3396,7 +3398,7 @@ CRGB WS2812FX::pacifica_one_layer(uint16_t i, CRGBPalette16 &p, uint16_t cistart
uint16_t waveangle = ioff;
uint16_t wavescale_half = (wavescale >> 1) + 20;
- waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i
+ waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i
uint16_t s16 = sin16(waveangle) + 32768;
uint16_t cs = scale16(s16, wavescale_half) + wavescale_half;
ci += (cs * i);
@@ -3424,19 +3426,19 @@ uint16_t WS2812FX::mode_sunrise() {
//speed 60 - 120 : sunset time in minutes - 60;
//speed above: "breathing" rise and set
if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) {
- SEGENV.step = millis(); //save starting time, millis() because now can change from sync
+ SEGENV.step = millis(); //save starting time, millis() because now can change from sync
SEGENV.aux0 = SEGMENT.speed;
}
fill(0);
uint16_t stage = 0xFFFF;
- uint32_t s10SinceStart = (millis() - SEGENV.step) / 100; //tenths of seconds
+ uint32_t s10SinceStart = (millis() - SEGENV.step) / 100; //tenths of seconds
- if (SEGMENT.speed > 120) { //quick sunrise and sunset
+ if (SEGMENT.speed > 120) { //quick sunrise and sunset
uint16_t counter = (now >> 1) * (((SEGMENT.speed - 120) >> 1) + 1);
stage = triwave16(counter);
- } else if (SEGMENT.speed) { //sunrise
+ } else if (SEGMENT.speed) { //sunrise
uint8_t durMins = SEGMENT.speed;
if (durMins > 60) {
durMins -= 60;
@@ -3447,21 +3449,21 @@ uint16_t WS2812FX::mode_sunrise() {
}
stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF);
if (SEGMENT.speed > 60) {
- stage = 0xFFFF - stage; //sunset
+ stage = 0xFFFF - stage; //sunset
}
}
for (uint16_t i = 0; i <= SEGLEN / 2; i++) {
//default palette is Fire
- uint32_t c = color_from_palette(0, false, true, 255); //background
+ uint32_t c = color_from_palette(0, false, true, 255); //background
uint16_t wave = triwave16((i * stage) / SEGLEN);
wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15);
- if (wave > 240) { //clipped, full white sun
+ if (wave > 240) { //clipped, full white sun
c = color_from_palette(240, false, true, 255);
- } else { //transition
+ } else { //transition
c = color_from_palette(wave, false, true, 255);
}
setPixelColor(i, c);
@@ -3474,33 +3476,33 @@ uint16_t WS2812FX::mode_sunrise() {
/*
* Effects by Andrew Tuline
*/
-uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline.
+uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline.
- uint8_t allfreq = 16; // Base frequency.
+ uint8_t allfreq = 16; // Base frequency.
//float* phasePtr = reinterpret_cast(SEGENV.step); // Phase change value gets calculated.
- static float phase = 0; //phasePtr[0];
- uint8_t cutOff = (255 - SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192).
- uint8_t modVal = 5; //SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5).
+ static float phase = 0; //phasePtr[0];
+ uint8_t cutOff = (255 - SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192).
+ uint8_t modVal = 5; //SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5).
- uint8_t index = now / 64; // Set color rotation speed
- phase += SEGMENT.speed / 32.0; // You can change the speed of the wave. AKA SPEED (was .4)
+ uint8_t index = now / 64; // Set color rotation speed
+ phase += SEGMENT.speed / 32.0; // You can change the speed of the wave. AKA SPEED (was .4)
//phasePtr[0] = phase;
for (int i = 0; i < SEGLEN; i++) {
if (moder == 1) {
- modVal = (inoise8(i * 10 + i * 10) / 16); // Let's randomize our mod length with some Perlin noise.
+ modVal = (inoise8(i * 10 + i * 10) / 16); // Let's randomize our mod length with some Perlin noise.
}
- uint16_t val = (i + 1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used.
+ uint16_t val = (i + 1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used.
if (modVal == 0) {
modVal = 1;
}
- val += phase * (i % modVal + 1) / 2; // This sets the varying phase change of the waves. By Andrew Tuline.
- uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave.
- b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
+ val += phase * (i % modVal + 1) / 2; // This sets the varying phase change of the waves. By Andrew Tuline.
+ uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave.
+ b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b));
index += 256 / SEGLEN;
if (SEGLEN > 256) {
- index++; // Correction for segments longer than 256 LEDs
+ index++; // Correction for segments longer than 256 LEDs
}
}
@@ -3515,11 +3517,11 @@ uint16_t WS2812FX::mode_phased_noise(void) {
return phased_base(1);
}
-uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
- random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
+uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
+ random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
for (int i = 0; i < SEGLEN; i++) {
- uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work.
+ uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work.
uint8_t pixBri = sin8(ranstart + 16 * now / (256 - SEGMENT.speed));
if (random8() > SEGMENT.intensity) {
pixBri = 0;
@@ -3531,18 +3533,18 @@ uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with f
}
// Peaceful noise that's slow and with gradually changing palettes. Does not support WLED palettes or default colours or controls.
-uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline.
- uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
+uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline.
+ uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
//#define scale 30
- uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes)
+ uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes)
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
CRGBPalette16 *palettes = reinterpret_cast(SEGENV.data);
- uint16_t changePaletteMs = 4000 + SEGMENT.speed * 10; //between 4 - 6.5sec
+ uint16_t changePaletteMs = 4000 + SEGMENT.speed * 10; //between 4 - 6.5sec
if (millis() - SEGENV.step > changePaletteMs) {
SEGENV.step = millis();
@@ -3553,19 +3555,19 @@ uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by And
CRGB color;
//EVERY_N_MILLIS(10) //(don't have to time this, effect function is only called every 24ms)
- nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations.
+ nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations.
if (SEGMENT.palette > 0) {
palettes[0] = currentPalette;
}
for (int i = 0; i < SEGLEN; i++) {
- uint8_t index = inoise8(i * scale, SEGENV.aux0 + i * scale); // Get a value from the noise function. I'm using both x and y axis.
- color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette.
+ uint8_t index = inoise8(i * scale, SEGENV.aux0 + i * scale); // Get a value from the noise function. I'm using both x and y axis.
+ color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette.
setPixelColor(i, color.red, color.green, color.blue);
}
- SEGENV.aux0 += beatsin8(10, 1, 4); // Moving along the distance. Vary it a bit with a sine wave.
+ SEGENV.aux0 += beatsin8(10, 1, 4); // Moving along the distance. Vary it a bit with a sine wave.
return FRAMETIME;
}
@@ -3573,16 +3575,16 @@ uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by And
// Sine waves that have controllable phase change speed, frequency and cutoff. By Andrew Tuline.
// SEGMENT.speed ->Speed, SEGMENT.intensity -> Frequency (SEGMENT.fft1 -> Color change, SEGMENT.fft2 -> PWM cutoff)
//
-uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline
+uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline
//#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0
- uint16_t colorIndex = now / 32; //(256 - SEGMENT.fft1); // Amount of colour change.
+ uint16_t colorIndex = now / 32; //(256 - SEGMENT.fft1); // Amount of colour change.
- SEGENV.step += SEGMENT.speed / 16; // Speed of animation.
- uint16_t freq = SEGMENT.intensity / 4; //SEGMENT.fft2/8; // Frequency of the signal.
+ SEGENV.step += SEGMENT.speed / 16; // Speed of animation.
+ uint16_t freq = SEGMENT.intensity / 4; //SEGMENT.fft2/8; // Frequency of the signal.
- for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows:
- int pixBri = cubicwave8((i * freq) + SEGENV.step); //qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub)..
+ for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows:
+ int pixBri = cubicwave8((i * freq) + SEGENV.step); //qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub)..
//setPixCol(i, i*colorIndex/255, pixBri);
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i * colorIndex / 255, false, PALETTE_SOLID_WRAP, 0), pixBri));
}
@@ -3600,10 +3602,10 @@ uint16_t WS2812FX::mode_flow(void) {
counter = counter >> 8;
}
- uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs
+ uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs
uint16_t zones = (SEGMENT.intensity * maxZones) >> 8;
if (zones & 0x01) {
- zones++; //zones must be even
+ zones++; //zones must be even
}
if (zones < 2) {
zones = 2;
@@ -3635,14 +3637,14 @@ uint16_t WS2812FX::mode_flow(void) {
uint16_t WS2812FX::mode_chunchun(void) {
fill(SEGCOLOR(1));
uint16_t counter = now * (6 + (SEGMENT.speed >> 4));
- uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
+ uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
uint16_t span = (SEGMENT.intensity << 8) / numBirds;
for (uint16_t i = 0; i < numBirds; i++) {
counter -= span;
uint16_t megumin = sin16(counter) + 0x8000;
uint32_t bird = (megumin * SEGLEN) >> 16;
- uint32_t c = color_from_palette((i * 255) / numBirds, false, false, 0); // no palette wrapping
+ uint32_t c = color_from_palette((i * 255) / numBirds, false, false, 0); // no palette wrapping
setPixelColor(bird, c);
}
return FRAMETIME;
@@ -3666,9 +3668,9 @@ typedef struct Spotlight {
#define SPOT_TYPE_4X_DOT 5
#define SPOT_TYPES_COUNT 6
#ifdef ESP8266
-#define SPOT_MAX_COUNT 17 //Number of simultaneous waves
+#define SPOT_MAX_COUNT 17 //Number of simultaneous waves
#else
-#define SPOT_MAX_COUNT 49 //Number of simultaneous waves
+#define SPOT_MAX_COUNT 49 //Number of simultaneous waves
#endif
/*
@@ -3679,13 +3681,13 @@ typedef struct Spotlight {
* By Steve Pomeroy @xxv
*/
uint16_t WS2812FX::mode_dancing_shadows(void) {
- uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 18 segment ESP8266
+ uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 18 segment ESP8266
bool initialize = SEGENV.aux0 != numSpotlights;
SEGENV.aux0 = numSpotlights;
uint16_t dataSize = sizeof(spotlight) * numSpotlights;
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
Spotlight *spotlights = reinterpret_cast(SEGENV.data);
@@ -3819,9 +3821,9 @@ uint16_t WS2812FX::mode_washing_machine(void) {
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
*/
uint16_t WS2812FX::mode_blends(void) {
- uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 18 segment ESP8266
+ uint16_t dataSize = sizeof(uint32_t) * SEGLEN; // max segment length of 56 pixels on 18 segment ESP8266
if (!SEGENV.allocateData(dataSize)) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
uint32_t *pixels = reinterpret_cast(SEGENV.data);
uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
@@ -3856,7 +3858,7 @@ typedef struct TvSim {
uint8_t actualColorR = 0;
uint8_t actualColorG = 0;
uint8_t actualColorB = 0;
- uint16_t pr = 0; // Prev R, G, B
+ uint16_t pr = 0; // Prev R, G, B
uint16_t pg = 0;
uint16_t pb = 0;
} tvSim;
@@ -3866,7 +3868,7 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
uint8_t sat, bri, j;
if (!SEGENV.allocateData(sizeof(tvSim))) {
- return mode_static(); //allocation failed
+ return mode_static(); //allocation failed
}
TvSim *tvSimulator = reinterpret_cast(SEGENV.data);
@@ -3881,11 +3883,11 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
// create a new sceene
if (((millis() - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) {
- tvSimulator->sceeneStart = millis(); // remember the start of the new sceene
- tvSimulator->sceeneDuration = random16(60 * 250 * colorSpeed, 60 * 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider)
- tvSimulator->sceeneColorHue = random16(0, 768); // random start color-tone for the sceene
- tvSimulator->sceeneColorSat = random8(100, 130 + colorIntensity); // random start color-saturation for the sceene
- tvSimulator->sceeneColorBri = random8(200, 240); // random start color-brightness for the sceene
+ tvSimulator->sceeneStart = millis(); // remember the start of the new sceene
+ tvSimulator->sceeneDuration = random16(60 * 250 * colorSpeed, 60 * 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider)
+ tvSimulator->sceeneColorHue = random16(0, 768); // random start color-tone for the sceene
+ tvSimulator->sceeneColorSat = random8(100, 130 + colorIntensity); // random start color-saturation for the sceene
+ tvSimulator->sceeneColorBri = random8(200, 240); // random start color-brightness for the sceene
SEGENV.aux1 = 1;
SEGENV.aux0 = 0;
}
@@ -3894,8 +3896,8 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
if (SEGENV.aux0 == 0) {
// hue change in both directions
j = random8(4 * colorIntensity);
- hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative
- ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767); // positive
+ hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative
+ ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767); // positive
// saturation
j = random8(2 * colorIntensity);
@@ -3907,7 +3909,7 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
// calculate R,G,B from HSV
// Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
- { // just to create a local scope for the variables
+ { // just to create a local scope for the variables
uint8_t temp[5], n = (hue >> 8) % 3;
uint8_t x = ((((hue & 255) * sat) >> 8) * bri) >> 8;
uint8_t s = ((256 - sat) * bri) >> 8;
@@ -3920,22 +3922,22 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
}
}
// Apply gamma correction, further expand to 16/16/16
- nr = (uint8_t)gamma8(tvSimulator->actualColorR) * 257; // New R/G/B
+ nr = (uint8_t)gamma8(tvSimulator->actualColorR) * 257; // New R/G/B
ng = (uint8_t)gamma8(tvSimulator->actualColorG) * 257;
nb = (uint8_t)gamma8(tvSimulator->actualColorB) * 257;
- if (SEGENV.aux0 == 0) { // initialize next iteration
+ if (SEGENV.aux0 == 0) { // initialize next iteration
SEGENV.aux0 = 1;
// randomize total duration and fade duration for the actual color
- tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time
- tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
+ tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time
+ tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
if (random8(10) < 3) {
- tvSimulator->fadeTime = 0; // Force scene cut 30% of time
+ tvSimulator->fadeTime = 0; // Force scene cut 30% of time
}
tvSimulator->startTime = millis();
- } // end of initialization
+ } // end of initialization
// how much time is elapsed ?
tvSimulator->elapsed = millis() - tvSimulator->startTime;
@@ -3945,7 +3947,7 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr);
g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng);
b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb);
- } else { // Avoid divide-by-zero in map()
+ } else { // Avoid divide-by-zero in map()
r = nr;
g = ng;
b = nb;
@@ -3953,12 +3955,12 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
// set strip color
for (i = 0; i < SEGLEN; i++) {
- setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit
+ setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit
}
// if total duration has passed, remember last color and restart the loop
if (tvSimulator->elapsed >= tvSimulator->totalTime) {
- tvSimulator->pr = nr; // Prev RGB = new RGB
+ tvSimulator->pr = nr; // Prev RGB = new RGB
tvSimulator->pg = ng;
tvSimulator->pb = nb;
SEGENV.aux0 = 0;
@@ -3973,12 +3975,12 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
//CONFIG
#ifdef ESP8266
-#define W_MAX_COUNT 9 //Number of simultaneous waves
+#define W_MAX_COUNT 9 //Number of simultaneous waves
#else
-#define W_MAX_COUNT 20 //Number of simultaneous waves
+#define W_MAX_COUNT 20 //Number of simultaneous waves
#endif
-#define W_MAX_SPEED 6 //Higher number, higher speed
-#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
+#define W_MAX_SPEED 6 //Higher number, higher speed
+#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
//24 bytes
class AuroraWave {
@@ -3999,7 +4001,7 @@ class AuroraWave {
basecolor = color;
basealpha = random(60, 101) / (float)100;
age = 0;
- width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
+ width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
if (!width) {
width = 1;
}
@@ -4011,7 +4013,7 @@ class AuroraWave {
CRGB getColorForLED(int ledIndex) {
if (ledIndex < center - width || ledIndex > center + width) {
- return 0; //Position out of range of this wave
+ return 0; //Position out of range of this wave
}
CRGB rgb;
@@ -4084,8 +4086,8 @@ uint16_t WS2812FX::mode_aurora(void) {
SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
SEGENV.aux0 = SEGMENT.intensity;
- if (!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 18 segment ESP8266
- return mode_static(); //allocation failed
+ if (!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 18 segment ESP8266
+ return mode_static(); //allocation failed
}
waves = reinterpret_cast(SEGENV.data);
@@ -4107,7 +4109,7 @@ uint16_t WS2812FX::mode_aurora(void) {
}
}
- uint8_t backlight = 1; //dimmer backlight if less active colors
+ uint8_t backlight = 1; //dimmer backlight if less active colors
if (SEGCOLOR(0)) {
backlight++;
}
@@ -4137,18 +4139,18 @@ uint16_t WS2812FX::mode_aurora(void) {
return FRAMETIME;
}
+#define N_LEDS_PER_EDGE 10
+
/*
* New awesome Hive 51 Light Installation effect.
* Random Strobing Segments
*/
-uint16_t WS2812FX::mode_hive_51(void) {
- const uint8_t N_LEDS_PER_EDGE = 10;
+uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150U; // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint16_t prog = (perc * 10) / cycleTime; // current progress in active cycle (0 = start, 10 = end)
- uint32_t cycleTime = 750 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
- uint32_t perc = now % cycleTime; // current time step in active cycle in ms
- uint16_t prog = (perc * 10) / cycleTime; // current progress in active cycle (0 = start, 65535 = end)
-
- uint8_t nActiveEdges = SEGLEN / N_LEDS_PER_EDGE / 3; // set 1/3 of the edges to active
+ uint16_t nActiveEdges = SEGLEN / N_LEDS_PER_EDGE / 3U; // set 1/3 of the edges to active
// check if active edges are set
if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
if (!SEGENV.allocateData(nActiveEdges)) {
@@ -4177,13 +4179,15 @@ uint16_t WS2812FX::mode_hive_51(void) {
}
}
}
- if (SEGENV.step == (uint8_t)(prog - 1) || !isValidData) {
+ if (!isValidData || SEGENV.step != prog) {
+ //if (SEGENV.step == (uint8_t)(prog - 1) || SEGENV.step == 0 || !isValidData) {
// update active segments to next random value
for (uint8_t ii = 0; ii < nActiveEdges; ii++) {
bool duplicates;
do {
+ // get new random edge and check if it already on
duplicates = false;
- SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE - 1);
+ SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE);
for (uint8_t jj = 0; jj < ii; jj++) {
if (SEGENV.data[ii] == SEGENV.data[jj]) {
duplicates = true;
@@ -4192,9 +4196,9 @@ uint16_t WS2812FX::mode_hive_51(void) {
}
} while (duplicates);
}
- } else {
+ /*} else {
// this should not happen
- return 0;
+ return mode_static();*/
}
// set LED colors
@@ -4208,32 +4212,98 @@ uint16_t WS2812FX::mode_hive_51(void) {
break;
}
}
+ uint32_t color = RED;
if (isActiveEdge) {
// set LED colors on active edge to white
- for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
- setPixelColor(jj, WHITE);
- }
- ii += N_LEDS_PER_EDGE - 1;
- continue;
+ color = WHITE;
} else {
// set LED colors on inactive edge to black
- for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
- setPixelColor(jj, BLACK);
- }
- ii += N_LEDS_PER_EDGE - 1;
- continue;
+ color = BLACK;
+ }
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(jj, color);
}
+ ii += N_LEDS_PER_EDGE - 1;
+
} else {
- setPixelColor(ii, BLACK);
+ setPixelColor(ii, RED);
}
}
- for (uint8_t ii = 0; ii < sizeof(SEGENV.data); ii++) {
- // cycle through active edges
- for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
- setPixelColor(SEGENV.data[ii] * N_LEDS_PER_EDGE + jj, WHITE);
- }
+
+ SEGENV.step = prog; // update step counter
+ return FRAMETIME;
+}
+
+#define EDGES_0 \
+ { 0, 70, 140 }
+#define EDGES_1 \
+ { 10, 80, 150 }
+#define EDGES_2 \
+ { 20, 90, 160 }
+#define EDGES_3 \
+ { 30, 100, 170 }
+#define EDGES_4 \
+ { 40, 110, 180 }
+#define EDGES_5 \
+ { 50, 120, 190 }
+
+#define EDGES_0_DIR \
+ { true, false, true }
+#define EDGES_1_DIR \
+ { true, false, true }
+#define EDGES_2_DIR \
+ { true, false, true }
+#define EDGES_3_DIR \
+ { true, false, true }
+#define EDGES_4_DIR \
+ { true, false, true }
+#define EDGES_5_DIR \
+ { true, false, true }
+
+#define SLOPE 30
+#define ROTATION_COLOR WHITE
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Random Strobing Segments
+ */
+uint16_t WS2812FX::mode_HIVE_rotate(void) {
+
+ // TODO: reverse counter-clockwise edges
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint16_t prog = (perc * 6 * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 60 = end)
+
+ for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
+ // edges 0 for first 30 steps
+ uint8_t diff = 0;
+ bool dir;
+ if (std::find(std::begin(EDGES_0), std::end(EDGES_0), ii) != std::end(EDGES_0)) {
+ diff = prog;
+ dir = EDGES_0_DIR[std::find(std::begin(EDGES_0), std::end(EDGES_0), ii)];
+ } else if (std::find(std::begin(EDGES_1), std::end(EDGES_1), ii) != std::end(EDGES_1)) {
+ diff = prog - N_LEDS_PER_EDGE;
+ } else if (std::find(std::begin(EDGES_2), std::end(EDGES_2), ii) != std::end(EDGES_2)) {
+ diff = prog - 2 * N_LEDS_PER_EDGE;
+ } else if (std::find(std::begin(EDGES_3), std::end(EDGES_3), ii) != std::end(EDGES_3)) {
+ diff = prog - 3 * N_LEDS_PER_EDGE;
+ } else if (std::find(std::begin(EDGES_4), std::end(EDGES_4), ii) != std::end(EDGES_4)) {
+ diff = prog - 4 * N_LEDS_PER_EDGE;
+ } else if (std::find(std::begin(EDGES_5), std::end(EDGES_5), ii) != std::end(EDGES_5)) {
+ diff = prog - 5 * N_LEDS_PER_EDGE;
+ } else {
+ for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(ii + jj, BLACK);
+ }
+ continue;
+ }
+ for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
+ diff -= jj;
+ diff %= 6 * N_LEDS_PER_EDGE;
+ diff = diff < 0 ? diff + 6 * N_LEDS_PER_EDGE : diff;
+ setPixelColor(ii + jj, color_from_palette(((float) diff) / 6 / N_LEDS_PER_EDGE * 256, false, false, 255U));
+ }
}
- SEGENV.step = prog; // update step counter
return FRAMETIME;
-}
\ No newline at end of file
+}
diff --git a/wled00/FX.h b/wled00/FX.h
index d713575795..97d09c0c96 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -116,7 +116,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
-#define MODE_COUNT 119
+#define MODE_COUNT 120
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -236,7 +236,8 @@
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
-#define FX_MODE_HIVE_51 118
+#define FX_MODE_HIVE_51_STROBE_SEG 118 // custom effect for HIVE
+#define FX_MODE_HIVE_51_ROTATE 119 // custom effect for HIVE
class WS2812FX {
@@ -610,7 +611,8 @@ class WS2812FX {
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
- _mode[FX_MODE_HIVE_51] = &WS2812FX::mode_hive_51;
+ _mode[FX_MODE_HIVE_51_STROBE_SEG] = &WS2812FX::mode_HIVE_strobing_segments; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_51_ROTATE] = &WS2812FX::mode_HIVE_rotate; // custom effect for HIVE
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@@ -827,7 +829,8 @@ class WS2812FX {
mode_blends(void),
mode_tv_simulator(void),
mode_dynamic_smooth(void),
- mode_hive_51(void);
+ mode_HIVE_strobing_segments(void), // custom effect for HIVE
+ mode_HIVE_rotate(void); // custom effect for HIVE
private:
uint32_t crgb_to_col(CRGB fastled);
@@ -920,7 +923,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
-"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Hive 51"
+"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Hive 51 Strobe","Hive 51 Rotation"
])=====";
From 5feace19b1cee298b704ee55c285290ee2fe5329 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 10 Oct 2021 21:24:42 +0200
Subject: [PATCH 05/31] adjust power usage constant to hardware
---
wled00/FX_fcn.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index 598148fe17..fcfd4a5ecb 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -289,7 +289,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
//I am NOT to be held liable for burned down garages!
//fine tune power estimation constants for your setup
-#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
+#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
void WS2812FX::show(void) {
From 22f5d62baaef36f4e789419597d283372def186a Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 10 Oct 2021 21:32:38 +0200
Subject: [PATCH 06/31] get edge directions from segment number
---
wled00/FX.cpp | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 6a45dd2b02..2e49759ec5 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4278,19 +4278,30 @@ uint16_t WS2812FX::mode_HIVE_rotate(void) {
// edges 0 for first 30 steps
uint8_t diff = 0;
bool dir;
- if (std::find(std::begin(EDGES_0), std::end(EDGES_0), ii) != std::end(EDGES_0)) {
+ if (uint8_t index = std::find(std::begin(EDGES_0), std::end(EDGES_0), ii) != std::end(EDGES_0)) {
diff = prog;
- dir = EDGES_0_DIR[std::find(std::begin(EDGES_0), std::end(EDGES_0), ii)];
- } else if (std::find(std::begin(EDGES_1), std::end(EDGES_1), ii) != std::end(EDGES_1)) {
+ bool dirs[]= EDGES_0_DIR;
+ dir = dirs[index];
+ } else if (uint8_t index = std::find(std::begin(EDGES_1), std::end(EDGES_1), ii) != std::end(EDGES_1)) {
diff = prog - N_LEDS_PER_EDGE;
- } else if (std::find(std::begin(EDGES_2), std::end(EDGES_2), ii) != std::end(EDGES_2)) {
+ bool dirs[]= EDGES_1_DIR;
+ dir = dirs[index];
+ } else if (uint8_t index = std::find(std::begin(EDGES_2), std::end(EDGES_2), ii) != std::end(EDGES_2)) {
diff = prog - 2 * N_LEDS_PER_EDGE;
- } else if (std::find(std::begin(EDGES_3), std::end(EDGES_3), ii) != std::end(EDGES_3)) {
+ bool dirs[]= EDGES_2_DIR;
+ dir = dirs[index];
+ } else if (uint8_t index = std::find(std::begin(EDGES_3), std::end(EDGES_3), ii) != std::end(EDGES_3)) {
diff = prog - 3 * N_LEDS_PER_EDGE;
- } else if (std::find(std::begin(EDGES_4), std::end(EDGES_4), ii) != std::end(EDGES_4)) {
+ bool dirs[]= EDGES_3_DIR;
+ dir = dirs[index];
+ } else if (uint8_t index = std::find(std::begin(EDGES_4), std::end(EDGES_4), ii) != std::end(EDGES_4)) {
diff = prog - 4 * N_LEDS_PER_EDGE;
- } else if (std::find(std::begin(EDGES_5), std::end(EDGES_5), ii) != std::end(EDGES_5)) {
+ bool dirs[]= EDGES_4_DIR;
+ dir = dirs[index];
+ } else if (uint8_t index = std::find(std::begin(EDGES_5), std::end(EDGES_5), ii) != std::end(EDGES_5)) {
diff = prog - 5 * N_LEDS_PER_EDGE;
+ bool dirs[]= EDGES_5_DIR;
+ dir = dirs[index];
} else {
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
setPixelColor(ii + jj, BLACK);
From 8738ac1e6920cfcd56b70beb891b2218465d0790 Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Mon, 11 Oct 2021 03:12:22 +0200
Subject: [PATCH 07/31] made basic rotation effect work
---
wled00/FX.cpp | 93 +++++++++++++++++++++++++++------------------------
1 file changed, 49 insertions(+), 44 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 2e49759ec5..4985ba27d3 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4234,18 +4234,6 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
return FRAMETIME;
}
-#define EDGES_0 \
- { 0, 70, 140 }
-#define EDGES_1 \
- { 10, 80, 150 }
-#define EDGES_2 \
- { 20, 90, 160 }
-#define EDGES_3 \
- { 30, 100, 170 }
-#define EDGES_4 \
- { 40, 110, 180 }
-#define EDGES_5 \
- { 50, 120, 190 }
#define EDGES_0_DIR \
{ true, false, true }
@@ -4268,51 +4256,68 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
* Random Strobing Segments
*/
uint16_t WS2812FX::mode_HIVE_rotate(void) {
-
// TODO: reverse counter-clockwise edges
uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * 6 * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 60 = end)
+ int edges_0[] = {0, 70, 140};
+ int edges_1[] = {10, 80, 150};
+ int edges_2[] = {20, 90, 160};
+ int edges_3[] = {30, 100, 170};
+ int edges_4[] = {40, 110, 180};
+ int edges_5[] = {50, 120, 190};
for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
// edges 0 for first 30 steps
- uint8_t diff = 0;
- bool dir;
- if (uint8_t index = std::find(std::begin(EDGES_0), std::end(EDGES_0), ii) != std::end(EDGES_0)) {
+ int diff = 0;
+ bool dir, isActive = true;
+ int index0 = std::distance(edges_0, std::find(std::begin(edges_0), std::end(edges_0), ii));
+ int index1 = std::distance(edges_1, std::find(std::begin(edges_1), std::end(edges_1), ii));
+ int index2 = std::distance(edges_2, std::find(std::begin(edges_2), std::end(edges_2), ii));
+ int index3 = std::distance(edges_3, std::find(std::begin(edges_3), std::end(edges_3), ii));
+ int index4 = std::distance(edges_4, std::find(std::begin(edges_4), std::end(edges_4), ii));
+ int index5 = std::distance(edges_5, std::find(std::begin(edges_5), std::end(edges_5), ii));
+ if (index0 != sizeof(edges_0) / sizeof(*edges_0)) {
diff = prog;
- bool dirs[]= EDGES_0_DIR;
- dir = dirs[index];
- } else if (uint8_t index = std::find(std::begin(EDGES_1), std::end(EDGES_1), ii) != std::end(EDGES_1)) {
+ bool dirs[] = EDGES_0_DIR;
+ dir = dirs[index0];
+ } else if (index1 != sizeof(edges_1) / sizeof(*edges_1)) {
diff = prog - N_LEDS_PER_EDGE;
- bool dirs[]= EDGES_1_DIR;
- dir = dirs[index];
- } else if (uint8_t index = std::find(std::begin(EDGES_2), std::end(EDGES_2), ii) != std::end(EDGES_2)) {
- diff = prog - 2 * N_LEDS_PER_EDGE;
- bool dirs[]= EDGES_2_DIR;
- dir = dirs[index];
- } else if (uint8_t index = std::find(std::begin(EDGES_3), std::end(EDGES_3), ii) != std::end(EDGES_3)) {
- diff = prog - 3 * N_LEDS_PER_EDGE;
- bool dirs[]= EDGES_3_DIR;
- dir = dirs[index];
- } else if (uint8_t index = std::find(std::begin(EDGES_4), std::end(EDGES_4), ii) != std::end(EDGES_4)) {
- diff = prog - 4 * N_LEDS_PER_EDGE;
- bool dirs[]= EDGES_4_DIR;
- dir = dirs[index];
- } else if (uint8_t index = std::find(std::begin(EDGES_5), std::end(EDGES_5), ii) != std::end(EDGES_5)) {
- diff = prog - 5 * N_LEDS_PER_EDGE;
- bool dirs[]= EDGES_5_DIR;
- dir = dirs[index];
+ bool dirs[] = EDGES_1_DIR;
+ dir = dirs[index1];
+ } else if (index2 != sizeof(edges_2) / sizeof(*edges_2)) {
+ diff = prog - (2 * N_LEDS_PER_EDGE);
+ bool dirs[] = EDGES_2_DIR;
+ dir = dirs[index2];
+ } else if (index3 != sizeof(edges_3) / sizeof(*edges_3)) {
+ diff = prog - (3 * N_LEDS_PER_EDGE);
+ bool dirs[] = EDGES_3_DIR;
+ dir = dirs[index3];
+ } else if (index4 != sizeof(edges_4) / sizeof(*edges_4)) {
+ diff = prog - (4 * N_LEDS_PER_EDGE);
+ bool dirs[] = EDGES_4_DIR;
+ dir = dirs[index4];
+ } else if (index5 != sizeof(edges_5) / sizeof(*edges_5)) {
+ diff = prog - (5 * N_LEDS_PER_EDGE);
+ bool dirs[] = EDGES_5_DIR;
+ dir = dirs[index5];
+ } else {
+ isActive = false;
+ }
+ if (isActive) {
+ for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
+ diff -= 1;
+ diff = diff < 0 ? diff + 6 * N_LEDS_PER_EDGE : diff;
+ float blend = diff;
+ blend *= 255.0f / (N_LEDS_PER_EDGE * 6.0f - 1);
+ // setPixelColor(ii + jj, WHITE);
+ setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 255U));
+ // setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
+ }
} else {
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
setPixelColor(ii + jj, BLACK);
}
- continue;
- }
- for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
- diff -= jj;
- diff %= 6 * N_LEDS_PER_EDGE;
- diff = diff < 0 ? diff + 6 * N_LEDS_PER_EDGE : diff;
- setPixelColor(ii + jj, color_from_palette(((float) diff) / 6 / N_LEDS_PER_EDGE * 256, false, false, 255U));
}
}
From c2ebdb7a4ec3e105640176448bdf0d2e48f02d51 Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Wed, 13 Oct 2021 01:19:51 +0200
Subject: [PATCH 08/31] finished rotating hives effects, added matrix effects
---
wled00/FX.cpp | 201 ++++++++++++++++++++++++++++++++++++++------------
wled00/FX.h | 28 +++++--
2 files changed, 172 insertions(+), 57 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 4985ba27d3..153e09b90e 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4139,7 +4139,10 @@ uint16_t WS2812FX::mode_aurora(void) {
return FRAMETIME;
}
-#define N_LEDS_PER_EDGE 10
+#define N_LEDS_PER_EDGE 10 // if != 10, correct DELTA in next line
+#define HEXAGON_CORRECTION_FACTOR \
+ { 0.89683481, 0.96869989, 1.02748279, 1.06629153, 1.07988476, 1.06629153, 1.02748279, 0.96869989, 0.89683481, 1.0014972 }
+// correction factor assumes a led spacing of 16.67 mm and a total edge length of 170 mm
/*
* New awesome Hive 51 Light Installation effect.
@@ -4234,85 +4237,116 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
return FRAMETIME;
}
-
-#define EDGES_0_DIR \
- { true, false, true }
-#define EDGES_1_DIR \
- { true, false, true }
-#define EDGES_2_DIR \
- { true, false, true }
-#define EDGES_3_DIR \
- { true, false, true }
-#define EDGES_4_DIR \
- { true, false, true }
-#define EDGES_5_DIR \
- { true, false, true }
-
-#define SLOPE 30
-#define ROTATION_COLOR WHITE
+#define EDGES_HEX_0 \
+ { 0, 70, 140 }
+#define EDGES_HEX_1 \
+ { 10, 80, 150 }
+#define EDGES_HEX_2 \
+ { 20, 90, 160 }
+#define EDGES_HEX_3 \
+ { 30, 100, 170 }
+#define EDGES_HEX_4 \
+ { 40, 110, 180 }
+#define EDGES_HEX_5 \
+ { 50, 120, 190 }
+
+#define EDGES_HEX_DIR_0 \
+ { true, true, true }
+#define EDGES_HEX_DIR_1 \
+ { true, true, true }
+#define EDGES_HEX_DIR_2 \
+ { true, true, true }
+#define EDGES_HEX_DIR_3 \
+ { true, true, true }
+#define EDGES_HEX_DIR_4 \
+ { true, true, true }
+#define EDGES_HEX_DIR_5 \
+ { true, true, true }
/*
* New awesome Hive 51 Light Installation effect.
- * Random Strobing Segments
+ * Rotating hives
*/
uint16_t WS2812FX::mode_HIVE_rotate(void) {
+ std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
+ std::vector> edge_dirs = {EDGES_HEX_DIR_0, EDGES_HEX_DIR_1, EDGES_HEX_DIR_2, EDGES_HEX_DIR_3, EDGES_HEX_DIR_4, EDGES_HEX_DIR_5};
+ return WS2812FX::HIVE_rotate(false, edges, edge_dirs);
+}
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Reverse rotating hives
+ */
+uint16_t WS2812FX::mode_HIVE_rotate_rev(void) {
+ std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
+ std::vector> edge_dirs = {EDGES_HEX_DIR_0, EDGES_HEX_DIR_1, EDGES_HEX_DIR_2, EDGES_HEX_DIR_3, EDGES_HEX_DIR_4, EDGES_HEX_DIR_5};
+ return WS2812FX::HIVE_rotate(true, edges, edge_dirs);
+}
+
+uint16_t WS2812FX::HIVE_rotate(bool rev, std::vector> edges, std::vector> edge_dirs) {
// TODO: reverse counter-clockwise edges
uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * 6 * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 60 = end)
- int edges_0[] = {0, 70, 140};
- int edges_1[] = {10, 80, 150};
- int edges_2[] = {20, 90, 160};
- int edges_3[] = {30, 100, 170};
- int edges_4[] = {40, 110, 180};
- int edges_5[] = {50, 120, 190};
+ if (rev) {
+ prog = (6 * N_LEDS_PER_EDGE) - prog;
+ }
for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
// edges 0 for first 30 steps
int diff = 0;
bool dir, isActive = true;
- int index0 = std::distance(edges_0, std::find(std::begin(edges_0), std::end(edges_0), ii));
- int index1 = std::distance(edges_1, std::find(std::begin(edges_1), std::end(edges_1), ii));
- int index2 = std::distance(edges_2, std::find(std::begin(edges_2), std::end(edges_2), ii));
- int index3 = std::distance(edges_3, std::find(std::begin(edges_3), std::end(edges_3), ii));
- int index4 = std::distance(edges_4, std::find(std::begin(edges_4), std::end(edges_4), ii));
- int index5 = std::distance(edges_5, std::find(std::begin(edges_5), std::end(edges_5), ii));
- if (index0 != sizeof(edges_0) / sizeof(*edges_0)) {
+ int index0 = std::find(edges.at(0).begin(), edges.at(0).end(), ii) - edges.at(0).begin();
+ int index1 = std::find(edges.at(1).begin(), edges.at(1).end(), ii) - edges.at(1).begin();
+ int index2 = std::find(edges.at(2).begin(), edges.at(2).end(), ii) - edges.at(2).begin();
+ int index3 = std::find(edges.at(3).begin(), edges.at(3).end(), ii) - edges.at(3).begin();
+ int index4 = std::find(edges.at(4).begin(), edges.at(4).end(), ii) - edges.at(4).begin();
+ int index5 = std::find(edges.at(5).begin(), edges.at(5).end(), ii) - edges.at(5).begin();
+ if (index0 != -1) {
diff = prog;
- bool dirs[] = EDGES_0_DIR;
- dir = dirs[index0];
- } else if (index1 != sizeof(edges_1) / sizeof(*edges_1)) {
+ dir = edge_dirs.at(0).at(index0);
+ } else if (index1 != -1) {
diff = prog - N_LEDS_PER_EDGE;
- bool dirs[] = EDGES_1_DIR;
- dir = dirs[index1];
- } else if (index2 != sizeof(edges_2) / sizeof(*edges_2)) {
+ dir = edge_dirs.at(1).at(index1);
+ } else if (index2 != -1) {
diff = prog - (2 * N_LEDS_PER_EDGE);
- bool dirs[] = EDGES_2_DIR;
- dir = dirs[index2];
- } else if (index3 != sizeof(edges_3) / sizeof(*edges_3)) {
+ dir = edge_dirs.at(2).at(index2);
+ } else if (index3 != -1) {
diff = prog - (3 * N_LEDS_PER_EDGE);
- bool dirs[] = EDGES_3_DIR;
- dir = dirs[index3];
- } else if (index4 != sizeof(edges_4) / sizeof(*edges_4)) {
+ dir = edge_dirs.at(3).at(index3);
+ } else if (index4 != -1) {
diff = prog - (4 * N_LEDS_PER_EDGE);
- bool dirs[] = EDGES_4_DIR;
- dir = dirs[index4];
- } else if (index5 != sizeof(edges_5) / sizeof(*edges_5)) {
+ dir = edge_dirs.at(4).at(index4);
+ } else if (index5 != -1) {
diff = prog - (5 * N_LEDS_PER_EDGE);
- bool dirs[] = EDGES_5_DIR;
- dir = dirs[index5];
+ dir = edge_dirs.at(5).at(index5);
} else {
isActive = false;
}
if (isActive) {
+ if (!dir) {
+ dir -= N_LEDS_PER_EDGE;
+ }
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
- diff -= 1;
+ // only for N_LEDS_PER_EDGE == 10
+ if (dir) {
+ diff--; // modulo 10, to prevent accessing array index out of bounds
+ } else {
+ diff++;
+ }
+ if (rev) {
+ diff = -diff;
+ }
diff = diff < 0 ? diff + 6 * N_LEDS_PER_EDGE : diff;
float blend = diff;
blend *= 255.0f / (N_LEDS_PER_EDGE * 6.0f - 1);
+
// setPixelColor(ii + jj, WHITE);
setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 255U));
// setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
+ if (rev) {
+ diff = -diff;
+ }
}
} else {
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
@@ -4323,3 +4357,72 @@ uint16_t WS2812FX::mode_HIVE_rotate(void) {
return FRAMETIME;
}
+
+/*
+ * Helper function for displaying predefined frames
+ * frame_size = 0 auto-detects the sze of the frame
+ * frames saved as {r1, g1, b1, r2, g2, b2, ...} or {r1, g1, b1, w1, r2, g2, b2, w2, ...}
+ */
+uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_rgbw = false) {
+ uint8_t channels = is_rgbw ? 4 : 3;
+ frame_size = frame_size == 0 ? sizeof(frame) / sizeof(*frame) / channels : frame_size;
+ for (uint16_t ii = 0; ii < channels * MIN(SEGLEN, frame_size); ii += channels) {
+ if (is_rgbw) {
+ setPixelColor(ii, frame[ii], frame[ii + 1], frame[ii + 2], frame[ii + 3]);
+ } else {
+ setPixelColor(ii, frame[ii], frame[ii + 1], frame[ii + 2], 255U);
+ }
+ }
+ if (SEGLEN > frame_size) {
+ for (uint16_t ii = frame_size; ii < SEGLEN; ii++) {
+ setPixelColor(ii, BLACK);
+ }
+ }
+ return FRAMETIME;
+}
+
+#define EDGES_COL_0 \
+ { 0, 70, 140 }
+#define EDGES_COL_1 \
+ { 10, 80, 150 }
+#define EDGES_COL_2 \
+ { 20, 90, 160 }
+#define EDGES_COL_3 \
+ { 30, 100, 170 }
+#define EDGES_COL_4 \
+ { 40, 110, 180 }
+#define EDGES_COL_5 \
+ { 50, 120, 190 }
+
+#define EDGES_COL_DIR_0 \
+ { true, true, true }
+#define EDGES_COL_DIR_1 \
+ { true, true, true }
+#define EDGES_COL_DIR_2 \
+ { true, true, true }
+#define EDGES_COL_DIR_3 \
+ { true, true, true }
+#define EDGES_COL_DIR_4 \
+ { true, true, true }
+#define EDGES_COL_DIR_5 \
+ { true, true, true }
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Matrix style descending lights
+ */
+uint16_t WS2812FX::mode_HIVE_matrix(void) {
+ std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5};
+ return WS2812FX::HIVE_rotate(false, edges, edge_dirs);
+}
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Matrix style ascending lights
+ */
+uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
+ std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5};
+ return WS2812FX::HIVE_rotate(true, edges, edge_dirs);
+}
\ No newline at end of file
diff --git a/wled00/FX.h b/wled00/FX.h
index 33b82e22ce..40d669f210 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -116,7 +116,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
-#define MODE_COUNT 120
+#define MODE_COUNT 123
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -236,8 +236,11 @@
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
-#define FX_MODE_HIVE_51_STROBE_SEG 118 // custom effect for HIVE
-#define FX_MODE_HIVE_51_ROTATE 119 // custom effect for HIVE
+#define FX_MODE_HIVE_STROBE_SEG 118 // custom effect for HIVE
+#define FX_MODE_HIVE_ROTATE 119 // custom effect for HIVE
+#define FX_MODE_HIVE_ROTATE_REV 120 // custom effect for HIVE
+#define FX_MODE_HIVE_MATRIX 121 // custom effect for HIVE
+#define FX_MODE_HIVE_MATRIX_REV 122 // custom effect for HIVE
class WS2812FX {
@@ -611,8 +614,11 @@ class WS2812FX {
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
- _mode[FX_MODE_HIVE_51_STROBE_SEG] = &WS2812FX::mode_HIVE_strobing_segments; // custom effect for HIVE
- _mode[FX_MODE_HIVE_51_ROTATE] = &WS2812FX::mode_HIVE_rotate; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_STROBE_SEG] = &WS2812FX::mode_HIVE_strobing_segments; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_ROTATE] = &WS2812FX::mode_HIVE_rotate; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_ROTATE_REV] = &WS2812FX::mode_HIVE_rotate_rev; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_MATRIX] = &WS2812FX::mode_HIVE_matrix; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_MATRIX_REV] = &WS2812FX::mode_HIVE_matrix_rev; // custom effect for HIVE
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@@ -834,7 +840,10 @@ class WS2812FX {
mode_tv_simulator(void),
mode_dynamic_smooth(void),
mode_HIVE_strobing_segments(void), // custom effect for HIVE
- mode_HIVE_rotate(void); // custom effect for HIVE
+ mode_HIVE_rotate_rev(void), // custom effect for HIVE
+ mode_HIVE_rotate(void), // custom effect for HIVE
+ mode_HIVE_matrix(void), // custom effect for HIVE
+ mode_HIVE_matrix_rev(void); // custom effect for HIVE
private:
uint32_t crgb_to_col(CRGB fastled);
@@ -876,7 +885,9 @@ class WS2812FX {
tricolor_chase(uint32_t, uint32_t),
twinklefox_base(bool),
spots_base(uint16_t),
- phased_base(uint8_t);
+ phased_base(uint8_t),
+ HIVE_rotate(bool, std::vector>, std::vector>),
+ display_frame(byte *, uint16_t, bool);
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
@@ -927,7 +938,8 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
-"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Hive 51 Strobe","Hive 51 Rotation"
+"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Hive 51 Strobe","Hive 51 Rotation",
+"Hive 51 Rotation Reverse", "Hive 51 Matrix desc.", "Hive 51 Matrix asc."
])=====";
From 815cc3431f769972ae5cc0d6f0112f765037c89b Mon Sep 17 00:00:00 2001
From: Gorian <55580941+G0RIAN@users.noreply.github.com>
Date: Wed, 20 Oct 2021 19:20:37 +0200
Subject: [PATCH 09/31] Updated README
---
readme.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/readme.md b/readme.md
index 506f7de737..716c62680e 100644
--- a/readme.md
+++ b/readme.md
@@ -9,6 +9,17 @@
+
+# WLED on hexagon structures
+This fork of WLED implements further effects designed for hexagon structures (specifically a struture of 3 * 5 hexagons (a total of 60 edges) with an edge length of 10 LEDs (=16.67 cm with a 60 LEDs/m strip). The basic functionality of WLED is still given. Current added effects include:
+- 6 rotating hexagons (color adapts to chosen palette)
+- 6 reverse rotating hexagons (color adapts to chosen palette)
+- randomly strobing edges (does not adapt to the chosen palette, uses white instead)
+- matrix style descending stripes on the 6 "vertical" edges (color adapts to chosen palette)
+- matrix style ascending stripes on the 6 "vertical" edges (color adapts to chosen palette)
+- more to come
+
+Original project description of WLED by Aircoookie below.
# Welcome to my project WLED! ✨
From 2285ed90813a3c7f2476242e4636727edcef2486 Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Wed, 20 Oct 2021 19:26:24 +0200
Subject: [PATCH 10/31] clean Code, make the strobing segments effect use the
color palette
---
readme.md | 2 +-
wled00/FX.cpp | 15 ++++++---------
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/readme.md b/readme.md
index 716c62680e..248e869b99 100644
--- a/readme.md
+++ b/readme.md
@@ -14,7 +14,7 @@
This fork of WLED implements further effects designed for hexagon structures (specifically a struture of 3 * 5 hexagons (a total of 60 edges) with an edge length of 10 LEDs (=16.67 cm with a 60 LEDs/m strip). The basic functionality of WLED is still given. Current added effects include:
- 6 rotating hexagons (color adapts to chosen palette)
- 6 reverse rotating hexagons (color adapts to chosen palette)
-- randomly strobing edges (does not adapt to the chosen palette, uses white instead)
+- randomly strobing edges (color adapts to chosen palette)
- matrix style descending stripes on the 6 "vertical" edges (color adapts to chosen palette)
- matrix style ascending stripes on the 6 "vertical" edges (color adapts to chosen palette)
- more to come
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 153e09b90e..28f7d85a3c 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4183,7 +4183,6 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
}
}
if (!isValidData || SEGENV.step != prog) {
- //if (SEGENV.step == (uint8_t)(prog - 1) || SEGENV.step == 0 || !isValidData) {
// update active segments to next random value
for (uint8_t ii = 0; ii < nActiveEdges; ii++) {
bool duplicates;
@@ -4199,9 +4198,6 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
}
} while (duplicates);
}
- /*} else {
- // this should not happen
- return mode_static();*/
}
// set LED colors
@@ -4218,13 +4214,14 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
uint32_t color = RED;
if (isActiveEdge) {
// set LED colors on active edge to white
- color = WHITE;
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(jj, color_from_palette((float) (jj - ii) / (N_LEDS_PER_EDGE - 1) * 255, false, false, 0));
+ }
} else {
// set LED colors on inactive edge to black
- color = BLACK;
- }
- for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
- setPixelColor(jj, color);
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(jj, BLACK);
+ }
}
ii += N_LEDS_PER_EDGE - 1;
From 233e272741ac1dfc9bfbd2f432bb8d880a2cf3d8 Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Wed, 20 Oct 2021 19:28:39 +0200
Subject: [PATCH 11/31] add icon
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 248e869b99..be50fa1510 100644
--- a/readme.md
+++ b/readme.md
@@ -10,7 +10,7 @@
-# WLED on hexagon structures
+# WLED on hexagon structures ⬡
This fork of WLED implements further effects designed for hexagon structures (specifically a struture of 3 * 5 hexagons (a total of 60 edges) with an edge length of 10 LEDs (=16.67 cm with a 60 LEDs/m strip). The basic functionality of WLED is still given. Current added effects include:
- 6 rotating hexagons (color adapts to chosen palette)
- 6 reverse rotating hexagons (color adapts to chosen palette)
From 56680d64b8b64e91223bb67a59fbff4d0decc9b6 Mon Sep 17 00:00:00 2001
From: Moritz Weixler
Date: Thu, 21 Oct 2021 21:35:47 +0200
Subject: [PATCH 12/31] rename swipe function
---
wled00/FX.cpp | 11 +++++------
wled00/FX.h | 2 +-
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 28f7d85a3c..84e52e788f 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4267,7 +4267,7 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
uint16_t WS2812FX::mode_HIVE_rotate(void) {
std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
std::vector> edge_dirs = {EDGES_HEX_DIR_0, EDGES_HEX_DIR_1, EDGES_HEX_DIR_2, EDGES_HEX_DIR_3, EDGES_HEX_DIR_4, EDGES_HEX_DIR_5};
- return WS2812FX::HIVE_rotate(false, edges, edge_dirs);
+ return WS2812FX::HIVE_segment_swipe(false, edges, edge_dirs);
}
/*
@@ -4277,11 +4277,10 @@ uint16_t WS2812FX::mode_HIVE_rotate(void) {
uint16_t WS2812FX::mode_HIVE_rotate_rev(void) {
std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
std::vector> edge_dirs = {EDGES_HEX_DIR_0, EDGES_HEX_DIR_1, EDGES_HEX_DIR_2, EDGES_HEX_DIR_3, EDGES_HEX_DIR_4, EDGES_HEX_DIR_5};
- return WS2812FX::HIVE_rotate(true, edges, edge_dirs);
+ return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
}
-uint16_t WS2812FX::HIVE_rotate(bool rev, std::vector> edges, std::vector> edge_dirs) {
- // TODO: reverse counter-clockwise edges
+uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> edges, std::vector> edge_dirs) {
uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * 6 * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 60 = end)
@@ -4411,7 +4410,7 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
uint16_t WS2812FX::mode_HIVE_matrix(void) {
std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5};
std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5};
- return WS2812FX::HIVE_rotate(false, edges, edge_dirs);
+ return WS2812FX::HIVE_segment_swipe(false, edges, edge_dirs);
}
/*
@@ -4421,5 +4420,5 @@ uint16_t WS2812FX::mode_HIVE_matrix(void) {
uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5};
- return WS2812FX::HIVE_rotate(true, edges, edge_dirs);
+ return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
}
\ No newline at end of file
diff --git a/wled00/FX.h b/wled00/FX.h
index 40d669f210..955e32991a 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -886,7 +886,7 @@ class WS2812FX {
twinklefox_base(bool),
spots_base(uint16_t),
phased_base(uint8_t),
- HIVE_rotate(bool, std::vector>, std::vector>),
+ HIVE_segment_swipe(bool, std::vector>, std::vector>),
display_frame(byte *, uint16_t, bool);
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
From f1e0ece5986ef52c0a3941c54221ed16e8368bb4 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 7 Nov 2021 21:57:48 +0100
Subject: [PATCH 13/31] switch to ESP32
---
platformio.ini | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/platformio.ini b/platformio.ini
index 112f9a972f..cb213f2e2c 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -22,12 +22,12 @@
; default_envs = nodemcuv2
; default_envs = esp01_1m_full
; default_envs = esp07
-default_envs = d1_mini
+; default_envs = d1_mini
; default_envs = heltec_wifi_kit_8
; default_envs = h803wf
; default_envs = d1_mini_debug
; default_envs = d1_mini_ota
-; default_envs = esp32dev
+default_envs = esp32dev
; default_envs = esp8285_4CH_MagicHome
; default_envs = esp8285_4CH_H801
; default_envs = esp8285_5CH_H801
From 4adf2fa48e0b5b1ca2a1a99f503fa1e7cf5b509d Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 7 Nov 2021 21:59:05 +0100
Subject: [PATCH 14/31] define LED indices for effect edges
---
wled00/FX.cpp | 98 +++++++++++++++++++++------------------------------
1 file changed, 41 insertions(+), 57 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 84e52e788f..93f5e6dab8 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4235,30 +4235,30 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
}
#define EDGES_HEX_0 \
- { 0, 70, 140 }
+ { 540, 470, 400, 240, 160, 100 }
#define EDGES_HEX_1 \
- { 10, 80, 150 }
+ { 530, 460, 390, 250, 150, 90 }
#define EDGES_HEX_2 \
- { 20, 90, 160 }
+ { 510, 450, 380, 200, 140, 80 }
#define EDGES_HEX_3 \
- { 30, 100, 170 }
+ { 570, 300, 370, 210, 30, 70 }
#define EDGES_HEX_4 \
- { 40, 110, 180 }
+ { 560, 490, 420, 220, 180, 120 }
#define EDGES_HEX_5 \
- { 50, 120, 190 }
+ { 550, 480, 410, 230, 170, 110 }
#define EDGES_HEX_DIR_0 \
- { true, true, true }
+ { false, false, false, true, false, false }
#define EDGES_HEX_DIR_1 \
- { true, true, true }
+ { false, false, false, true, false, false }
#define EDGES_HEX_DIR_2 \
- { true, true, true }
+ { true , true , false, true, true , false }
#define EDGES_HEX_DIR_3 \
- { true, true, true }
+ { false, false, true , true, false, false }
#define EDGES_HEX_DIR_4 \
- { true, true, true }
+ { false, false, false, true, false, false }
#define EDGES_HEX_DIR_5 \
- { true, true, true }
+ { false, false, false, true, false, false }
/*
* New awesome Hive 51 Light Installation effect.
@@ -4283,40 +4283,24 @@ uint16_t WS2812FX::mode_HIVE_rotate_rev(void) {
uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> edges, std::vector> edge_dirs) {
uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
- uint16_t prog = (perc * 6 * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 60 = end)
+ uint16_t prog = (perc * edges.size() * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 10 * (number of edges per cycle) = end)
if (rev) {
- prog = (6 * N_LEDS_PER_EDGE) - prog;
+ prog = (edges.size() * N_LEDS_PER_EDGE) - prog;
}
for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
- // edges 0 for first 30 steps
int diff = 0;
- bool dir, isActive = true;
- int index0 = std::find(edges.at(0).begin(), edges.at(0).end(), ii) - edges.at(0).begin();
- int index1 = std::find(edges.at(1).begin(), edges.at(1).end(), ii) - edges.at(1).begin();
- int index2 = std::find(edges.at(2).begin(), edges.at(2).end(), ii) - edges.at(2).begin();
- int index3 = std::find(edges.at(3).begin(), edges.at(3).end(), ii) - edges.at(3).begin();
- int index4 = std::find(edges.at(4).begin(), edges.at(4).end(), ii) - edges.at(4).begin();
- int index5 = std::find(edges.at(5).begin(), edges.at(5).end(), ii) - edges.at(5).begin();
- if (index0 != -1) {
- diff = prog;
- dir = edge_dirs.at(0).at(index0);
- } else if (index1 != -1) {
- diff = prog - N_LEDS_PER_EDGE;
- dir = edge_dirs.at(1).at(index1);
- } else if (index2 != -1) {
- diff = prog - (2 * N_LEDS_PER_EDGE);
- dir = edge_dirs.at(2).at(index2);
- } else if (index3 != -1) {
- diff = prog - (3 * N_LEDS_PER_EDGE);
- dir = edge_dirs.at(3).at(index3);
- } else if (index4 != -1) {
- diff = prog - (4 * N_LEDS_PER_EDGE);
- dir = edge_dirs.at(4).at(index4);
- } else if (index5 != -1) {
- diff = prog - (5 * N_LEDS_PER_EDGE);
- dir = edge_dirs.at(5).at(index5);
- } else {
+ bool dir, isActive = NULL;
+ std::vector indices;
+ for (uint8_t jj = 0; jj < edges.size(); jj++) {
+ indices.push_back(std::find(edges.at(jj).begin(), edges.at(jj).end(), ii) - edges.at(jj).begin());
+ if (indices[jj] != -1) {
+ diff = prog - jj * N_LEDS_PER_EDGE;
+ dir = edge_dirs.at(jj).at(indices[jj]);
+ break;
+ }
+ }
+ if (dir == NULL) {
isActive = false;
}
if (isActive) {
@@ -4326,16 +4310,16 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
// only for N_LEDS_PER_EDGE == 10
if (dir) {
- diff--; // modulo 10, to prevent accessing array index out of bounds
+ diff--;
} else {
diff++;
}
if (rev) {
diff = -diff;
}
- diff = diff < 0 ? diff + 6 * N_LEDS_PER_EDGE : diff;
+ diff = diff < 0 ? diff + edges.size() * N_LEDS_PER_EDGE : diff;
float blend = diff;
- blend *= 255.0f / (N_LEDS_PER_EDGE * 6.0f - 1);
+ blend *= 255.0f / (N_LEDS_PER_EDGE * edges.size() - 1);
// setPixelColor(ii + jj, WHITE);
setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 255U));
@@ -4378,30 +4362,30 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
}
#define EDGES_COL_0 \
- { 0, 70, 140 }
+ { 550, 510, 480, 460, 420, 390 }
#define EDGES_COL_1 \
- { 10, 80, 150 }
+ { 560, 520, 490, 450, 430, 380 }
#define EDGES_COL_2 \
- { 20, 90, 160 }
+ { 580, 260, 290, 310, 340, 360 }
#define EDGES_COL_3 \
- { 30, 100, 170 }
+ { 590, 250, 280, 320, 110, 350 }
#define EDGES_COL_4 \
- { 40, 110, 180 }
+ { 230, 200, 170, 150, 120, 90 }
#define EDGES_COL_5 \
- { 50, 120, 190 }
+ { 220, 0, 180, 140, 60, 80 }
#define EDGES_COL_DIR_0 \
- { true, true, true }
+ { true , true , true , false, true , false }
#define EDGES_COL_DIR_1 \
- { true, true, true }
+ { true , true , true , true , true , false }
#define EDGES_COL_DIR_2 \
- { true, true, true }
+ { true , false, false, true , true , false }
#define EDGES_COL_DIR_3 \
- { true, true, true }
+ { true , true , true , true , true , false }
#define EDGES_COL_DIR_4 \
- { true, true, true }
+ { false, true , true , false, true , false }
#define EDGES_COL_DIR_5 \
- { true, true, true }
+ { false, true , true , true , false, false }
/*
* New awesome Hive 51 Light Installation effect.
@@ -4418,7 +4402,7 @@ uint16_t WS2812FX::mode_HIVE_matrix(void) {
* Matrix style ascending lights
*/
uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
- std::vector> edges = {EDGES_HEX_0, EDGES_HEX_1, EDGES_HEX_2, EDGES_HEX_3, EDGES_HEX_4, EDGES_HEX_5};
+ std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5};
std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5};
return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
}
\ No newline at end of file
From 5983ec1b815b2b99413f4870b203c794d0e105b8 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Mon, 8 Nov 2021 17:16:24 +0100
Subject: [PATCH 15/31] fix effects, simplify code, add comments, add exception
handling, change strobe frequency range
---
wled00/FX.cpp | 157 ++++++++++++++++++++++++++++++--------------------
1 file changed, 95 insertions(+), 62 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 93f5e6dab8..632b99f9e5 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4139,21 +4139,32 @@ uint16_t WS2812FX::mode_aurora(void) {
return FRAMETIME;
}
-#define N_LEDS_PER_EDGE 10 // if != 10, correct DELTA in next line
+#define N_LEDS_PER_EDGE 10 // if != 10, correct HEXAGON_CORRECTION_FACTOR in next line
#define HEXAGON_CORRECTION_FACTOR \
{ 0.89683481, 0.96869989, 1.02748279, 1.06629153, 1.07988476, 1.06629153, 1.02748279, 0.96869989, 0.89683481, 1.0014972 }
// correction factor assumes a led spacing of 16.67 mm and a total edge length of 170 mm
+#define MIN_ACTIVE_EDGES 1
+#define MAX_ACTIVE_EDGES SEGLEN / N_LEDS_PER_EDGE
+#define MIN_ACTIVE_EDGES_PERC 0.1
+#define MAX_ACTIVE_EDGES_PERC 0.9
+#define N_REPEATS 10
+#define MAX_RAND_CALLS 100
/*
* New awesome Hive 51 Light Installation effect.
* Random Strobing Segments
*/
uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
- uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150U; // total cycle time in ms
- uint32_t perc = now % cycleTime; // current time step in active cycle in ms
- uint16_t prog = (perc * 10) / cycleTime; // current progress in active cycle (0 = start, 10 = end)
+ uint32_t cycleTime = N_REPEATS * (2 * FRAMETIME + (255 - SEGMENT.speed) * 20); // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint16_t prog = (perc * N_REPEATS) / cycleTime; // current progress in active cycle (0 = start, N_REPEATS = end)
+
+ uint32_t percActiveEdges = MIN_ACTIVE_EDGES_PERC + (float)SEGMENT.intensity * (MAX_ACTIVE_EDGES_PERC - MIN_ACTIVE_EDGES_PERC) / 255.0;
+ percActiveEdges = 0.5;
+ uint16_t nActiveEdges = round((float)MAX_ACTIVE_EDGES * percActiveEdges);
+ nActiveEdges = MIN(MAX(nActiveEdges, MIN_ACTIVE_EDGES), MAX_ACTIVE_EDGES); // assure at least one and at most all edges are active
+ nActiveEdges = 30;
- uint16_t nActiveEdges = SEGLEN / N_LEDS_PER_EDGE / 3U; // set 1/3 of the edges to active
// check if active edges are set
if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
if (!SEGENV.allocateData(nActiveEdges)) {
@@ -4164,13 +4175,14 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
bool isValidData = true;
if (SEGENV.step == prog) {
- // do not update LEDs and use old states saved to SEGENV.data
for (uint8_t ii = 0; ii < nActiveEdges; ii++) {
+ // check if saved edge indices are valid (in range 0 to SEGLEN / N_LEDS_PER_EDGE)
if (SEGENV.data[ii] > SEGLEN / N_LEDS_PER_EDGE - 1) {
isValidData = false;
ii = nActiveEdges;
break;
}
+ // check if saved edge indices are valid (no duplicates)
for (uint8_t jj = 0; jj < nActiveEdges; jj++) {
if (ii != jj) {
if (SEGENV.data[ii] == SEGENV.data[jj]) {
@@ -4182,51 +4194,53 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
}
}
}
+
if (!isValidData || SEGENV.step != prog) {
// update active segments to next random value
for (uint8_t ii = 0; ii < nActiveEdges; ii++) {
bool duplicates;
+ uint8_t randCalls = 0;
do {
- // get new random edge and check if it already on
+ // get new random edge and check if it is already on
duplicates = false;
SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE);
+ randCalls++;
for (uint8_t jj = 0; jj < ii; jj++) {
if (SEGENV.data[ii] == SEGENV.data[jj]) {
duplicates = true;
break;
}
}
+ if (randCalls >= MAX_RAND_CALLS) {
+ // prevent infinite loop (and blocking of loop) by limiting number of calls to random function
+ // this will result in duplicate edge indices in SEGENV.data and therefore less active segments
+ break;
+ }
} while (duplicates);
}
}
// set LED colors
- for (uint16_t ii = 0; ii < SEGLEN; ii++) {
- // set all LEDs to secondary color
- if (ii % N_LEDS_PER_EDGE == 0) {
- bool isActiveEdge = false;
- for (uint8_t jj = 0; jj < sizeof(SEGENV.data); jj++) {
- if (SEGENV.data[jj] == ii / N_LEDS_PER_EDGE) {
- isActiveEdge = true;
- break;
- }
+ for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
+ bool isActiveEdge = false;
+ for (uint8_t jj = 0; jj < sizeof(SEGENV.data); jj++) {
+ if (SEGENV.data[jj] * N_LEDS_PER_EDGE == ii) {
+ isActiveEdge = true;
+ //break;
}
- uint32_t color = RED;
- if (isActiveEdge) {
- // set LED colors on active edge to white
- for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
- setPixelColor(jj, color_from_palette((float) (jj - ii) / (N_LEDS_PER_EDGE - 1) * 255, false, false, 0));
- }
- } else {
- // set LED colors on inactive edge to black
- for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
- setPixelColor(jj, BLACK);
- }
+ }
+ if (isActiveEdge) {
+ // set LED colors on active edge to white
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ // setPixelColor(jj, SEGCOLOR(0));
+ setPixelColor(jj, WHITE);
+ //setPixelColor(jj, color_from_palette((float) (jj - ii) / (N_LEDS_PER_EDGE - 1) * 255, false, false, 0));
}
- ii += N_LEDS_PER_EDGE - 1;
-
} else {
- setPixelColor(ii, RED);
+ // set LED colors on inactive edge to black
+ for (uint16_t jj = ii; jj < ii + N_LEDS_PER_EDGE; jj++) {
+ setPixelColor(jj, BLACK);
+ }
}
}
@@ -4237,11 +4251,11 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
#define EDGES_HEX_0 \
{ 540, 470, 400, 240, 160, 100 }
#define EDGES_HEX_1 \
- { 530, 460, 390, 250, 150, 90 }
+ { 530, 460, 390, 250, 150, 90 }
#define EDGES_HEX_2 \
- { 510, 450, 380, 200, 140, 80 }
+ { 510, 450, 380, 200, 140, 80 }
#define EDGES_HEX_3 \
- { 570, 300, 370, 210, 30, 70 }
+ { 570, 300, 370, 210, 30, 70 }
#define EDGES_HEX_4 \
{ 560, 490, 420, 220, 180, 120 }
#define EDGES_HEX_5 \
@@ -4252,9 +4266,9 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
#define EDGES_HEX_DIR_1 \
{ false, false, false, true, false, false }
#define EDGES_HEX_DIR_2 \
- { true , true , false, true, true , false }
+ { true, true, false, true, true, false }
#define EDGES_HEX_DIR_3 \
- { false, false, true , true, false, false }
+ { false, false, true, true, false, false }
#define EDGES_HEX_DIR_4 \
{ false, false, false, true, false, false }
#define EDGES_HEX_DIR_5 \
@@ -4281,8 +4295,8 @@ uint16_t WS2812FX::mode_HIVE_rotate_rev(void) {
}
uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> edges, std::vector> edge_dirs) {
- uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
- uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * edges.size() * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 10 * (number of edges per cycle) = end)
if (rev) {
prog = (edges.size() * N_LEDS_PER_EDGE) - prog;
@@ -4290,51 +4304,70 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
int diff = 0;
- bool dir, isActive = NULL;
- std::vector indices;
+ bool dir = false;
+ bool isActive = false;
+ std::vector indices{};
+
for (uint8_t jj = 0; jj < edges.size(); jj++) {
- indices.push_back(std::find(edges.at(jj).begin(), edges.at(jj).end(), ii) - edges.at(jj).begin());
- if (indices[jj] != -1) {
- diff = prog - jj * N_LEDS_PER_EDGE;
- dir = edge_dirs.at(jj).at(indices[jj]);
- break;
+ std::vector currentEdge;
+ std::vector currentEdgeDir;
+ try {
+ currentEdge = edges.at(jj);
+ currentEdgeDir = edge_dirs.at(jj);
+ indices.push_back(std::find(currentEdge.begin(), currentEdge.end(), ii) - currentEdge.begin());
+ } catch (const std::out_of_range &ex) {
+ fill(RED);
+ return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
+ }
+ try {
+ if (indices.back() != currentEdge.end() - currentEdge.begin()) {
+ // edge starting at LED jj is part of the primary cycle
+ diff = prog - jj * N_LEDS_PER_EDGE;
+ dir = currentEdgeDir.at(indices.back());
+
+ isActive = true;
+ break;
+ }
+ } catch (const std::out_of_range &ex) {
+ fill(GREEN);
+ return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition
}
}
- if (dir == NULL) {
- isActive = false;
- }
+
if (isActive) {
if (!dir) {
- dir -= N_LEDS_PER_EDGE;
+ diff -= N_LEDS_PER_EDGE;
}
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
// only for N_LEDS_PER_EDGE == 10
if (dir) {
- diff--;
+ diff--;
} else {
diff++;
}
if (rev) {
- diff = -diff;
+ // negate the difference to use the reverse direction
+ diff *= -1;
}
diff = diff < 0 ? diff + edges.size() * N_LEDS_PER_EDGE : diff;
float blend = diff;
blend *= 255.0f / (N_LEDS_PER_EDGE * edges.size() - 1);
// setPixelColor(ii + jj, WHITE);
- setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 255U));
+ setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 0U));
// setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
if (rev) {
- diff = -diff;
+ // reset the diff sign
+ diff *= -1;
}
}
} else {
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
- setPixelColor(ii + jj, BLACK);
+ setPixelColor(ii + jj, BLACK); // TODO: use first color from
}
}
}
-
+
return FRAMETIME;
}
@@ -4370,22 +4403,22 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
#define EDGES_COL_3 \
{ 590, 250, 280, 320, 110, 350 }
#define EDGES_COL_4 \
- { 230, 200, 170, 150, 120, 90 }
+ { 230, 200, 170, 150, 120, 90 }
#define EDGES_COL_5 \
- { 220, 0, 180, 140, 60, 80 }
+ { 220, 0, 180, 140, 60, 80 }
#define EDGES_COL_DIR_0 \
- { true , true , true , false, true , false }
+ { true, true, true, false, true, false }
#define EDGES_COL_DIR_1 \
- { true , true , true , true , true , false }
+ { true, true, true, true, true, false }
#define EDGES_COL_DIR_2 \
- { true , false, false, true , true , false }
+ { true, false, false, true, true, false }
#define EDGES_COL_DIR_3 \
- { true , true , true , true , true , false }
+ { true, true, true, true, true, false }
#define EDGES_COL_DIR_4 \
- { false, true , true , false, true , false }
+ { false, true, true, false, true, false }
#define EDGES_COL_DIR_5 \
- { false, true , true , true , false, false }
+ { false, true, true, true, false, false }
/*
* New awesome Hive 51 Light Installation effect.
From 59f699491c04304f5b3f776505e7b2fd85bb5a79 Mon Sep 17 00:00:00 2001
From: Jonazzzzz
Date: Sun, 14 Nov 2021 22:36:02 +0100
Subject: [PATCH 16/31] fix active edges count per slider, fix skipping LED,
optimize reversing effects
---
wled00/FX.cpp | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 632b99f9e5..2c3de9834e 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4159,11 +4159,9 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * N_REPEATS) / cycleTime; // current progress in active cycle (0 = start, N_REPEATS = end)
- uint32_t percActiveEdges = MIN_ACTIVE_EDGES_PERC + (float)SEGMENT.intensity * (MAX_ACTIVE_EDGES_PERC - MIN_ACTIVE_EDGES_PERC) / 255.0;
- percActiveEdges = 0.5;
+ float percActiveEdges = MIN_ACTIVE_EDGES_PERC + (float)SEGMENT.intensity * (MAX_ACTIVE_EDGES_PERC - MIN_ACTIVE_EDGES_PERC) / 255.0;
uint16_t nActiveEdges = round((float)MAX_ACTIVE_EDGES * percActiveEdges);
nActiveEdges = MIN(MAX(nActiveEdges, MIN_ACTIVE_EDGES), MAX_ACTIVE_EDGES); // assure at least one and at most all edges are active
- nActiveEdges = 30;
// check if active edges are set
if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
@@ -4295,11 +4293,11 @@ uint16_t WS2812FX::mode_HIVE_rotate_rev(void) {
}
uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> edges, std::vector> edge_dirs) {
- uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 150; // total cycle time in ms
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 100; // total cycle time in ms
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
- uint16_t prog = (perc * edges.size() * N_LEDS_PER_EDGE) / cycleTime; // current progress in active cycle (0 = start, 10 * (number of edges per cycle) = end)
+ uint16_t prog = (perc * (edges.size() * N_LEDS_PER_EDGE + 1)) / cycleTime; // current progress in active cycle (0 = start, 10 * (number of edges per cycle) = end)
if (rev) {
- prog = (edges.size() * N_LEDS_PER_EDGE) - prog;
+ prog = (edges.size() * N_LEDS_PER_EDGE + 1) - prog;
}
for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
@@ -4338,6 +4336,10 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
if (!dir) {
diff -= N_LEDS_PER_EDGE;
}
+ if (rev) {
+ // negate the difference to use the reverse direction
+ diff *= -1;
+ }
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
// only for N_LEDS_PER_EDGE == 10
if (dir) {
@@ -4345,25 +4347,21 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
} else {
diff++;
}
- if (rev) {
- // negate the difference to use the reverse direction
- diff *= -1;
- }
diff = diff < 0 ? diff + edges.size() * N_LEDS_PER_EDGE : diff;
float blend = diff;
blend *= 255.0f / (N_LEDS_PER_EDGE * edges.size() - 1);
// setPixelColor(ii + jj, WHITE);
setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 0U));
- // setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
- if (rev) {
- // reset the diff sign
- diff *= -1;
- }
+ // setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
+ }
+ if (rev) {
+ // reset the diff sign
+ diff *= -1;
}
} else {
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
- setPixelColor(ii + jj, BLACK); // TODO: use first color from
+ setPixelColor(ii + jj, BLACK); // TODO: use first color from palette
}
}
}
From 7642b2ddc54207fd94874c7213a61ec6eafb9e01 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 14 Nov 2021 23:07:32 +0100
Subject: [PATCH 17/31] add 'hex_' prefix to binaries
---
pio-scripts/output_bins.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py
index 01223e93d5..6d63424751 100644
--- a/pio-scripts/output_bins.py
+++ b/pio-scripts/output_bins.py
@@ -35,7 +35,7 @@ def bin_rename_copy(source, target, env):
if release_name:
_create_dirs(["release"])
version = _get_cpp_define_value(env, "WLED_VERSION")
- release_file = "{}release{}WLED_{}_{}.bin".format(OUTPUT_DIR, os.path.sep, version, release_name)
+ release_file = "{}release{}WLED_hex_{}_{}.bin".format(OUTPUT_DIR, os.path.sep, version, release_name)
shutil.copy(str(target[0]), release_file)
# check if new target files exist and remove if necessary
From 73db7ba7a5d1f909a14c8161107caf4641172998 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 14 Nov 2021 23:12:08 +0100
Subject: [PATCH 18/31] change repo url to fork
---
package.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/package.json b/package.json
index be29449fbf..57fd3b8d8c 100644
--- a/package.json
+++ b/package.json
@@ -13,14 +13,14 @@
},
"repository": {
"type": "git",
- "url": "git+https://github.com/Aircoookie/WLED.git"
+ "url": "git+https://github.com/G0RIAN/WLED.git"
},
"author": "",
"license": "ISC",
"bugs": {
- "url": "https://github.com/Aircoookie/WLED/issues"
+ "url": "https://github.com/G0RIAN/WLED/issues"
},
- "homepage": "https://github.com/Aircoookie/WLED#readme",
+ "homepage": "https://github.com/G0RIAN/WLED#readme",
"dependencies": {
"clean-css": "^4.2.3",
"html-minifier-terser": "^5.1.1",
From 33c8ce68002f4ae3049d63d79c66d803ad8125d3 Mon Sep 17 00:00:00 2001
From: Jonazzzzzz
Date: Sun, 14 Nov 2021 23:40:47 +0100
Subject: [PATCH 19/31] Added wave effect
---
wled00/FX.cpp | 9 +++++++++
wled00/FX.h | 2 ++
2 files changed, 11 insertions(+)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 2c3de9834e..dd33cca42a 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4436,4 +4436,13 @@ uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5};
std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5};
return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
+}
+
+/*
+* New awesome Hive 51 Light Installation effect.
+* Wave Left-Right
+*/
+uint16_t WS2812FX::mode_HIVE_wave(void) {
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 100;
+ return FRAMETIME;
}
\ No newline at end of file
diff --git a/wled00/FX.h b/wled00/FX.h
index 955e32991a..9768f1db98 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -241,6 +241,7 @@
#define FX_MODE_HIVE_ROTATE_REV 120 // custom effect for HIVE
#define FX_MODE_HIVE_MATRIX 121 // custom effect for HIVE
#define FX_MODE_HIVE_MATRIX_REV 122 // custom effect for HIVE
+#define FX_MODE_HIVE_WAVE 123 // custom effect for HIVE
class WS2812FX {
@@ -619,6 +620,7 @@ class WS2812FX {
_mode[FX_MODE_HIVE_ROTATE_REV] = &WS2812FX::mode_HIVE_rotate_rev; // custom effect for HIVE
_mode[FX_MODE_HIVE_MATRIX] = &WS2812FX::mode_HIVE_matrix; // custom effect for HIVE
_mode[FX_MODE_HIVE_MATRIX_REV] = &WS2812FX::mode_HIVE_matrix_rev; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_WAVE] = &WS2812FX::mode_HIVE_wave; //custom effect for HIVE
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
From 43236247acaee01e3d609662df163ec265b698fd Mon Sep 17 00:00:00 2001
From: G0rian
Date: Mon, 15 Nov 2021 01:11:37 +0100
Subject: [PATCH 20/31] remove redundant memory allocation check, fix: use
correct edge count from intensity slider, revert dumb "fix"
---
wled00/FX.cpp | 35 +++++++++++++++++------------------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 2c3de9834e..d6007b2449 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4160,15 +4160,12 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
uint16_t prog = (perc * N_REPEATS) / cycleTime; // current progress in active cycle (0 = start, N_REPEATS = end)
float percActiveEdges = MIN_ACTIVE_EDGES_PERC + (float)SEGMENT.intensity * (MAX_ACTIVE_EDGES_PERC - MIN_ACTIVE_EDGES_PERC) / 255.0;
- uint16_t nActiveEdges = round((float)MAX_ACTIVE_EDGES * percActiveEdges);
+ uint16_t nActiveEdges = roundf((float)MAX_ACTIVE_EDGES * percActiveEdges);
nActiveEdges = MIN(MAX(nActiveEdges, MIN_ACTIVE_EDGES), MAX_ACTIVE_EDGES); // assure at least one and at most all edges are active
- // check if active edges are set
- if (!SEGENV.data || sizeof(SEGENV.data) != nActiveEdges) {
- if (!SEGENV.allocateData(nActiveEdges)) {
- // return static effect if memory cannot be allocated
- return mode_static();
- }
+ if (!SEGENV.allocateData(nActiveEdges)) {
+ // return static effect if memory cannot be allocated
+ return mode_static();
}
bool isValidData = true;
@@ -4201,7 +4198,7 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
do {
// get new random edge and check if it is already on
duplicates = false;
- SEGENV.data[ii] = random8(0, SEGLEN / N_LEDS_PER_EDGE);
+ SEGENV.data[ii] = (byte) random8(0, (float)SEGLEN / N_LEDS_PER_EDGE - 1);
randCalls++;
for (uint8_t jj = 0; jj < ii; jj++) {
if (SEGENV.data[ii] == SEGENV.data[jj]) {
@@ -4212,6 +4209,7 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
if (randCalls >= MAX_RAND_CALLS) {
// prevent infinite loop (and blocking of loop) by limiting number of calls to random function
// this will result in duplicate edge indices in SEGENV.data and therefore less active segments
+ SEGENV.data[ii] = SEGLEN / N_LEDS_PER_EDGE + 1;
break;
}
} while (duplicates);
@@ -4221,10 +4219,10 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
// set LED colors
for (uint16_t ii = 0; ii < SEGLEN; ii += N_LEDS_PER_EDGE) {
bool isActiveEdge = false;
- for (uint8_t jj = 0; jj < sizeof(SEGENV.data); jj++) {
+ for (uint8_t jj = 0; jj < nActiveEdges; jj++) {
if (SEGENV.data[jj] * N_LEDS_PER_EDGE == ii) {
isActiveEdge = true;
- //break;
+ break;
}
}
if (isActiveEdge) {
@@ -4336,10 +4334,7 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
if (!dir) {
diff -= N_LEDS_PER_EDGE;
}
- if (rev) {
- // negate the difference to use the reverse direction
- diff *= -1;
- }
+
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
// only for N_LEDS_PER_EDGE == 10
if (dir) {
@@ -4347,6 +4342,10 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
} else {
diff++;
}
+ if (rev) {
+ // negate the difference to use the reverse direction
+ diff *= -1;
+ }
diff = diff < 0 ? diff + edges.size() * N_LEDS_PER_EDGE : diff;
float blend = diff;
blend *= 255.0f / (N_LEDS_PER_EDGE * edges.size() - 1);
@@ -4354,10 +4353,10 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
// setPixelColor(ii + jj, WHITE);
setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 0U));
// setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
- }
- if (rev) {
- // reset the diff sign
- diff *= -1;
+ if (rev) {
+ // reset the diff sign
+ diff *= -1;
+ }
}
} else {
for (uint8_t jj = 0; jj < N_LEDS_PER_EDGE; jj++) {
From 5c769b3586a156ce3df5b80955112f00ff44520d Mon Sep 17 00:00:00 2001
From: G0rian
Date: Mon, 15 Nov 2021 01:14:26 +0100
Subject: [PATCH 21/31] add missing function declaration for HIVE wave effect
---
wled00/FX.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/wled00/FX.h b/wled00/FX.h
index 9768f1db98..2fc9d0ba8d 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -845,7 +845,8 @@ class WS2812FX {
mode_HIVE_rotate_rev(void), // custom effect for HIVE
mode_HIVE_rotate(void), // custom effect for HIVE
mode_HIVE_matrix(void), // custom effect for HIVE
- mode_HIVE_matrix_rev(void); // custom effect for HIVE
+ mode_HIVE_matrix_rev(void), // custom effect for HIVE
+ mode_HIVE_wave(void); // custom effect for HIVE
private:
uint32_t crgb_to_col(CRGB fastled);
From 6cecd228011f499aa2ceba61fab00909ba69a35e Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 12 Dec 2021 17:05:07 +0100
Subject: [PATCH 22/31] reduced strobing interval
---
wled00/FX.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index ba7e58f52e..c0adeee66e 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4155,7 +4155,7 @@ uint16_t WS2812FX::mode_aurora(void) {
* Random Strobing Segments
*/
uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
- uint32_t cycleTime = N_REPEATS * (2 * FRAMETIME + (255 - SEGMENT.speed) * 20); // total cycle time in ms
+ uint32_t cycleTime = N_REPEATS * (FRAMETIME + (255 - SEGMENT.speed) * 10); // total cycle time in ms
uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * N_REPEATS) / cycleTime; // current progress in active cycle (0 = start, N_REPEATS = end)
@@ -4198,7 +4198,7 @@ uint16_t WS2812FX::mode_HIVE_strobing_segments(void) {
do {
// get new random edge and check if it is already on
duplicates = false;
- SEGENV.data[ii] = (byte) random8(0, (float)SEGLEN / N_LEDS_PER_EDGE - 1);
+ SEGENV.data[ii] = (byte)random8(0, (float)SEGLEN / N_LEDS_PER_EDGE - 1);
randCalls++;
for (uint8_t jj = 0; jj < ii; jj++) {
if (SEGENV.data[ii] == SEGENV.data[jj]) {
@@ -4291,8 +4291,8 @@ uint16_t WS2812FX::mode_HIVE_rotate_rev(void) {
}
uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> edges, std::vector> edge_dirs) {
- uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 100; // total cycle time in ms
- uint32_t perc = now % cycleTime; // current time step in active cycle in ms
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 100; // total cycle time in ms
+ uint32_t perc = now % cycleTime; // current time step in active cycle in ms
uint16_t prog = (perc * (edges.size() * N_LEDS_PER_EDGE + 1)) / cycleTime; // current progress in active cycle (0 = start, 10 * (number of edges per cycle) = end)
if (rev) {
prog = (edges.size() * N_LEDS_PER_EDGE + 1) - prog;
@@ -4352,7 +4352,7 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
// setPixelColor(ii + jj, WHITE);
setPixelColor(ii + jj, color_from_palette(255U - blend, false, false, 0U));
- // setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
+ // setPixelColor(ii + jj, color_blend(BLACK, WHITE, 255U - blend, false);
if (rev) {
// reset the diff sign
diff *= -1;
@@ -4364,7 +4364,7 @@ uint16_t WS2812FX::HIVE_segment_swipe(bool rev, std::vector> ed
}
}
}
-
+
return FRAMETIME;
}
@@ -4442,6 +4442,6 @@ uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
* Wave Left-Right
*/
uint16_t WS2812FX::mode_HIVE_wave(void) {
- uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 100;
+ uint32_t cycleTime = 250 + (255 - SEGMENT.speed) * 100;
return FRAMETIME;
}
\ No newline at end of file
From 5e3d67e99d9233004afdced89dbea40876176420 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 12 Dec 2021 17:06:42 +0100
Subject: [PATCH 23/31] allow the compiler to use exceptions
---
platformio.ini | 3 +++
1 file changed, 3 insertions(+)
diff --git a/platformio.ini b/platformio.ini
index cb213f2e2c..ed52241157 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -113,8 +113,11 @@ build_flags =
-D DECODE_LG=true
-DWLED_USE_MY_CONFIG
; -D USERMOD_SENSORSTOMQTT
+ -fexceptions
+
build_unflags =
+ -fno-exceptions
# enables all features for travis CI
build_flags_all_features =
From 812386919be9fd6bf784c86769332e3c0abdc05f Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 12 Dec 2021 22:33:31 +0100
Subject: [PATCH 24/31] added full matrix effects
---
wled00/FX.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
wled00/FX.h | 6 ++++++
2 files changed, 56 insertions(+)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index c0adeee66e..21aaa92409 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4404,6 +4404,21 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
#define EDGES_COL_5 \
{ 220, 0, 180, 140, 60, 80 }
+#define EDGES_COL_0_FULL \
+ { 550, 530, 480, 460, 410, 390 }
+#define EDGES_COL_1_FULL \
+ { 560, 510, 490, 450, 420, 380 }
+#define EDGES_COL_2_FULL \
+ { 580, 520, 290, 310, 430, 360 }
+#define EDGES_COL_3_FULL \
+ { 590, 260, 280, 320, 340, 350 }
+#define EDGES_COL_4_FULL \
+ { 230, 250, 170, 150, 110, 90 }
+#define EDGES_COL_5_FULL \
+ { 220, 200, 180, 140, 120, 80 }
+#define EDGES_COL_6_FULL \
+ { -1, 0, 20, 40, 60, -1 }
+
#define EDGES_COL_DIR_0 \
{ true, true, true, false, true, false }
#define EDGES_COL_DIR_1 \
@@ -4417,6 +4432,21 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
#define EDGES_COL_DIR_5 \
{ false, true, true, true, false, false }
+#define EDGES_COL_DIR_0_FULL \
+ { true, false, true, false, true, false }
+#define EDGES_COL_DIR_1_FULL \
+ { true, true, true, true, true, false }
+#define EDGES_COL_DIR_2_FULL \
+ { true, true, false, true, true, false }
+#define EDGES_COL_DIR_3_FULL \
+ { true, false, true, true, true, false }
+#define EDGES_COL_DIR_4_FULL \
+ { false, true, true, false, true, false }
+#define EDGES_COL_DIR_5_FULL \
+ { false, true, true, true, true, false }
+#define EDGES_COL_DIR_6_FULL \
+ { true, true, false, false, false, true }
+
/*
* New awesome Hive 51 Light Installation effect.
* Matrix style descending lights
@@ -4437,6 +4467,26 @@ uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
}
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Matrix style descending lights
+ */
+uint16_t WS2812FX::mode_HIVE_matrix_full(void) {
+ std::vector> edges = {EDGES_COL_0_FULL, EDGES_COL_1_FULL, EDGES_COL_2_FULL, EDGES_COL_3_FULL, EDGES_COL_4_FULL, EDGES_COL_5_FULL, EDGES_COL_6_FULL};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0_FULL, EDGES_COL_DIR_1_FULL, EDGES_COL_DIR_2_FULL, EDGES_COL_DIR_3_FULL, EDGES_COL_DIR_4_FULL, EDGES_COL_DIR_5_FULL, EDGES_COL_DIR_6_FULL};
+ return WS2812FX::HIVE_segment_swipe(false, edges, edge_dirs);
+}
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Matrix style ascending lights
+ */
+uint16_t WS2812FX::mode_HIVE_matrix_rev_full(void) {
+ std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5, EDGES_COL_6_FULL};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5, EDGES_COL_DIR_6_FULL};
+ return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
+}
+
/*
* New awesome Hive 51 Light Installation effect.
* Wave Left-Right
diff --git a/wled00/FX.h b/wled00/FX.h
index 2fc9d0ba8d..d8579d87fb 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -242,6 +242,8 @@
#define FX_MODE_HIVE_MATRIX 121 // custom effect for HIVE
#define FX_MODE_HIVE_MATRIX_REV 122 // custom effect for HIVE
#define FX_MODE_HIVE_WAVE 123 // custom effect for HIVE
+#define FX_MODE_HIVE_MATRIX_FULL 124 // custom effect for HIVE
+#define FX_MODE_HIVE_MATRIX_REV_FULL 125 // custom effect for HIVE
class WS2812FX {
@@ -620,6 +622,8 @@ class WS2812FX {
_mode[FX_MODE_HIVE_ROTATE_REV] = &WS2812FX::mode_HIVE_rotate_rev; // custom effect for HIVE
_mode[FX_MODE_HIVE_MATRIX] = &WS2812FX::mode_HIVE_matrix; // custom effect for HIVE
_mode[FX_MODE_HIVE_MATRIX_REV] = &WS2812FX::mode_HIVE_matrix_rev; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_MATRIX_FULL] = &WS2812FX::mode_HIVE_matrix_full; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_MATRIX_REV_FULL] = &WS2812FX::mode_HIVE_matrix_rev_full; // custom effect for HIVE
_mode[FX_MODE_HIVE_WAVE] = &WS2812FX::mode_HIVE_wave; //custom effect for HIVE
_brightness = DEFAULT_BRIGHTNESS;
@@ -846,6 +850,8 @@ class WS2812FX {
mode_HIVE_rotate(void), // custom effect for HIVE
mode_HIVE_matrix(void), // custom effect for HIVE
mode_HIVE_matrix_rev(void), // custom effect for HIVE
+ mode_HIVE_matrix_full(void), // custom effect for HIVE
+ mode_HIVE_matrix_rev_full(void), // custom effect for HIVE
mode_HIVE_wave(void); // custom effect for HIVE
private:
From 27bcd8ecde09e2903a2375883c783067d0119619 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Sun, 12 Dec 2021 22:33:31 +0100
Subject: [PATCH 25/31] added full matrix effects
---
wled00/FX.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
wled00/FX.h | 8 +++++++-
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index c0adeee66e..21aaa92409 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4404,6 +4404,21 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
#define EDGES_COL_5 \
{ 220, 0, 180, 140, 60, 80 }
+#define EDGES_COL_0_FULL \
+ { 550, 530, 480, 460, 410, 390 }
+#define EDGES_COL_1_FULL \
+ { 560, 510, 490, 450, 420, 380 }
+#define EDGES_COL_2_FULL \
+ { 580, 520, 290, 310, 430, 360 }
+#define EDGES_COL_3_FULL \
+ { 590, 260, 280, 320, 340, 350 }
+#define EDGES_COL_4_FULL \
+ { 230, 250, 170, 150, 110, 90 }
+#define EDGES_COL_5_FULL \
+ { 220, 200, 180, 140, 120, 80 }
+#define EDGES_COL_6_FULL \
+ { -1, 0, 20, 40, 60, -1 }
+
#define EDGES_COL_DIR_0 \
{ true, true, true, false, true, false }
#define EDGES_COL_DIR_1 \
@@ -4417,6 +4432,21 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
#define EDGES_COL_DIR_5 \
{ false, true, true, true, false, false }
+#define EDGES_COL_DIR_0_FULL \
+ { true, false, true, false, true, false }
+#define EDGES_COL_DIR_1_FULL \
+ { true, true, true, true, true, false }
+#define EDGES_COL_DIR_2_FULL \
+ { true, true, false, true, true, false }
+#define EDGES_COL_DIR_3_FULL \
+ { true, false, true, true, true, false }
+#define EDGES_COL_DIR_4_FULL \
+ { false, true, true, false, true, false }
+#define EDGES_COL_DIR_5_FULL \
+ { false, true, true, true, true, false }
+#define EDGES_COL_DIR_6_FULL \
+ { true, true, false, false, false, true }
+
/*
* New awesome Hive 51 Light Installation effect.
* Matrix style descending lights
@@ -4437,6 +4467,26 @@ uint16_t WS2812FX::mode_HIVE_matrix_rev(void) {
return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
}
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Matrix style descending lights
+ */
+uint16_t WS2812FX::mode_HIVE_matrix_full(void) {
+ std::vector> edges = {EDGES_COL_0_FULL, EDGES_COL_1_FULL, EDGES_COL_2_FULL, EDGES_COL_3_FULL, EDGES_COL_4_FULL, EDGES_COL_5_FULL, EDGES_COL_6_FULL};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0_FULL, EDGES_COL_DIR_1_FULL, EDGES_COL_DIR_2_FULL, EDGES_COL_DIR_3_FULL, EDGES_COL_DIR_4_FULL, EDGES_COL_DIR_5_FULL, EDGES_COL_DIR_6_FULL};
+ return WS2812FX::HIVE_segment_swipe(false, edges, edge_dirs);
+}
+
+/*
+ * New awesome Hive 51 Light Installation effect.
+ * Matrix style ascending lights
+ */
+uint16_t WS2812FX::mode_HIVE_matrix_rev_full(void) {
+ std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5, EDGES_COL_6_FULL};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5, EDGES_COL_DIR_6_FULL};
+ return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
+}
+
/*
* New awesome Hive 51 Light Installation effect.
* Wave Left-Right
diff --git a/wled00/FX.h b/wled00/FX.h
index 2fc9d0ba8d..178d987e12 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -116,7 +116,7 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
-#define MODE_COUNT 123
+#define MODE_COUNT 126
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -242,6 +242,8 @@
#define FX_MODE_HIVE_MATRIX 121 // custom effect for HIVE
#define FX_MODE_HIVE_MATRIX_REV 122 // custom effect for HIVE
#define FX_MODE_HIVE_WAVE 123 // custom effect for HIVE
+#define FX_MODE_HIVE_MATRIX_FULL 124 // custom effect for HIVE
+#define FX_MODE_HIVE_MATRIX_REV_FULL 125 // custom effect for HIVE
class WS2812FX {
@@ -620,6 +622,8 @@ class WS2812FX {
_mode[FX_MODE_HIVE_ROTATE_REV] = &WS2812FX::mode_HIVE_rotate_rev; // custom effect for HIVE
_mode[FX_MODE_HIVE_MATRIX] = &WS2812FX::mode_HIVE_matrix; // custom effect for HIVE
_mode[FX_MODE_HIVE_MATRIX_REV] = &WS2812FX::mode_HIVE_matrix_rev; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_MATRIX_FULL] = &WS2812FX::mode_HIVE_matrix_full; // custom effect for HIVE
+ _mode[FX_MODE_HIVE_MATRIX_REV_FULL] = &WS2812FX::mode_HIVE_matrix_rev_full; // custom effect for HIVE
_mode[FX_MODE_HIVE_WAVE] = &WS2812FX::mode_HIVE_wave; //custom effect for HIVE
_brightness = DEFAULT_BRIGHTNESS;
@@ -846,6 +850,8 @@ class WS2812FX {
mode_HIVE_rotate(void), // custom effect for HIVE
mode_HIVE_matrix(void), // custom effect for HIVE
mode_HIVE_matrix_rev(void), // custom effect for HIVE
+ mode_HIVE_matrix_full(void), // custom effect for HIVE
+ mode_HIVE_matrix_rev_full(void), // custom effect for HIVE
mode_HIVE_wave(void); // custom effect for HIVE
private:
From 6a053ec48c94762358929c60adb1b7621be895d6 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Mon, 13 Dec 2021 00:55:13 +0100
Subject: [PATCH 26/31] make full matrix swipe use full segments, change
direction of edge 40, add new effects to list
---
wled00/FX.cpp | 4 ++--
wled00/FX.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 21aaa92409..7bee912850 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -4445,7 +4445,7 @@ uint16_t WS2812FX::display_frame(byte *frame, uint16_t frame_size = 0, bool is_r
#define EDGES_COL_DIR_5_FULL \
{ false, true, true, true, true, false }
#define EDGES_COL_DIR_6_FULL \
- { true, true, false, false, false, true }
+ { true, true, false, true, false, true }
/*
* New awesome Hive 51 Light Installation effect.
@@ -4483,7 +4483,7 @@ uint16_t WS2812FX::mode_HIVE_matrix_full(void) {
*/
uint16_t WS2812FX::mode_HIVE_matrix_rev_full(void) {
std::vector> edges = {EDGES_COL_0, EDGES_COL_1, EDGES_COL_2, EDGES_COL_3, EDGES_COL_4, EDGES_COL_5, EDGES_COL_6_FULL};
- std::vector> edge_dirs = {EDGES_COL_DIR_0, EDGES_COL_DIR_1, EDGES_COL_DIR_2, EDGES_COL_DIR_3, EDGES_COL_DIR_4, EDGES_COL_DIR_5, EDGES_COL_DIR_6_FULL};
+ std::vector> edge_dirs = {EDGES_COL_DIR_0_FULL, EDGES_COL_DIR_1_FULL, EDGES_COL_DIR_2_FULL, EDGES_COL_DIR_3_FULL, EDGES_COL_DIR_4_FULL, EDGES_COL_DIR_5_FULL, EDGES_COL_DIR_6_FULL};
return WS2812FX::HIVE_segment_swipe(true, edges, edge_dirs);
}
diff --git a/wled00/FX.h b/wled00/FX.h
index 178d987e12..c261a4990b 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -948,7 +948,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Hive 51 Strobe","Hive 51 Rotation",
-"Hive 51 Rotation Reverse", "Hive 51 Matrix desc.", "Hive 51 Matrix asc."
+"Hive Rotation Reverse", "Hive Matrix desc.", "Hive Matrix asc.", "Hive WAve", "Hive Matrix Full desc.", "Hive Matrix Full asc."
])=====";
From fde87ba6b020ef0a086aa025d716aff31263dc42 Mon Sep 17 00:00:00 2001
From: G0rian
Date: Mon, 13 Dec 2021 01:55:39 +0100
Subject: [PATCH 27/31] added WLED Hive image
---
images/hives.jpg | Bin 0 -> 4029191 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 images/hives.jpg
diff --git a/images/hives.jpg b/images/hives.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cba8682f95d36bea438cbf114b9c36a65b052042
GIT binary patch
literal 4029191
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