| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | WS2812FX.cpp contains all effect methods | ||
| 3 | Harm Aldick - 2016 | ||
| 4 | www.aldick.org | ||
| 5 | |||
| 6 | Copyright (c) 2016 Harm Aldick | ||
| 7 | Licensed under the EUPL v. 1.2 or later | ||
| 8 | Adapted from code originally licensed under the MIT license | ||
| 9 | |||
| 10 | Modified heavily for WLED | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <ctime> | ||
| 14 | |||
| 15 | #include "wled.h" | ||
| 16 | #include "FX.h" | ||
| 17 | #include "fcn_declare.h" | ||
| 18 | |||
| 19 | #if !(defined(WLED_DISABLE_PARTICLESYSTEM2D) && defined(WLED_DISABLE_PARTICLESYSTEM1D)) | ||
| 20 | #include "FXparticleSystem.h" | ||
| 21 | #ifdef ESP8266 | ||
| 22 | #if !defined(WLED_DISABLE_PARTICLESYSTEM2D) && !defined(WLED_DISABLE_PARTICLESYSTEM1D) | ||
| 23 | #error ESP8266 does not support 1D and 2D particle systems simultaneously. Please disable one of them. | ||
| 24 | #endif | ||
| 25 | #endif | ||
| 26 | #else | ||
| 27 | #define WLED_PS_DONT_REPLACE_FX | ||
| 28 | #endif | ||
| 29 | |||
| 30 | ////////////// | ||
| 31 | // DEV INFO // | ||
| 32 | ////////////// | ||
| 33 | /* | ||
| 34 | information for FX metadata strings: https://kno.wled.ge/interfaces/json-api/#effect-metadata | ||
| 35 | |||
| 36 | Audio Reactive: use the following code to pass usermod variables to effect | ||
| 37 | |||
| 38 | uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux1+1); // just in case assignment | ||
| 39 | bool samplePeak = false; | ||
| 40 | float FFT_MajorPeak = 1.0; | ||
| 41 | uint8_t *fftResult = nullptr; | ||
| 42 | float *fftBin = nullptr; | ||
| 43 | um_data_t *um_data = getAudioData(); | ||
| 44 | volumeSmth = *(float*) um_data->u_data[0]; | ||
| 45 | volumeRaw = *(float*) um_data->u_data[1]; | ||
| 46 | fftResult = (uint8_t*) um_data->u_data[2]; | ||
| 47 | samplePeak = *(uint8_t*) um_data->u_data[3]; | ||
| 48 | FFT_MajorPeak = *(float*) um_data->u_data[4]; | ||
| 49 | my_magnitude = *(float*) um_data->u_data[5]; | ||
| 50 | maxVol = (uint8_t*) um_data->u_data[6]; // requires UI element (SEGMENT.customX?), changes source element | ||
| 51 | binNum = (uint8_t*) um_data->u_data[7]; // requires UI element (SEGMENT.customX?), changes source element | ||
| 52 | fftBin = (float*) um_data->u_data[8]; | ||
| 53 | */ | ||
| 54 | |||
| 55 | #define IBN 5100 | ||
| 56 | // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) | ||
| 57 | #define PALETTE_SOLID_WRAP (strip().paletteBlend == 1 || strip().paletteBlend == 3) | ||
| 58 | #define PALETTE_MOVING_WRAP !(strip().paletteBlend == 2 || (strip().paletteBlend == 0 && SEGMENT.speed == 0)) | ||
| 59 | |||
| 60 | #define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16)) | ||
| 61 | |||
| 62 | // a few constants needed for AudioReactive effects | ||
| 63 | // for 22Khz sampling | ||
| 64 | #define MAX_FREQUENCY 11025 // sample frequency / 2 (as per Nyquist criterion) | ||
| 65 | #define MAX_FREQ_LOG10 4.04238f // log10(MAX_FREQUENCY) | ||
| 66 | // for 20Khz sampling | ||
| 67 | //#define MAX_FREQUENCY 10240 | ||
| 68 | //#define MAX_FREQ_LOG10 4.0103f | ||
| 69 | // for 10Khz sampling | ||
| 70 | //#define MAX_FREQUENCY 5120 | ||
| 71 | //#define MAX_FREQ_LOG10 3.71f | ||
| 72 | |||
| 73 | // effect utility functions | ||
| 74 | 15022 | uint8_t sin_gap(uint16_t in) { | |
| 75 |
2/2✓ Branch 0 taken 5514 times.
✓ Branch 1 taken 9508 times.
|
15022 | if (in & 0x100) return 0; |
| 76 | 9508 | return sin8_t(in + 192); // correct phase shift of sine so that it starts and stops at 0 | |
| 77 | } | ||
| 78 | |||
| 79 | 18108 | uint16_t triwave16(uint16_t in) { | |
| 80 |
2/2✓ Branch 0 taken 12405 times.
✓ Branch 1 taken 5703 times.
|
18108 | if (in < 0x8000) return in *2; |
| 81 | 5703 | return 0xFFFF - (in - 0x8000)*2; | |
| 82 | } | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Generates a tristate square wave w/ attac & decay | ||
| 86 | * @param x input value 0-255 | ||
| 87 | * @param pulsewidth 0-127 | ||
| 88 | * @param attdec attack & decay, max. pulsewidth / 2 | ||
| 89 | * @returns signed waveform value | ||
| 90 | */ | ||
| 91 | 23 | int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { | |
| 92 | 23 | int8_t a = 127; | |
| 93 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (x > 127) { |
| 94 | 5 | a = -127; | |
| 95 | 5 | x -= 127; | |
| 96 | } | ||
| 97 | |||
| 98 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (x < attdec) { //inc to max |
| 99 | ✗ | return (int16_t) x * a / attdec; | |
| 100 | } | ||
| 101 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9 times.
|
23 | else if (x < pulsewidth - attdec) { //max |
| 102 | 14 | return a; | |
| 103 | } | ||
| 104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | else if (x < pulsewidth) { //dec to 0 |
| 105 | ✗ | return (int16_t) (pulsewidth - x) * a / attdec; | |
| 106 | } | ||
| 107 | 9 | return 0; | |
| 108 | } | ||
| 109 | |||
| 110 | 1400 | static um_data_t* getAudioData() { | |
| 111 | um_data_t *um_data; | ||
| 112 |
2/4✓ Branch 0 taken 1400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1400 times.
✗ Branch 3 not taken.
|
1400 | if (!UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { |
| 113 | // add support for no audio | ||
| 114 |
3/6✓ Branch 0 taken 1400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1400 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1400 times.
✗ Branch 5 not taken.
|
1400 | um_data = simulateSound(SEGMENT.soundSim); |
| 115 | } | ||
| 116 | 1400 | return um_data; | |
| 117 | } | ||
| 118 | |||
| 119 | // effect functions | ||
| 120 | |||
| 121 | /* | ||
| 122 | * No blinking. Just plain old static light. | ||
| 123 | */ | ||
| 124 | 282 | uint16_t mode_static(void) { | |
| 125 | 282 | SEGMENT.fill(SEGCOLOR(0)); | |
| 126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 282 times.
|
282 | return strip().isOffRefreshRequired() ? FRAMETIME : 350; |
| 127 | } | ||
| 128 | static const char _data_FX_MODE_STATIC[] PROGMEM = "Solid"; | ||
| 129 | |||
| 130 | |||
| 131 | /* | ||
| 132 | * Blink/strobe function | ||
| 133 | * Alternate between color1 and color2 | ||
| 134 | * if(strobe == true) then create a strobe effect | ||
| 135 | */ | ||
| 136 | 221 | uint16_t blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { | |
| 137 | 221 | uint32_t cycleTime = (255 - SEGMENT.speed)*20; | |
| 138 | 221 | uint32_t onTime = FRAMETIME; | |
| 139 |
2/2✓ Branch 0 taken 175 times.
✓ Branch 1 taken 46 times.
|
221 | if (!strobe) onTime += ((cycleTime * SEGMENT.intensity) >> 8); |
| 140 | 221 | cycleTime += FRAMETIME*2; | |
| 141 | 221 | uint32_t it = strip().now / cycleTime; | |
| 142 | 221 | uint32_t rem = strip().now % cycleTime; | |
| 143 | |||
| 144 | 221 | bool on = false; | |
| 145 | 221 | if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief | |
| 146 |
6/6✓ Branch 0 taken 192 times.
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 119 times.
✓ Branch 4 taken 102 times.
✓ Branch 5 taken 119 times.
|
221 | || rem <= onTime) { |
| 147 | 102 | on = true; | |
| 148 | } | ||
| 149 | |||
| 150 | 221 | SEGENV.step = it; //save previous iteration | |
| 151 | |||
| 152 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 119 times.
|
221 | uint32_t color = on ? color1 : color2; |
| 153 |
4/4✓ Branch 0 taken 102 times.
✓ Branch 1 taken 119 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 94 times.
|
221 | if (color == color1 && do_palette) |
| 154 | { | ||
| 155 |
2/2✓ Branch 0 taken 3243 times.
✓ Branch 1 taken 8 times.
|
3251 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 156 |
2/4✓ Branch 0 taken 3243 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3243 times.
|
3243 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 157 | } | ||
| 158 | 221 | } else SEGMENT.fill(color); | |
| 159 | |||
| 160 | 221 | return FRAMETIME; | |
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | /* | ||
| 165 | * Normal blinking. Intensity sets duty cycle. | ||
| 166 | */ | ||
| 167 | ✗ | uint16_t mode_blink(void) { | |
| 168 | ✗ | return blink(SEGCOLOR(0), SEGCOLOR(1), false, true); | |
| 169 | } | ||
| 170 | static const char _data_FX_MODE_BLINK[] PROGMEM = "Blink@!,Duty cycle;!,!;!;01"; | ||
| 171 | |||
| 172 | |||
| 173 | /* | ||
| 174 | * Classic Blink effect. Cycling through the rainbow. | ||
| 175 | */ | ||
| 176 | 175 | uint16_t mode_blink_rainbow(void) { | |
| 177 | 175 | return blink(SEGMENT.color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), false, false); | |
| 178 | } | ||
| 179 | static const char _data_FX_MODE_BLINK_RAINBOW[] PROGMEM = "Blink Rainbow@Frequency,Blink duration;!,!;!;01"; | ||
| 180 | |||
| 181 | |||
| 182 | /* | ||
| 183 | * Classic Strobe effect. | ||
| 184 | */ | ||
| 185 | 23 | uint16_t mode_strobe(void) { | |
| 186 | 23 | return blink(SEGCOLOR(0), SEGCOLOR(1), true, true); | |
| 187 | } | ||
| 188 | static const char _data_FX_MODE_STROBE[] PROGMEM = "Strobe@!;!,!;!;01"; | ||
| 189 | |||
| 190 | |||
| 191 | /* | ||
| 192 | * Classic Strobe effect. Cycling through the rainbow. | ||
| 193 | */ | ||
| 194 | 23 | uint16_t mode_strobe_rainbow(void) { | |
| 195 | 23 | return blink(SEGMENT.color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), true, false); | |
| 196 | } | ||
| 197 | static const char _data_FX_MODE_STROBE_RAINBOW[] PROGMEM = "Strobe Rainbow@!;,!;!;01"; | ||
| 198 | |||
| 199 | |||
| 200 | /* | ||
| 201 | * Color wipe function | ||
| 202 | * LEDs are turned on (color1) in sequence, then turned off (color2) in sequence. | ||
| 203 | * if (bool rev == true) then LEDs are turned off in reverse order | ||
| 204 | */ | ||
| 205 | 92 | uint16_t color_wipe(bool rev, bool useRandomColors) { | |
| 206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | if (SEGLEN <= 1) return mode_static(); |
| 207 | 92 | uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; | |
| 208 | 92 | uint32_t perc = strip().now % cycleTime; | |
| 209 | 92 | unsigned prog = (perc * 65535) / cycleTime; | |
| 210 | 92 | bool back = (prog > 32767); | |
| 211 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 32 times.
|
92 | if (back) { |
| 212 | 60 | prog -= 32767; | |
| 213 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 39 times.
|
60 | if (SEGENV.step == 0) SEGENV.step = 1; |
| 214 | } else { | ||
| 215 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (SEGENV.step == 2) SEGENV.step = 3; //trigger color change |
| 216 | } | ||
| 217 | |||
| 218 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
|
92 | if (useRandomColors) { |
| 219 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
|
46 | if (SEGENV.call == 0) { |
| 220 | 10 | SEGENV.aux0 = hw_random8(); | |
| 221 | 10 | SEGENV.step = 3; | |
| 222 | } | ||
| 223 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
|
46 | if (SEGENV.step == 1) { //if flag set, change to new random color |
| 224 | 7 | SEGENV.aux1 = get_random_wheel_index(SEGENV.aux0); | |
| 225 | 7 | SEGENV.step = 2; | |
| 226 | } | ||
| 227 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
|
46 | if (SEGENV.step == 3) { |
| 228 | 10 | SEGENV.aux0 = get_random_wheel_index(SEGENV.aux1); | |
| 229 | 10 | SEGENV.step = 0; | |
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | 92 | unsigned ledIndex = (prog * SEGLEN) >> 15; | |
| 234 | 92 | uint16_t rem = (prog * SEGLEN) * 2; //mod 0xFFFF by truncating | |
| 235 | 92 | rem /= (SEGMENT.intensity +1); | |
| 236 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 45 times.
|
92 | if (rem > 255) rem = 255; |
| 237 | |||
| 238 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
|
92 | uint32_t col1 = useRandomColors? SEGMENT.color_wheel(SEGENV.aux1) : SEGCOLOR(1); |
| 239 |
2/2✓ Branch 0 taken 30044 times.
✓ Branch 1 taken 92 times.
|
30136 | for (unsigned i = 0; i < SEGLEN; i++) |
| 240 | { | ||
| 241 |
4/4✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 15022 times.
✓ Branch 2 taken 13312 times.
✓ Branch 3 taken 1710 times.
|
30044 | unsigned index = (rev && back)? SEGLEN -1 -i : i; |
| 242 |
4/6✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 15022 times.
✓ Branch 2 taken 15022 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15022 times.
|
30044 | uint32_t col0 = useRandomColors? SEGMENT.color_wheel(SEGENV.aux0) : SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0); |
| 243 | |||
| 244 |
2/2✓ Branch 0 taken 11899 times.
✓ Branch 1 taken 18145 times.
|
30044 | if (i < ledIndex) |
| 245 | { | ||
| 246 |
2/2✓ Branch 0 taken 9913 times.
✓ Branch 1 taken 1986 times.
|
11899 | SEGMENT.setPixelColor(index, back? col1 : col0); |
| 247 | } else | ||
| 248 | { | ||
| 249 |
2/2✓ Branch 0 taken 17187 times.
✓ Branch 1 taken 958 times.
|
18145 | SEGMENT.setPixelColor(index, back? col0 : col1); |
| 250 |
6/6✓ Branch 0 taken 92 times.
✓ Branch 1 taken 18053 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 60 times.
✓ Branch 5 taken 32 times.
|
18145 | if (i == ledIndex) SEGMENT.setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, uint8_t(rem))); |
| 251 | } | ||
| 252 | } | ||
| 253 | 92 | return FRAMETIME; | |
| 254 | } | ||
| 255 | |||
| 256 | |||
| 257 | /* | ||
| 258 | * Lights all LEDs one after another. | ||
| 259 | */ | ||
| 260 | 23 | uint16_t mode_color_wipe(void) { | |
| 261 | 23 | return color_wipe(false, false); | |
| 262 | } | ||
| 263 | static const char _data_FX_MODE_COLOR_WIPE[] PROGMEM = "Wipe@!,!;!,!;!"; | ||
| 264 | |||
| 265 | |||
| 266 | /* | ||
| 267 | * Lights all LEDs one after another. Turns off opposite | ||
| 268 | */ | ||
| 269 | 23 | uint16_t mode_color_sweep(void) { | |
| 270 | 23 | return color_wipe(true, false); | |
| 271 | } | ||
| 272 | static const char _data_FX_MODE_COLOR_SWEEP[] PROGMEM = "Sweep@!,!;!,!;!"; | ||
| 273 | |||
| 274 | |||
| 275 | /* | ||
| 276 | * Turns all LEDs after each other to a random color. | ||
| 277 | * Then starts over with another color. | ||
| 278 | */ | ||
| 279 | 23 | uint16_t mode_color_wipe_random(void) { | |
| 280 | 23 | return color_wipe(false, true); | |
| 281 | } | ||
| 282 | static const char _data_FX_MODE_COLOR_WIPE_RANDOM[] PROGMEM = "Wipe Random@!;;!"; | ||
| 283 | |||
| 284 | |||
| 285 | /* | ||
| 286 | * Random color introduced alternating from start and end of strip(). | ||
| 287 | */ | ||
| 288 | 23 | uint16_t mode_color_sweep_random(void) { | |
| 289 | 23 | return color_wipe(true, true); | |
| 290 | } | ||
| 291 | static const char _data_FX_MODE_COLOR_SWEEP_RANDOM[] PROGMEM = "Sweep Random@!;;!"; | ||
| 292 | |||
| 293 | |||
| 294 | /* | ||
| 295 | * Lights all LEDs up in one random color. Then switches them | ||
| 296 | * to the next random color. | ||
| 297 | */ | ||
| 298 | 23 | uint16_t mode_random_color(void) { | |
| 299 | 23 | uint32_t cycleTime = 200 + (255 - SEGMENT.speed)*50; | |
| 300 | 23 | uint32_t it = strip().now / cycleTime; | |
| 301 | 23 | uint32_t rem = strip().now % cycleTime; | |
| 302 | 23 | unsigned fadedur = (cycleTime * SEGMENT.intensity) >> 8; | |
| 303 | |||
| 304 | 23 | uint32_t fade = 255; | |
| 305 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (fadedur) { |
| 306 | 19 | fade = (rem * 255) / fadedur; | |
| 307 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 13 times.
|
19 | if (fade > 255) fade = 255; |
| 308 | } | ||
| 309 | |||
| 310 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 311 | 5 | SEGENV.aux0 = hw_random8(); | |
| 312 | 5 | SEGENV.step = 2; | |
| 313 | } | ||
| 314 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
|
23 | if (it != SEGENV.step) //new color |
| 315 | { | ||
| 316 | 7 | SEGENV.aux1 = SEGENV.aux0; | |
| 317 | 7 | SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index | |
| 318 | 7 | SEGENV.step = it; | |
| 319 | } | ||
| 320 | |||
| 321 | 23 | SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), uint8_t(fade))); | |
| 322 | 23 | return FRAMETIME; | |
| 323 | } | ||
| 324 | static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01"; | ||
| 325 | |||
| 326 | |||
| 327 | /* | ||
| 328 | * Lights every LED in a random color. Changes all LED at the same time | ||
| 329 | * to new random colors. | ||
| 330 | */ | ||
| 331 | 46 | uint16_t mode_dynamic(void) { | |
| 332 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed |
| 333 | |||
| 334 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
|
46 | if(SEGENV.call == 0) { |
| 335 | //SEGMENT.fill(BLACK); | ||
| 336 |
2/2✓ Branch 0 taken 3414 times.
✓ Branch 1 taken 10 times.
|
3424 | for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = hw_random8(); |
| 337 | } | ||
| 338 | |||
| 339 | 46 | uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15; | |
| 340 | 46 | uint32_t it = strip().now / cycleTime; | |
| 341 |
6/6✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 31 times.
|
46 | if (it != SEGENV.step && SEGMENT.speed != 0) //new color |
| 342 | { | ||
| 343 |
2/2✓ Branch 0 taken 5974 times.
✓ Branch 1 taken 15 times.
|
5989 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 344 |
2/2✓ Branch 0 taken 5056 times.
✓ Branch 1 taken 918 times.
|
5974 | if (hw_random8() <= SEGMENT.intensity) SEGENV.data[i] = hw_random8(); // random color index |
| 345 | } | ||
| 346 | 15 | SEGENV.step = it; | |
| 347 | } | ||
| 348 | |||
| 349 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | if (SEGMENT.check1) { |
| 350 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 351 | 7511 | SEGMENT.blendPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i]), 16); | |
| 352 | } | ||
| 353 | } else { | ||
| 354 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 355 | 7511 | SEGMENT.setPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i])); | |
| 356 | } | ||
| 357 | } | ||
| 358 | 46 | return FRAMETIME; | |
| 359 | } | ||
| 360 | static const char _data_FX_MODE_DYNAMIC[] PROGMEM = "Dynamic@!,!,,,,Smooth;;!"; | ||
| 361 | |||
| 362 | |||
| 363 | /* | ||
| 364 | * effect "Dynamic" with smooth color-fading | ||
| 365 | */ | ||
| 366 | 23 | uint16_t mode_dynamic_smooth(void) { | |
| 367 | 23 | bool old = SEGMENT.check1; | |
| 368 | 23 | SEGMENT.check1 = true; | |
| 369 | 23 | mode_dynamic(); | |
| 370 | 23 | SEGMENT.check1 = old; | |
| 371 | 23 | return FRAMETIME; | |
| 372 | } | ||
| 373 | static const char _data_FX_MODE_DYNAMIC_SMOOTH[] PROGMEM = "Dynamic Smooth@!,!;;!"; | ||
| 374 | |||
| 375 | |||
| 376 | /* | ||
| 377 | * Does the "standby-breathing" of well known i-Devices. | ||
| 378 | */ | ||
| 379 | 23 | uint16_t mode_breath(void) { | |
| 380 | 23 | unsigned var = 0; | |
| 381 | 23 | unsigned counter = (strip().now * ((SEGMENT.speed >> 3) +10)) & 0xFFFFU; | |
| 382 | 23 | counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048 | |
| 383 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6 times.
|
23 | if (counter < 16384) { |
| 384 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 4 times.
|
17 | if (counter > 8192) counter = 8192 - (counter - 8192); |
| 385 | 17 | var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 | |
| 386 | } | ||
| 387 | |||
| 388 | 23 | uint8_t lum = 30 + var; | |
| 389 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 390 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); |
| 391 | } | ||
| 392 | |||
| 393 | 23 | return FRAMETIME; | |
| 394 | } | ||
| 395 | static const char _data_FX_MODE_BREATH[] PROGMEM = "Breathe@!;!,!;!;01"; | ||
| 396 | |||
| 397 | |||
| 398 | /* | ||
| 399 | * Fades the LEDs between two colors | ||
| 400 | */ | ||
| 401 | 23 | uint16_t mode_fade(void) { | |
| 402 | 23 | unsigned counter = (strip().now * ((SEGMENT.speed >> 3) +10)); | |
| 403 | 23 | uint8_t lum = triwave16(counter) >> 8; | |
| 404 | |||
| 405 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 406 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); |
| 407 | } | ||
| 408 | |||
| 409 | 23 | return FRAMETIME; | |
| 410 | } | ||
| 411 | static const char _data_FX_MODE_FADE[] PROGMEM = "Fade@!;!,!;!;01"; | ||
| 412 | |||
| 413 | |||
| 414 | /* | ||
| 415 | * Scan mode parent function | ||
| 416 | */ | ||
| 417 | 46 | uint16_t scan(bool dual) { | |
| 418 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGLEN <= 1) return mode_static(); |
| 419 | 46 | uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; | |
| 420 | 46 | uint32_t perc = strip().now % cycleTime; | |
| 421 | 46 | int prog = (perc * 65535) / cycleTime; | |
| 422 | 46 | int size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9); | |
| 423 | 46 | int ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16; | |
| 424 | |||
| 425 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); |
| 426 | |||
| 427 | 46 | int led_offset = ledIndex - (SEGLEN - size); | |
| 428 | 46 | led_offset = abs(led_offset); | |
| 429 | |||
| 430 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | if (dual) { |
| 431 |
2/2✓ Branch 0 taken 1893 times.
✓ Branch 1 taken 23 times.
|
1916 | for (int j = led_offset; j < led_offset + size; j++) { |
| 432 | 1893 | unsigned i2 = SEGLEN -1 -j; | |
| 433 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 1893 times.
✓ Branch 2 taken 1893 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1893 times.
|
1893 | SEGMENT.setPixelColor(i2, SEGMENT.color_from_palette(i2, true, PALETTE_SOLID_WRAP, (SEGCOLOR(2))? 2:0)); |
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 |
2/2✓ Branch 0 taken 3786 times.
✓ Branch 1 taken 46 times.
|
3832 | for (int j = led_offset; j < led_offset + size; j++) { |
| 438 |
2/4✓ Branch 0 taken 3786 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3786 times.
|
3786 | SEGMENT.setPixelColor(j, SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0)); |
| 439 | } | ||
| 440 | |||
| 441 | 46 | return FRAMETIME; | |
| 442 | } | ||
| 443 | |||
| 444 | |||
| 445 | /* | ||
| 446 | * Runs a single pixel back and forth. | ||
| 447 | */ | ||
| 448 | 23 | uint16_t mode_scan(void) { | |
| 449 | 23 | return scan(false); | |
| 450 | } | ||
| 451 | static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots,,,,,Overlay;!,!,!;!"; | ||
| 452 | |||
| 453 | |||
| 454 | /* | ||
| 455 | * Runs two pixel back and forth in opposite directions. | ||
| 456 | */ | ||
| 457 | 23 | uint16_t mode_dual_scan(void) { | |
| 458 | 23 | return scan(true); | |
| 459 | } | ||
| 460 | static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots,,,,,Overlay;!,!,!;!"; | ||
| 461 | |||
| 462 | |||
| 463 | /* | ||
| 464 | * Cycles all LEDs at once through a rainbow. | ||
| 465 | */ | ||
| 466 | 51 | uint16_t mode_rainbow(void) { | |
| 467 | 51 | unsigned counter = (strip().now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; | |
| 468 | 51 | counter = counter >> 8; | |
| 469 | |||
| 470 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 47 times.
|
51 | if (SEGMENT.intensity < 128){ |
| 471 | 4 | SEGMENT.fill(color_blend(SEGMENT.color_wheel(counter),WHITE,uint8_t(128-SEGMENT.intensity))); | |
| 472 | } else { | ||
| 473 | 47 | SEGMENT.fill(SEGMENT.color_wheel(counter)); | |
| 474 | } | ||
| 475 | |||
| 476 | 51 | return FRAMETIME; | |
| 477 | } | ||
| 478 | static const char _data_FX_MODE_RAINBOW[] PROGMEM = "Colorloop@!,Saturation;;!;01"; | ||
| 479 | |||
| 480 | |||
| 481 | /* | ||
| 482 | * Cycles a rainbow over the entire string of LEDs. | ||
| 483 | */ | ||
| 484 | 228 | uint16_t mode_rainbow_cycle(void) { | |
| 485 | 228 | unsigned counter = (strip().now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; | |
| 486 | 228 | counter = counter >> 8; | |
| 487 | |||
| 488 |
2/2✓ Branch 0 taken 104617 times.
✓ Branch 1 taken 228 times.
|
104845 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 489 | //intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16) | ||
| 490 | 104617 | uint8_t index = (i * (16 << (SEGMENT.intensity /29)) / SEGLEN) + counter; | |
| 491 | 104617 | SEGMENT.setPixelColor(i, SEGMENT.color_wheel(index)); | |
| 492 | } | ||
| 493 | |||
| 494 | 228 | return FRAMETIME; | |
| 495 | } | ||
| 496 | static const char _data_FX_MODE_RAINBOW_CYCLE[] PROGMEM = "Rainbow@!,Size;;!"; | ||
| 497 | |||
| 498 | |||
| 499 | /* | ||
| 500 | * Alternating pixels running function. | ||
| 501 | */ | ||
| 502 | 69 | static uint16_t running(uint32_t color1, uint32_t color2, bool theatre = false) { | |
| 503 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 23 times.
|
69 | int width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window |
| 504 | 69 | uint32_t cycleTime = 50 + (255 - SEGMENT.speed); | |
| 505 | 69 | uint32_t it = strip().now / cycleTime; | |
| 506 | 69 | bool usePalette = color1 == SEGCOLOR(0); | |
| 507 | |||
| 508 |
2/2✓ Branch 0 taken 22533 times.
✓ Branch 1 taken 69 times.
|
22602 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 509 | 22533 | uint32_t col = color2; | |
| 510 |
4/6✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 7511 times.
✓ Branch 2 taken 15022 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15022 times.
|
22533 | if (usePalette) color1 = SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0); |
| 511 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 7511 times.
|
22533 | if (theatre) { |
| 512 |
2/2✓ Branch 0 taken 2228 times.
✓ Branch 1 taken 12794 times.
|
15022 | if ((i % width) == SEGENV.aux0) col = color1; |
| 513 | } else { | ||
| 514 | 7511 | int pos = (i % (width<<1)); | |
| 515 |
7/8✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6937 times.
✓ Branch 3 taken 574 times.
✓ Branch 4 taken 3782 times.
✓ Branch 5 taken 3155 times.
✓ Branch 6 taken 3782 times.
✓ Branch 7 taken 3729 times.
|
7511 | if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1; |
| 516 | } | ||
| 517 | 22533 | SEGMENT.setPixelColor(i,col); | |
| 518 | } | ||
| 519 | |||
| 520 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 34 times.
|
69 | if (it != SEGENV.step) { |
| 521 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 12 times.
|
35 | SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1)); |
| 522 | 35 | SEGENV.step = it; | |
| 523 | } | ||
| 524 | 69 | return FRAMETIME; | |
| 525 | } | ||
| 526 | |||
| 527 | |||
| 528 | /* | ||
| 529 | * Theatre-style crawling lights. | ||
| 530 | * Inspired by the Adafruit examples. | ||
| 531 | */ | ||
| 532 | 23 | uint16_t mode_theater_chase(void) { | |
| 533 | 23 | return running(SEGCOLOR(0), SEGCOLOR(1), true); | |
| 534 | } | ||
| 535 | static const char _data_FX_MODE_THEATER_CHASE[] PROGMEM = "Theater@!,Gap size;!,!;!"; | ||
| 536 | |||
| 537 | |||
| 538 | /* | ||
| 539 | * Theatre-style crawling lights with rainbow effect. | ||
| 540 | * Inspired by the Adafruit examples. | ||
| 541 | */ | ||
| 542 | 23 | uint16_t mode_theater_chase_rainbow(void) { | |
| 543 | 23 | return running(SEGMENT.color_wheel(SEGENV.step), SEGCOLOR(1), true); | |
| 544 | } | ||
| 545 | static const char _data_FX_MODE_THEATER_CHASE_RAINBOW[] PROGMEM = "Theater Rainbow@!,Gap size;,!;!"; | ||
| 546 | |||
| 547 | |||
| 548 | /* | ||
| 549 | * Running lights effect with smooth sine transition base. | ||
| 550 | */ | ||
| 551 | 69 | static uint16_t running_base(bool saw, bool dual=false) { | |
| 552 | 69 | unsigned x_scale = SEGMENT.intensity >> 2; | |
| 553 | 69 | uint32_t counter = (strip().now * SEGMENT.speed) >> 9; | |
| 554 | |||
| 555 |
2/2✓ Branch 0 taken 22533 times.
✓ Branch 1 taken 69 times.
|
22602 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 556 | 22533 | unsigned a = i*x_scale - counter; | |
| 557 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 15022 times.
|
22533 | if (saw) { |
| 558 | 7511 | a &= 0xFF; | |
| 559 |
2/2✓ Branch 0 taken 2366 times.
✓ Branch 1 taken 5145 times.
|
7511 | if (a < 16) |
| 560 | { | ||
| 561 | 2366 | a = 192 + a*8; | |
| 562 | } else { | ||
| 563 | 5145 | a = map(a,16,255,64,192); | |
| 564 | } | ||
| 565 | 7511 | a = 255 - a; | |
| 566 | } | ||
| 567 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 15022 times.
|
22533 | uint8_t s = dual ? sin_gap(a) : sin8_t(a); |
| 568 |
2/4✓ Branch 0 taken 22533 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22533 times.
|
22533 | uint32_t ca = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s); |
| 569 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 15022 times.
|
22533 | if (dual) { |
| 570 | 7511 | unsigned b = (SEGLEN-1-i)*x_scale - counter; | |
| 571 | 7511 | uint8_t t = sin_gap(b); | |
| 572 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | uint32_t cb = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t); |
| 573 | 7511 | ca = color_blend(ca, cb, uint8_t(127)); | |
| 574 | } | ||
| 575 | 22533 | SEGMENT.setPixelColor(i, ca); | |
| 576 | } | ||
| 577 | |||
| 578 | 69 | return FRAMETIME; | |
| 579 | } | ||
| 580 | |||
| 581 | |||
| 582 | /* | ||
| 583 | * Running lights in opposite directions. | ||
| 584 | * Idea: Make the gap width controllable with a third slider in the future | ||
| 585 | */ | ||
| 586 | 23 | uint16_t mode_running_dual(void) { | |
| 587 | 23 | return running_base(false, true); | |
| 588 | } | ||
| 589 | static const char _data_FX_MODE_RUNNING_DUAL[] PROGMEM = "Running Dual@!,Wave width;L,!,R;!"; | ||
| 590 | |||
| 591 | |||
| 592 | /* | ||
| 593 | * Running lights effect with smooth sine transition. | ||
| 594 | */ | ||
| 595 | 23 | uint16_t mode_running_lights(void) { | |
| 596 | 23 | return running_base(false); | |
| 597 | } | ||
| 598 | static const char _data_FX_MODE_RUNNING_LIGHTS[] PROGMEM = "Running@!,Wave width;!,!;!"; | ||
| 599 | |||
| 600 | |||
| 601 | /* | ||
| 602 | * Running lights effect with sawtooth transition. | ||
| 603 | */ | ||
| 604 | 23 | uint16_t mode_saw(void) { | |
| 605 | 23 | return running_base(true); | |
| 606 | } | ||
| 607 | static const char _data_FX_MODE_SAW[] PROGMEM = "Saw@!,Width;!,!;!"; | ||
| 608 | |||
| 609 | |||
| 610 | /* | ||
| 611 | * Blink several LEDs in random colors on, reset, repeat. | ||
| 612 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ | ||
| 613 | */ | ||
| 614 | 23 | uint16_t mode_twinkle(void) { | |
| 615 | 23 | SEGMENT.fade_out(224); | |
| 616 | |||
| 617 | 23 | uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5; | |
| 618 | 23 | uint32_t it = strip().now / cycleTime; | |
| 619 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 15 times.
|
23 | if (it != SEGENV.step) |
| 620 | { | ||
| 621 | 8 | unsigned maxOn = map(SEGMENT.intensity, 0, 255, 1, SEGLEN); // make sure at least one LED is on | |
| 622 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (SEGENV.aux0 >= maxOn) |
| 623 | { | ||
| 624 | ✗ | SEGENV.aux0 = 0; | |
| 625 | ✗ | SEGENV.aux1 = hw_random(); //new seed for our PRNG | |
| 626 | } | ||
| 627 | 8 | SEGENV.aux0++; | |
| 628 | 8 | SEGENV.step = it; | |
| 629 | } | ||
| 630 | |||
| 631 | 23 | unsigned PRNG16 = SEGENV.aux1; | |
| 632 | |||
| 633 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 23 times.
|
52 | for (unsigned i = 0; i < SEGENV.aux0; i++) |
| 634 | { | ||
| 635 | 29 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next 'random' number | |
| 636 | 29 | uint32_t p = (uint32_t)SEGLEN * (uint32_t)PRNG16; | |
| 637 | 29 | unsigned j = p >> 16; | |
| 638 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
|
29 | SEGMENT.setPixelColor(j, SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0)); |
| 639 | } | ||
| 640 | |||
| 641 | 23 | return FRAMETIME; | |
| 642 | } | ||
| 643 | static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0"; //pixels | ||
| 644 | |||
| 645 | |||
| 646 | /* | ||
| 647 | * Dissolve function | ||
| 648 | */ | ||
| 649 | 46 | uint16_t dissolve(uint32_t color) { | |
| 650 | 46 | unsigned dataSize = sizeof(uint32_t) * SEGLEN; | |
| 651 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 652 | 46 | uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | |
| 653 | |||
| 654 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
|
46 | if (SEGENV.call == 0) { |
| 655 |
2/2✓ Branch 0 taken 3414 times.
✓ Branch 1 taken 10 times.
|
3424 | for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = SEGCOLOR(1); |
| 656 | 10 | SEGENV.aux0 = 1; | |
| 657 | } | ||
| 658 | |||
| 659 |
2/2✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 46 times.
|
1086 | for (unsigned j = 0; j <= SEGLEN / 15; j++) { |
| 660 |
2/2✓ Branch 0 taken 512 times.
✓ Branch 1 taken 528 times.
|
1040 | if (hw_random8() <= SEGMENT.intensity) { |
| 661 |
2/2✓ Branch 0 taken 4006 times.
✓ Branch 1 taken 388 times.
|
4394 | for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times |
| 662 | 4006 | unsigned i = hw_random16(SEGLEN); | |
| 663 |
1/2✓ Branch 0 taken 4006 times.
✗ Branch 1 not taken.
|
4006 | if (SEGENV.aux0) { //dissolve to primary/palette |
| 664 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 3882 times.
|
4006 | if (pixels[i] == SEGCOLOR(1)) { |
| 665 |
4/6✓ Branch 0 taken 63 times.
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 63 times.
|
124 | pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color; |
| 666 | 124 | break; //only spawn 1 new pixel per frame per 50 LEDs | |
| 667 | } | ||
| 668 | } else { //dissolve to secondary | ||
| 669 | ✗ | if (pixels[i] != SEGCOLOR(1)) { | |
| 670 | ✗ | pixels[i] = SEGCOLOR(1); | |
| 671 | ✗ | break; | |
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
| 675 | } | ||
| 676 | } | ||
| 677 | // fix for #4401 | ||
| 678 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 46 times.
|
15068 | for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]); |
| 679 | |||
| 680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGENV.step > (255 - SEGMENT.speed) + 15U) { |
| 681 | ✗ | SEGENV.aux0 = !SEGENV.aux0; | |
| 682 | ✗ | SEGENV.step = 0; | |
| 683 | } else { | ||
| 684 | 46 | SEGENV.step++; | |
| 685 | } | ||
| 686 | |||
| 687 | 46 | return FRAMETIME; | |
| 688 | } | ||
| 689 | |||
| 690 | |||
| 691 | /* | ||
| 692 | * Blink several LEDs on and then off | ||
| 693 | */ | ||
| 694 | 23 | uint16_t mode_dissolve(void) { | |
| 695 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | return dissolve(SEGMENT.check1 ? SEGMENT.color_wheel(hw_random8()) : SEGCOLOR(0)); |
| 696 | } | ||
| 697 | static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Dissolve speed,,,,Random;!,!;!"; | ||
| 698 | |||
| 699 | |||
| 700 | /* | ||
| 701 | * Blink several LEDs on and then off in random colors | ||
| 702 | */ | ||
| 703 | 23 | uint16_t mode_dissolve_random(void) { | |
| 704 | 23 | return dissolve(SEGMENT.color_wheel(hw_random8())); | |
| 705 | } | ||
| 706 | static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat speed,Dissolve speed;,!;!"; | ||
| 707 | |||
| 708 | |||
| 709 | /* | ||
| 710 | * Blinks one LED at a time. | ||
| 711 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ | ||
| 712 | */ | ||
| 713 | 23 | uint16_t mode_sparkle(void) { | |
| 714 |
3/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✓ Branch 3 taken 23 times.
|
7534 | if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { |
| 715 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); |
| 716 | } | ||
| 717 | 23 | uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2; | |
| 718 | 23 | uint32_t it = strip().now / cycleTime; | |
| 719 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 13 times.
|
23 | if (it != SEGENV.step) |
| 720 | { | ||
| 721 | 10 | SEGENV.aux0 = hw_random16(SEGLEN); // aux0 stores the random led index | |
| 722 | 10 | SEGENV.step = it; | |
| 723 | } | ||
| 724 | |||
| 725 | 23 | SEGMENT.setPixelColor(SEGENV.aux0, SEGCOLOR(0)); | |
| 726 | 23 | return FRAMETIME; | |
| 727 | } | ||
| 728 | static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!;!;;m12=0"; | ||
| 729 | |||
| 730 | |||
| 731 | /* | ||
| 732 | * Lights all LEDs in the color. Flashes single col 1 pixels randomly. (List name: Sparkle Dark) | ||
| 733 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ | ||
| 734 | */ | ||
| 735 | 23 | uint16_t mode_flash_sparkle(void) { | |
| 736 |
3/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✓ Branch 3 taken 23 times.
|
7534 | if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { |
| 737 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 738 | } | ||
| 739 | |||
| 740 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 12 times.
|
23 | if (strip().now - SEGENV.aux0 > SEGENV.step) { |
| 741 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
|
11 | if(hw_random8((255-SEGMENT.intensity) >> 4) == 0) { |
| 742 | 4 | SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1)); //flash | |
| 743 | } | ||
| 744 | 11 | SEGENV.step = strip().now; | |
| 745 | 11 | SEGENV.aux0 = 255-SEGMENT.speed; | |
| 746 | } | ||
| 747 | 23 | return FRAMETIME; | |
| 748 | } | ||
| 749 | static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!,,,,,Overlay;Bg,Fx;!;;m12=0"; | ||
| 750 | |||
| 751 | |||
| 752 | /* | ||
| 753 | * Like flash sparkle. With more flash. | ||
| 754 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ | ||
| 755 | */ | ||
| 756 | 23 | uint16_t mode_hyper_sparkle(void) { | |
| 757 |
3/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✓ Branch 3 taken 23 times.
|
7534 | if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { |
| 758 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 759 | } | ||
| 760 | |||
| 761 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 12 times.
|
23 | if (strip().now - SEGENV.aux0 > SEGENV.step) { |
| 762 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | if (hw_random8((255-SEGMENT.intensity) >> 4) == 0) { |
| 763 | 5 | int len = max(1, (int)SEGLEN/3); | |
| 764 |
2/2✓ Branch 0 taken 687 times.
✓ Branch 1 taken 5 times.
|
692 | for (int i = 0; i < len; i++) { |
| 765 | 687 | SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1)); | |
| 766 | } | ||
| 767 | } | ||
| 768 | 11 | SEGENV.step = strip().now; | |
| 769 | 11 | SEGENV.aux0 = 255-SEGMENT.speed; | |
| 770 | } | ||
| 771 | 23 | return FRAMETIME; | |
| 772 | } | ||
| 773 | static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!,,,,,Overlay;Bg,Fx;!;;m12=0"; | ||
| 774 | |||
| 775 | |||
| 776 | /* | ||
| 777 | * Strobe effect with different strobe count and pause, controlled by speed. | ||
| 778 | */ | ||
| 779 | 23 | uint16_t mode_multi_strobe(void) { | |
| 780 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 781 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); |
| 782 | } | ||
| 783 | |||
| 784 | 23 | SEGENV.aux0 = 50 + 20*(uint16_t)(255-SEGMENT.speed); | |
| 785 | 23 | unsigned count = 2 * ((SEGMENT.intensity / 10) + 1); | |
| 786 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1 times.
|
23 | if(SEGENV.aux1 < count) { |
| 787 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 13 times.
|
22 | if((SEGENV.aux1 & 1) == 0) { |
| 788 | 9 | SEGMENT.fill(SEGCOLOR(0)); | |
| 789 | 9 | SEGENV.aux0 = 15; | |
| 790 | } else { | ||
| 791 | 13 | SEGENV.aux0 = 50; | |
| 792 | } | ||
| 793 | } | ||
| 794 | |||
| 795 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 7 times.
|
23 | if (strip().now - SEGENV.aux0 > SEGENV.step) { |
| 796 | 16 | SEGENV.aux1++; | |
| 797 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (SEGENV.aux1 > count) SEGENV.aux1 = 0; |
| 798 | 16 | SEGENV.step = strip().now; | |
| 799 | } | ||
| 800 | |||
| 801 | 23 | return FRAMETIME; | |
| 802 | } | ||
| 803 | static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!;01"; | ||
| 804 | |||
| 805 | |||
| 806 | /* | ||
| 807 | * Android loading circle | ||
| 808 | */ | ||
| 809 | 56 | uint16_t mode_android(void) { | |
| 810 | |||
| 811 |
2/2✓ Branch 0 taken 1138 times.
✓ Branch 1 taken 56 times.
|
1194 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 812 |
2/4✓ Branch 0 taken 1138 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1138 times.
|
1138 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); |
| 813 | } | ||
| 814 | |||
| 815 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 43 times.
|
56 | if (SEGENV.aux1 > (SEGMENT.intensity*SEGLEN)/255) |
| 816 | { | ||
| 817 | 13 | SEGENV.aux0 = 1; | |
| 818 | } else | ||
| 819 | { | ||
| 820 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 14 times.
|
43 | if (SEGENV.aux1 < 2) SEGENV.aux0 = 0; |
| 821 | } | ||
| 822 | |||
| 823 | 56 | unsigned a = SEGENV.step & 0xFFFFU; | |
| 824 | |||
| 825 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 17 times.
|
56 | if (SEGENV.aux0 == 0) |
| 826 | { | ||
| 827 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 27 times.
|
39 | if (SEGENV.call %3 == 1) {a++;} |
| 828 | 27 | else {SEGENV.aux1++;} | |
| 829 | } else | ||
| 830 | { | ||
| 831 | 17 | a++; | |
| 832 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
|
17 | if (SEGENV.call %3 != 1) SEGENV.aux1--; |
| 833 | } | ||
| 834 | |||
| 835 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 52 times.
|
56 | if (a >= SEGLEN) a = 0; |
| 836 | |||
| 837 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 11 times.
|
56 | if (a + SEGENV.aux1 < SEGLEN) |
| 838 | { | ||
| 839 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 45 times.
|
119 | for (unsigned i = a; i < a+SEGENV.aux1; i++) { |
| 840 | 74 | SEGMENT.setPixelColor(i, SEGCOLOR(0)); | |
| 841 | } | ||
| 842 | } else | ||
| 843 | { | ||
| 844 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 11 times.
|
29 | for (unsigned i = a; i < SEGLEN; i++) { |
| 845 | 18 | SEGMENT.setPixelColor(i, SEGCOLOR(0)); | |
| 846 | } | ||
| 847 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
|
14 | for (unsigned i = 0; i < SEGENV.aux1 - (SEGLEN -a); i++) { |
| 848 | 3 | SEGMENT.setPixelColor(i, SEGCOLOR(0)); | |
| 849 | } | ||
| 850 | } | ||
| 851 | 56 | SEGENV.step = a; | |
| 852 | |||
| 853 | 56 | return 3 + ((8 * (uint32_t)(255 - SEGMENT.speed)) / SEGLEN); | |
| 854 | } | ||
| 855 | static const char _data_FX_MODE_ANDROID[] PROGMEM = "Android@!,Width;!,!;!;;m12=1"; //vertical | ||
| 856 | |||
| 857 | |||
| 858 | /* | ||
| 859 | * color chase function. | ||
| 860 | * color1 = background color | ||
| 861 | * color2 and color3 = colors of two adjacent leds | ||
| 862 | */ | ||
| 863 | 92 | static uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palette) { | |
| 864 | 92 | uint16_t counter = strip().now * ((SEGMENT.speed >> 2) + 1); | |
| 865 | 92 | uint16_t a = (counter * SEGLEN) >> 16; | |
| 866 | |||
| 867 | 92 | bool chase_random = (SEGMENT.mode == FX_MODE_CHASE_RANDOM); | |
| 868 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if (chase_random) { |
| 869 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (a < SEGENV.step) //we hit the start again, choose new color for Chase random |
| 870 | { | ||
| 871 | 1 | SEGENV.aux1 = SEGENV.aux0; //store previous random color | |
| 872 | 1 | SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); | |
| 873 | } | ||
| 874 | 23 | color1 = SEGMENT.color_wheel(SEGENV.aux0); | |
| 875 | } | ||
| 876 | 92 | SEGENV.step = a; | |
| 877 | |||
| 878 | // Use intensity setting to vary chase up to 1/2 string length | ||
| 879 | 92 | unsigned size = 1 + ((SEGMENT.intensity * SEGLEN) >> 10); | |
| 880 | |||
| 881 | 92 | uint16_t b = a + size; //"trail" of chase, filled with color1 | |
| 882 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 77 times.
|
92 | if (b > SEGLEN) b -= SEGLEN; |
| 883 | 92 | uint16_t c = b + size; | |
| 884 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 81 times.
|
92 | if (c > SEGLEN) c -= SEGLEN; |
| 885 | |||
| 886 | //background | ||
| 887 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if (do_palette) |
| 888 | { | ||
| 889 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 890 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); |
| 891 | } | ||
| 892 | 69 | } else SEGMENT.fill(color1); | |
| 893 | |||
| 894 | //if random, fill old background between a and end | ||
| 895 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if (chase_random) |
| 896 | { | ||
| 897 | 23 | color1 = SEGMENT.color_wheel(SEGENV.aux1); | |
| 898 |
2/2✓ Branch 0 taken 3952 times.
✓ Branch 1 taken 23 times.
|
3975 | for (unsigned i = a; i < SEGLEN; i++) |
| 899 | 3952 | SEGMENT.setPixelColor(i, color1); | |
| 900 | } | ||
| 901 | |||
| 902 | //fill between points a and b with color2 | ||
| 903 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 15 times.
|
92 | if (a < b) |
| 904 | { | ||
| 905 |
2/2✓ Branch 0 taken 3181 times.
✓ Branch 1 taken 77 times.
|
3258 | for (unsigned i = a; i < b; i++) |
| 906 | 3181 | SEGMENT.setPixelColor(i, color2); | |
| 907 | } else { | ||
| 908 |
2/2✓ Branch 0 taken 265 times.
✓ Branch 1 taken 15 times.
|
280 | for (unsigned i = a; i < SEGLEN; i++) //fill until end |
| 909 | 265 | SEGMENT.setPixelColor(i, color2); | |
| 910 |
2/2✓ Branch 0 taken 358 times.
✓ Branch 1 taken 15 times.
|
373 | for (unsigned i = 0; i < b; i++) //fill from start until b |
| 911 | 358 | SEGMENT.setPixelColor(i, color2); | |
| 912 | } | ||
| 913 | |||
| 914 | //fill between points b and c with color2 | ||
| 915 |
2/2✓ Branch 0 taken 81 times.
✓ Branch 1 taken 11 times.
|
92 | if (b < c) |
| 916 | { | ||
| 917 |
2/2✓ Branch 0 taken 3020 times.
✓ Branch 1 taken 81 times.
|
3101 | for (unsigned i = b; i < c; i++) |
| 918 | 3020 | SEGMENT.setPixelColor(i, color3); | |
| 919 | } else { | ||
| 920 |
2/2✓ Branch 0 taken 438 times.
✓ Branch 1 taken 11 times.
|
449 | for (unsigned i = b; i < SEGLEN; i++) //fill until end |
| 921 | 438 | SEGMENT.setPixelColor(i, color3); | |
| 922 |
2/2✓ Branch 0 taken 346 times.
✓ Branch 1 taken 11 times.
|
357 | for (unsigned i = 0; i < c; i++) //fill from start until c |
| 923 | 346 | SEGMENT.setPixelColor(i, color3); | |
| 924 | } | ||
| 925 | |||
| 926 | 92 | return FRAMETIME; | |
| 927 | } | ||
| 928 | |||
| 929 | |||
| 930 | /* | ||
| 931 | * Bicolor chase, more primary color. | ||
| 932 | */ | ||
| 933 | 23 | uint16_t mode_chase_color(void) { | |
| 934 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | return chase(SEGCOLOR(1), (SEGCOLOR(2)) ? SEGCOLOR(2) : SEGCOLOR(0), SEGCOLOR(0), true); |
| 935 | } | ||
| 936 | static const char _data_FX_MODE_CHASE_COLOR[] PROGMEM = "Chase@!,Width;!,!,!;!"; | ||
| 937 | |||
| 938 | |||
| 939 | /* | ||
| 940 | * Primary running followed by random color. | ||
| 941 | */ | ||
| 942 | 23 | uint16_t mode_chase_random(void) { | |
| 943 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | return chase(SEGCOLOR(1), (SEGCOLOR(2)) ? SEGCOLOR(2) : SEGCOLOR(0), SEGCOLOR(0), false); |
| 944 | } | ||
| 945 | static const char _data_FX_MODE_CHASE_RANDOM[] PROGMEM = "Chase Random@!,Width;!,,!;!"; | ||
| 946 | |||
| 947 | |||
| 948 | /* | ||
| 949 | * Primary, secondary running on rainbow. | ||
| 950 | */ | ||
| 951 | 23 | uint16_t mode_chase_rainbow(void) { | |
| 952 | 23 | unsigned color_sep = 256 / SEGLEN; | |
| 953 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | if (color_sep == 0) color_sep = 1; // correction for segments longer than 256 LEDs |
| 954 | 23 | unsigned color_index = SEGENV.call & 0xFF; | |
| 955 | 23 | uint32_t color = SEGMENT.color_wheel(((SEGENV.step * color_sep) + color_index) & 0xFF); | |
| 956 | |||
| 957 | 23 | return chase(color, SEGCOLOR(0), SEGCOLOR(1), false); | |
| 958 | } | ||
| 959 | static const char _data_FX_MODE_CHASE_RAINBOW[] PROGMEM = "Chase Rainbow@!,Width;!,!;!"; | ||
| 960 | |||
| 961 | |||
| 962 | /* | ||
| 963 | * Primary running on rainbow. | ||
| 964 | */ | ||
| 965 | 23 | uint16_t mode_chase_rainbow_white(void) { | |
| 966 | 23 | uint16_t n = SEGENV.step; | |
| 967 | 23 | uint16_t m = (SEGENV.step + 1) % SEGLEN; | |
| 968 | 23 | uint32_t color2 = SEGMENT.color_wheel(((n * 256 / SEGLEN) + (SEGENV.call & 0xFF)) & 0xFF); | |
| 969 | 23 | uint32_t color3 = SEGMENT.color_wheel(((m * 256 / SEGLEN) + (SEGENV.call & 0xFF)) & 0xFF); | |
| 970 | |||
| 971 | 23 | return chase(SEGCOLOR(0), color2, color3, false); | |
| 972 | } | ||
| 973 | static const char _data_FX_MODE_CHASE_RAINBOW_WHITE[] PROGMEM = "Rainbow Runner@!,Size;Bg;!"; | ||
| 974 | |||
| 975 | |||
| 976 | /* | ||
| 977 | * Red - Amber - Green - Blue lights running | ||
| 978 | */ | ||
| 979 | 23 | uint16_t mode_colorful(void) { | |
| 980 | 23 | unsigned numColors = 4; //3, 4, or 5 | |
| 981 | 23 | uint32_t cols[9]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC}; | |
| 982 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 19 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 19 times.
|
23 | if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color |
| 983 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | if (!SEGMENT.palette) { |
| 984 | 4 | numColors = 3; | |
| 985 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
|
16 | for (size_t i = 0; i < 3; i++) cols[i] = SEGCOLOR(i); |
| 986 | } else { | ||
| 987 | ✗ | unsigned fac = 80; | |
| 988 | ✗ | if (SEGMENT.palette == 52) {numColors = 5; fac = 61;} //C9 2 has 5 colors | |
| 989 | ✗ | for (size_t i = 0; i < numColors; i++) { | |
| 990 | ✗ | cols[i] = SEGMENT.color_from_palette(i*fac, false, true, 255); | |
| 991 | } | ||
| 992 | } | ||
| 993 |
4/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 15 times.
|
19 | } else if (SEGMENT.intensity < 80) //pastel (easter) colors |
| 994 | { | ||
| 995 | 4 | cols[0] = 0x00FF8040; | |
| 996 | 4 | cols[1] = 0x00E5D241; | |
| 997 | 4 | cols[2] = 0x0077FF77; | |
| 998 | 4 | cols[3] = 0x0077F0F0; | |
| 999 | } | ||
| 1000 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 23 times.
|
88 | for (size_t i = numColors; i < numColors*2 -1U; i++) cols[i] = cols[i-numColors]; |
| 1001 | |||
| 1002 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t cycleTime = 50 + (8 * (uint32_t)(255 - SEGMENT.speed)); |
| 1003 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | uint32_t it = strip().now / cycleTime; |
| 1004 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 14 times.
|
23 | if (it != SEGENV.step) |
| 1005 | { | ||
| 1006 |
6/10✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
|
9 | if (SEGMENT.speed > 0) SEGENV.aux0++; |
| 1007 |
6/10✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
9 | if (SEGENV.aux0 >= numColors) SEGENV.aux0 = 0; |
| 1008 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | SEGENV.step = it; |
| 1009 | } | ||
| 1010 | |||
| 1011 |
2/2✓ Branch 0 taken 2056 times.
✓ Branch 1 taken 23 times.
|
2079 | for (unsigned i = 0; i < SEGLEN; i+= numColors) |
| 1012 | { | ||
| 1013 |
7/12✓ Branch 0 taken 7540 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7540 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7540 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7540 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7540 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7540 times.
✓ Branch 11 taken 2056 times.
|
9596 | for (unsigned j = 0; j < numColors; j++) SEGMENT.setPixelColor(i + j, cols[SEGENV.aux0 + j]); |
| 1014 | } | ||
| 1015 | |||
| 1016 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
46 | return FRAMETIME; |
| 1017 | } | ||
| 1018 | static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2,3;!"; | ||
| 1019 | |||
| 1020 | |||
| 1021 | /* | ||
| 1022 | * Emulates a traffic light. | ||
| 1023 | */ | ||
| 1024 | 23 | uint16_t mode_traffic_light(void) { | |
| 1025 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1026 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i=0; i < SEGLEN; i++) |
| 1027 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); |
| 1028 | 23 | uint32_t mdelay = 500; | |
| 1029 |
2/2✓ Branch 0 taken 2495 times.
✓ Branch 1 taken 23 times.
|
2518 | for (unsigned i = 0; i < SEGLEN-2 ; i+=3) |
| 1030 | { | ||
| 1031 |
3/5✓ Branch 0 taken 567 times.
✓ Branch 1 taken 1418 times.
✓ Branch 2 taken 510 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
2495 | switch (SEGENV.aux0) |
| 1032 | { | ||
| 1033 | 567 | case 0: SEGMENT.setPixelColor(i, 0x00FF0000); mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));break; | |
| 1034 | 1418 | case 1: SEGMENT.setPixelColor(i, 0x00FF0000); mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed)); SEGMENT.setPixelColor(i+1, 0x00EECC00); break; | |
| 1035 | 510 | case 2: SEGMENT.setPixelColor(i+2, 0x0000FF00); mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));break; | |
| 1036 | ✗ | case 3: SEGMENT.setPixelColor(i+1, 0x00EECC00); mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed));break; | |
| 1037 | } | ||
| 1038 | } | ||
| 1039 | |||
| 1040 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (strip().now - SEGENV.step > mdelay) |
| 1041 | { | ||
| 1042 | 5 | SEGENV.aux0++; | |
| 1043 |
5/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
|
5 | if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence |
| 1044 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (SEGENV.aux0 > 3) SEGENV.aux0 = 0; |
| 1045 | 5 | SEGENV.step = strip().now; | |
| 1046 | } | ||
| 1047 | |||
| 1048 | 23 | return FRAMETIME; | |
| 1049 | } | ||
| 1050 | static const char _data_FX_MODE_TRAFFIC_LIGHT[] PROGMEM = "Traffic Light@!,US style;,!;!"; | ||
| 1051 | |||
| 1052 | |||
| 1053 | /* | ||
| 1054 | * Sec flashes running on prim. | ||
| 1055 | */ | ||
| 1056 | #define FLASH_COUNT 4 | ||
| 1057 | 23 | uint16_t mode_chase_flash(void) { | |
| 1058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1059 | 23 | unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); | |
| 1060 | |||
| 1061 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 1062 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 1063 | } | ||
| 1064 | |||
| 1065 | 23 | unsigned delay = 10 + ((30 * (uint16_t)(255 - SEGMENT.speed)) / SEGLEN); | |
| 1066 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if(flash_step < (FLASH_COUNT * 2)) { |
| 1067 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | if(flash_step % 2 == 0) { |
| 1068 | 13 | unsigned n = SEGENV.step; | |
| 1069 | 13 | unsigned m = (SEGENV.step + 1) % SEGLEN; | |
| 1070 | 13 | SEGMENT.setPixelColor( n, SEGCOLOR(1)); | |
| 1071 | 13 | SEGMENT.setPixelColor( m, SEGCOLOR(1)); | |
| 1072 | 13 | delay = 20; | |
| 1073 | } else { | ||
| 1074 | 10 | delay = 30; | |
| 1075 | } | ||
| 1076 | } else { | ||
| 1077 | ✗ | SEGENV.step = (SEGENV.step + 1) % SEGLEN; | |
| 1078 | } | ||
| 1079 | 23 | return delay; | |
| 1080 | } | ||
| 1081 | static const char _data_FX_MODE_CHASE_FLASH[] PROGMEM = "Chase Flash@!;Bg,Fx;!"; | ||
| 1082 | |||
| 1083 | |||
| 1084 | /* | ||
| 1085 | * Prim flashes running, followed by random color. | ||
| 1086 | */ | ||
| 1087 | 23 | uint16_t mode_chase_flash_random(void) { | |
| 1088 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1089 | 23 | unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); | |
| 1090 | |||
| 1091 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | for (int i = 0; i < SEGENV.aux1; i++) { |
| 1092 | ✗ | SEGMENT.setPixelColor(i, SEGMENT.color_wheel(SEGENV.aux0)); | |
| 1093 | } | ||
| 1094 | |||
| 1095 | 23 | unsigned delay = 1 + ((10 * (uint16_t)(255 - SEGMENT.speed)) / SEGLEN); | |
| 1096 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if(flash_step < (FLASH_COUNT * 2)) { |
| 1097 | 23 | unsigned n = SEGENV.aux1; | |
| 1098 | 23 | unsigned m = (SEGENV.aux1 + 1) % SEGLEN; | |
| 1099 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | if(flash_step % 2 == 0) { |
| 1100 | 13 | SEGMENT.setPixelColor( n, SEGCOLOR(0)); | |
| 1101 | 13 | SEGMENT.setPixelColor( m, SEGCOLOR(0)); | |
| 1102 | 13 | delay = 20; | |
| 1103 | } else { | ||
| 1104 | 10 | SEGMENT.setPixelColor( n, SEGMENT.color_wheel(SEGENV.aux0)); | |
| 1105 | 10 | SEGMENT.setPixelColor( m, SEGCOLOR(1)); | |
| 1106 | 10 | delay = 30; | |
| 1107 | } | ||
| 1108 | } else { | ||
| 1109 | ✗ | SEGENV.aux1 = (SEGENV.aux1 + 1) % SEGLEN; | |
| 1110 | |||
| 1111 | ✗ | if (SEGENV.aux1 == 0) { | |
| 1112 | ✗ | SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); | |
| 1113 | } | ||
| 1114 | } | ||
| 1115 | 23 | return delay; | |
| 1116 | } | ||
| 1117 | static const char _data_FX_MODE_CHASE_FLASH_RANDOM[] PROGMEM = "Chase Flash Rnd@!;!,!;!"; | ||
| 1118 | |||
| 1119 | |||
| 1120 | /* | ||
| 1121 | * Alternating color/sec pixels running. | ||
| 1122 | */ | ||
| 1123 | 23 | uint16_t mode_running_color(void) { | |
| 1124 | 23 | return running(SEGCOLOR(0), SEGCOLOR(1)); | |
| 1125 | } | ||
| 1126 | static const char _data_FX_MODE_RUNNING_COLOR[] PROGMEM = "Chase 2@!,Width;!,!;!"; | ||
| 1127 | |||
| 1128 | |||
| 1129 | /* | ||
| 1130 | * Random colored pixels running. ("Stream") | ||
| 1131 | */ | ||
| 1132 | 123 | uint16_t mode_running_random(void) { | |
| 1133 | 123 | uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed)); | |
| 1134 | 123 | uint32_t it = strip().now / cycleTime; | |
| 1135 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 117 times.
|
123 | if (SEGENV.call == 0) SEGENV.aux0 = hw_random(); // random seed for PRNG on start |
| 1136 | |||
| 1137 | 123 | unsigned zoneSize = ((255-SEGMENT.intensity) >> 4) +1; | |
| 1138 | 123 | uint16_t PRNG16 = SEGENV.aux0; | |
| 1139 | |||
| 1140 | 123 | unsigned z = it % zoneSize; | |
| 1141 |
4/4✓ Branch 0 taken 115 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 101 times.
|
123 | bool nzone = (!z && (it & 0xFFFF) != SEGENV.aux1); |
| 1142 |
2/2✓ Branch 0 taken 12511 times.
✓ Branch 1 taken 123 times.
|
12634 | for (int i=SEGLEN-1; i >= 0; i--) { |
| 1143 |
4/4✓ Branch 0 taken 12497 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 7490 times.
✓ Branch 3 taken 5007 times.
|
12511 | if (nzone || z >= zoneSize) { |
| 1144 | 7504 | unsigned lastrand = PRNG16 >> 8; | |
| 1145 | 7504 | int16_t diff = 0; | |
| 1146 |
2/2✓ Branch 0 taken 10399 times.
✓ Branch 1 taken 7504 times.
|
17903 | while (abs(diff) < 42) { // make sure the difference between adjacent colors is big enough |
| 1147 | 10399 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next zone, next 'random' number | |
| 1148 | 10399 | diff = (PRNG16 >> 8) - lastrand; | |
| 1149 | } | ||
| 1150 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7490 times.
|
7504 | if (nzone) { |
| 1151 | 14 | SEGENV.aux0 = PRNG16; // save next starting seed | |
| 1152 | 14 | nzone = false; | |
| 1153 | } | ||
| 1154 | 7504 | z = 0; | |
| 1155 | } | ||
| 1156 | 12511 | SEGMENT.setPixelColor(i, SEGMENT.color_wheel(PRNG16 >> 8)); | |
| 1157 | 12511 | z++; | |
| 1158 | } | ||
| 1159 | |||
| 1160 | 123 | SEGENV.aux1 = it & 0xFFFF; | |
| 1161 | 123 | return FRAMETIME; | |
| 1162 | } | ||
| 1163 | static const char _data_FX_MODE_RUNNING_RANDOM[] PROGMEM = "Stream@!,Zone size;;!"; | ||
| 1164 | |||
| 1165 | |||
| 1166 | /* | ||
| 1167 | * K.I.T.T. | ||
| 1168 | */ | ||
| 1169 | 46 | uint16_t mode_larson_scanner(void) { | |
| 1170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGLEN <= 1) return mode_static(); |
| 1171 | |||
| 1172 | 46 | const unsigned speed = FRAMETIME * map(SEGMENT.speed, 0, 255, 96, 2); // map into useful range | |
| 1173 | 46 | const unsigned pixels = SEGLEN / speed; // how many pixels to advance per frame | |
| 1174 | |||
| 1175 | 46 | SEGMENT.fade_out(255-SEGMENT.intensity); | |
| 1176 | |||
| 1177 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGENV.step > strip().now) return FRAMETIME; // we have a pause |
| 1178 | |||
| 1179 | 46 | unsigned index = SEGENV.aux1 + pixels; | |
| 1180 | // are we slow enough to use frames per pixel? | ||
| 1181 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 8 times.
|
46 | if (pixels == 0) { |
| 1182 | 38 | const unsigned frames = speed / SEGLEN; // how many frames per 1 pixel | |
| 1183 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2 times.
|
38 | if (SEGENV.step++ < frames) return FRAMETIME; |
| 1184 | 2 | SEGENV.step = 0; | |
| 1185 | 2 | index++; | |
| 1186 | } | ||
| 1187 | |||
| 1188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (index > SEGLEN) { |
| 1189 | |||
| 1190 | ✗ | SEGENV.aux0 = !SEGENV.aux0; // change direction | |
| 1191 | ✗ | SEGENV.aux1 = 0; // reset position | |
| 1192 | // set delay | ||
| 1193 | ✗ | if (SEGENV.aux0 || SEGMENT.check2) SEGENV.step = strip().now + SEGMENT.custom1 * 25; // multiply by 25ms | |
| 1194 | ✗ | else SEGENV.step = 0; | |
| 1195 | |||
| 1196 | } else { | ||
| 1197 | |||
| 1198 | // paint as many pixels as needed | ||
| 1199 |
2/2✓ Branch 0 taken 82 times.
✓ Branch 1 taken 10 times.
|
92 | for (unsigned i = SEGENV.aux1; i < index; i++) { |
| 1200 |
1/2✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
|
82 | unsigned j = (SEGENV.aux0) ? i : SEGLEN - 1 - i; |
| 1201 |
2/4✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
|
82 | uint32_t c = SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0); |
| 1202 | 82 | SEGMENT.setPixelColor(j, c); | |
| 1203 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 41 times.
|
82 | if (SEGMENT.check1) { |
| 1204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
|
41 | SEGMENT.setPixelColor(SEGLEN - 1 - j, SEGCOLOR(2) ? SEGCOLOR(2) : c); |
| 1205 | } | ||
| 1206 | } | ||
| 1207 | 10 | SEGENV.aux1 = index; | |
| 1208 | } | ||
| 1209 | 10 | return FRAMETIME; | |
| 1210 | } | ||
| 1211 | static const char _data_FX_MODE_LARSON_SCANNER[] PROGMEM = "Scanner@!,Trail,Delay,,,Dual,Bi-delay;!,!,!;!;;m12=0,c1=0"; | ||
| 1212 | |||
| 1213 | /* | ||
| 1214 | * Creates two Larson scanners moving in opposite directions | ||
| 1215 | * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/DualLarson.h | ||
| 1216 | */ | ||
| 1217 | 23 | uint16_t mode_dual_larson_scanner(void){ | |
| 1218 | 23 | SEGMENT.check1 = true; | |
| 1219 | 23 | return mode_larson_scanner(); | |
| 1220 | } | ||
| 1221 | static const char _data_FX_MODE_DUAL_LARSON_SCANNER[] PROGMEM = "Scanner Dual@!,Trail,Delay,,,Dual,Bi-delay;!,!,!;!;;m12=0,c1=0"; | ||
| 1222 | |||
| 1223 | /* | ||
| 1224 | * Firing comets from one end. "Lighthouse" | ||
| 1225 | */ | ||
| 1226 | 23 | uint16_t mode_comet(void) { | |
| 1227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1228 | 23 | unsigned counter = (strip().now * ((SEGMENT.speed >>2) +1)) & 0xFFFF; | |
| 1229 | 23 | unsigned index = (counter * SEGLEN) >> 16; | |
| 1230 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) SEGENV.aux0 = index; |
| 1231 | |||
| 1232 | 23 | SEGMENT.fade_out(SEGMENT.intensity); | |
| 1233 | |||
| 1234 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
23 | SEGMENT.setPixelColor( index, SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); |
| 1235 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9 times.
|
23 | if (index > SEGENV.aux0) { |
| 1236 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 14 times.
|
158 | for (unsigned i = SEGENV.aux0; i < index ; i++) { |
| 1237 |
2/4✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
|
144 | SEGMENT.setPixelColor( i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 1238 | } | ||
| 1239 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
9 | } else if (index < SEGENV.aux0 && index < 10) { |
| 1240 | ✗ | for (unsigned i = 0; i < index ; i++) { | |
| 1241 | ✗ | SEGMENT.setPixelColor( i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); | |
| 1242 | } | ||
| 1243 | } | ||
| 1244 | 23 | SEGENV.aux0 = index++; | |
| 1245 | |||
| 1246 | 23 | return FRAMETIME; | |
| 1247 | } | ||
| 1248 | static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!"; | ||
| 1249 | |||
| 1250 | /* | ||
| 1251 | * Fireworks function. | ||
| 1252 | */ | ||
| 1253 | 46 | uint16_t mode_fireworks() { | |
| 1254 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGLEN <= 1) return mode_static(); |
| 1255 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 10 times.
|
46 | const uint16_t width = SEGMENT.is2D() ? SEG_W : SEGLEN; |
| 1256 | 46 | const uint16_t height = SEG_H; | |
| 1257 | |||
| 1258 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
|
46 | if (SEGENV.call == 0) { |
| 1259 | 10 | SEGENV.aux0 = UINT16_MAX; | |
| 1260 | 10 | SEGENV.aux1 = UINT16_MAX; | |
| 1261 | } | ||
| 1262 | 46 | SEGMENT.fade_out(128); | |
| 1263 | |||
| 1264 | 46 | uint8_t x = SEGENV.aux0%width, y = SEGENV.aux0/width; // 2D coordinates stored in upper and lower byte | |
| 1265 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | if (!SEGENV.step) { |
| 1266 | // fireworks mode (blur flares) | ||
| 1267 | 23 | bool valid1 = (SEGENV.aux0 < width*height); | |
| 1268 | 23 | bool valid2 = (SEGENV.aux1 < width*height); | |
| 1269 | 23 | uint32_t sv1 = 0, sv2 = 0; | |
| 1270 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
23 | if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color |
| 1271 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
23 | if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1); |
| 1272 | 23 | SEGMENT.blur(16); // used in mode_rain() | |
| 1273 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
23 | if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur |
| 1274 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
23 | if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur |
| 1275 | } | ||
| 1276 | |||
| 1277 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 46 times.
|
152 | for (int i=0; i<max(1, width/20); i++) { |
| 1278 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 100 times.
|
106 | if (hw_random8(129 - (SEGMENT.intensity >> 1)) == 0) { |
| 1279 | 6 | uint16_t index = hw_random16(width*height); | |
| 1280 | 6 | x = index % width; | |
| 1281 | 6 | y = index / width; | |
| 1282 | 6 | uint32_t col = SEGMENT.color_from_palette(hw_random8(), false, false, 0); | |
| 1283 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col); |
| 1284 | 3 | else SEGMENT.setPixelColor(index, col); | |
| 1285 | 6 | SEGENV.aux1 = SEGENV.aux0; // old spark | |
| 1286 | 6 | SEGENV.aux0 = index; // remember where spark occurred | |
| 1287 | } | ||
| 1288 | } | ||
| 1289 | 46 | return FRAMETIME; | |
| 1290 | } | ||
| 1291 | static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!;!;12;ix=192,pal=11"; | ||
| 1292 | |||
| 1293 | //Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h | ||
| 1294 | 23 | uint16_t mode_rain() { | |
| 1295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1296 | 23 | const unsigned width = SEG_W; | |
| 1297 | 23 | const unsigned height = SEG_H; | |
| 1298 | 23 | SEGENV.step += FRAMETIME; | |
| 1299 |
6/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 12 times.
|
23 | if (SEGENV.call && SEGENV.step > SPEED_FORMULA_L) { |
| 1300 | 11 | SEGENV.step = 1; | |
| 1301 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
|
11 | if (SEGMENT.is2D()) { |
| 1302 | //uint32_t ctemp[width]; | ||
| 1303 | //for (int i = 0; i<width; i++) ctemp[i] = SEGMENT.getPixelColorXY(i, height-1); | ||
| 1304 | 9 | SEGMENT.move(6, 1, true); // move all pixels down | |
| 1305 | //for (int i = 0; i<width; i++) SEGMENT.setPixelColorXY(i, 0, ctemp[i]); // wrap around | ||
| 1306 | 9 | SEGENV.aux0 = (SEGENV.aux0 % width) + (SEGENV.aux0 / width + 1) * width; | |
| 1307 | 9 | SEGENV.aux1 = (SEGENV.aux1 % width) + (SEGENV.aux1 / width + 1) * width; | |
| 1308 | } else { | ||
| 1309 | //shift all leds left | ||
| 1310 | 2 | uint32_t ctemp = SEGMENT.getPixelColor(0); | |
| 1311 |
2/2✓ Branch 0 taken 298 times.
✓ Branch 1 taken 2 times.
|
300 | for (unsigned i = 0; i < SEGLEN - 1; i++) { |
| 1312 | 298 | SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); | |
| 1313 | } | ||
| 1314 | 2 | SEGMENT.setPixelColor(SEGLEN -1, ctemp); // wrap around | |
| 1315 | 2 | SEGENV.aux0++; // increase spark index | |
| 1316 | 2 | SEGENV.aux1++; | |
| 1317 | } | ||
| 1318 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark position |
| 1319 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (SEGENV.aux1 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark position |
| 1320 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (SEGENV.aux0 >= width*height) SEGENV.aux0 = 0; // ignore |
| 1321 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (SEGENV.aux1 >= width*height) SEGENV.aux1 = 0; |
| 1322 | } | ||
| 1323 | 23 | return mode_fireworks(); | |
| 1324 | } | ||
| 1325 | static const char _data_FX_MODE_RAIN[] PROGMEM = "Rain@!,Spawning rate;!,!;!;12;ix=128,pal=0"; | ||
| 1326 | |||
| 1327 | /* | ||
| 1328 | * Fire flicker function | ||
| 1329 | */ | ||
| 1330 | 23 | uint16_t mode_fire_flicker(void) { | |
| 1331 | 23 | uint32_t cycleTime = 40 + (255 - SEGMENT.speed); | |
| 1332 | 23 | uint32_t it = strip().now / cycleTime; | |
| 1333 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 12 times.
|
23 | if (SEGENV.step == it) return FRAMETIME; |
| 1334 | |||
| 1335 | 12 | byte w = (SEGCOLOR(0) >> 24); | |
| 1336 | 12 | byte r = (SEGCOLOR(0) >> 16); | |
| 1337 | 12 | byte g = (SEGCOLOR(0) >> 8); | |
| 1338 | 12 | byte b = (SEGCOLOR(0) ); | |
| 1339 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255; |
| 1340 | 12 | lum /= (((256-SEGMENT.intensity)/16)+1); | |
| 1341 |
2/2✓ Branch 0 taken 4438 times.
✓ Branch 1 taken 12 times.
|
4450 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 1342 | 4438 | byte flicker = hw_random8(lum); | |
| 1343 |
1/2✓ Branch 0 taken 4438 times.
✗ Branch 1 not taken.
|
4438 | if (SEGMENT.palette == 0) { |
| 1344 | 4438 | SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0)); | |
| 1345 | } else { | ||
| 1346 | ✗ | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker)); | |
| 1347 | } | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | 12 | SEGENV.step = it; | |
| 1351 | 12 | return FRAMETIME; | |
| 1352 | } | ||
| 1353 | static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!;01"; | ||
| 1354 | |||
| 1355 | |||
| 1356 | /* | ||
| 1357 | * Gradient run base function | ||
| 1358 | */ | ||
| 1359 | 46 | uint16_t gradient_base(bool loading) { | |
| 1360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGLEN <= 1) return mode_static(); |
| 1361 | 46 | uint16_t counter = strip().now * ((SEGMENT.speed >> 2) + 1); | |
| 1362 | 46 | uint16_t pp = (counter * SEGLEN) >> 16; | |
| 1363 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 36 times.
|
46 | if (SEGENV.call == 0) pp = 0; |
| 1364 | int val; //0 = sec 1 = pri | ||
| 1365 | 46 | int brd = 1 + loading ? SEGMENT.intensity/2 : SEGMENT.intensity/4; | |
| 1366 | //if (brd < 1) brd = 1; | ||
| 1367 | 46 | int p1 = pp-SEGLEN; | |
| 1368 | 46 | int p2 = pp+SEGLEN; | |
| 1369 | |||
| 1370 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 46 times.
|
15068 | for (int i = 0; i < (int)SEGLEN; i++) { |
| 1371 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 7511 times.
|
15022 | if (loading) { |
| 1372 |
2/2✓ Branch 0 taken 3525 times.
✓ Branch 1 taken 3986 times.
|
7511 | val = abs(((i>pp) ? p2:pp) - i); |
| 1373 | } else { | ||
| 1374 | 7511 | val = min(abs(pp-i),min(abs(p1-i),abs(p2-i))); | |
| 1375 | } | ||
| 1376 |
2/2✓ Branch 0 taken 1865 times.
✓ Branch 1 taken 13157 times.
|
15022 | val = (brd > val) ? (val * 255) / brd : 255; |
| 1377 |
2/4✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15022 times.
|
15022 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), uint8_t(val))); |
| 1378 | } | ||
| 1379 | |||
| 1380 | 46 | return FRAMETIME; | |
| 1381 | } | ||
| 1382 | |||
| 1383 | |||
| 1384 | /* | ||
| 1385 | * Gradient run | ||
| 1386 | */ | ||
| 1387 | 23 | uint16_t mode_gradient(void) { | |
| 1388 | 23 | return gradient_base(false); | |
| 1389 | } | ||
| 1390 | static const char _data_FX_MODE_GRADIENT[] PROGMEM = "Gradient@!,Spread;!,!;!;;ix=16"; | ||
| 1391 | |||
| 1392 | |||
| 1393 | /* | ||
| 1394 | * Gradient run with hard transition | ||
| 1395 | */ | ||
| 1396 | 23 | uint16_t mode_loading(void) { | |
| 1397 | 23 | return gradient_base(true); | |
| 1398 | } | ||
| 1399 | static const char _data_FX_MODE_LOADING[] PROGMEM = "Loading@!,Fade;!,!;!;;ix=16"; | ||
| 1400 | |||
| 1401 | /* | ||
| 1402 | * Two dots running | ||
| 1403 | */ | ||
| 1404 | 23 | uint16_t mode_two_dots() { | |
| 1405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1406 | 23 | unsigned delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster | |
| 1407 | 23 | uint32_t it = strip().now / map(SEGMENT.speed, 0, 255, delay<<4, delay); | |
| 1408 | 23 | unsigned offset = it % SEGLEN; | |
| 1409 | 23 | unsigned width = ((SEGLEN*(SEGMENT.intensity+1))>>9); //max width is half the strip | |
| 1410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!width) width = 1; |
| 1411 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2)); |
| 1412 | 23 | const uint32_t color1 = SEGCOLOR(0); | |
| 1413 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | const uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? color1 : SEGCOLOR(1); |
| 1414 |
2/2✓ Branch 0 taken 1883 times.
✓ Branch 1 taken 23 times.
|
1906 | for (unsigned i = 0; i < width; i++) { |
| 1415 | 1883 | unsigned indexR = (offset + i) % SEGLEN; | |
| 1416 | 1883 | unsigned indexB = (offset + i + (SEGLEN>>1)) % SEGLEN; | |
| 1417 | 1883 | SEGMENT.setPixelColor(indexR, color1); | |
| 1418 | 1883 | SEGMENT.setPixelColor(indexB, color2); | |
| 1419 | } | ||
| 1420 | 23 | return FRAMETIME; | |
| 1421 | } | ||
| 1422 | static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size,,,,,Overlay;1,2,Bg;!"; | ||
| 1423 | |||
| 1424 | |||
| 1425 | /* | ||
| 1426 | * Fairy, inspired by https://www.youtube.com/watch?v=zeOw5MZWq24 | ||
| 1427 | */ | ||
| 1428 | //4 bytes | ||
| 1429 | typedef struct Flasher { | ||
| 1430 | uint16_t stateStart; | ||
| 1431 | uint8_t stateDur; | ||
| 1432 | bool stateOn; | ||
| 1433 | } flasher; | ||
| 1434 | |||
| 1435 | #define FLASHERS_PER_ZONE 6 | ||
| 1436 | #define MAX_SHIMMER 92 | ||
| 1437 | |||
| 1438 | 23 | uint16_t mode_fairy() { | |
| 1439 | //set every pixel to a 'random' color from palette (using seed so it doesn't change between frames) | ||
| 1440 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | uint16_t PRNG16 = 5100 + strip().getCurrSegmentId(); |
| 1441 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 1442 | 7511 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number | |
| 1443 |
6/12✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7511 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7511 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7511 times.
✗ Branch 11 not taken.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0)); |
| 1444 | } | ||
| 1445 | |||
| 1446 | //amount of flasher pixels depending on intensity (0: none, 255: every LED) | ||
| 1447 |
5/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
23 | if (SEGMENT.intensity == 0) return FRAMETIME; |
| 1448 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | unsigned flasherDistance = ((255 - SEGMENT.intensity) / 28) +1; //1-10 |
| 1449 | 19 | unsigned numFlashers = (SEGLEN / flasherDistance) +1; | |
| 1450 | |||
| 1451 | 19 | unsigned dataSize = sizeof(flasher) * numFlashers; | |
| 1452 |
4/10✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 19 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
19 | if (!SEGENV.allocateData(dataSize)) return FRAMETIME; //allocation failed |
| 1453 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | Flasher* flashers = reinterpret_cast<Flasher*>(SEGENV.data); |
| 1454 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | unsigned now16 = strip().now & 0xFFFF; |
| 1455 | |||
| 1456 | //Up to 11 flashers in one brightness zone, afterwards a new zone for every 6 flashers | ||
| 1457 | 19 | unsigned zones = numFlashers/FLASHERS_PER_ZONE; | |
| 1458 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14 times.
|
19 | if (!zones) zones = 1; |
| 1459 | 19 | unsigned flashersInZone = numFlashers/zones; | |
| 1460 | uint8_t flasherBri[FLASHERS_PER_ZONE*2 -1]; | ||
| 1461 | |||
| 1462 |
2/2✓ Branch 0 taken 455 times.
✓ Branch 1 taken 19 times.
|
474 | for (unsigned z = 0; z < zones; z++) { |
| 1463 | 455 | unsigned flasherBriSum = 0; | |
| 1464 | 455 | unsigned firstFlasher = z*flashersInZone; | |
| 1465 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 436 times.
|
455 | if (z == zones-1) flashersInZone = numFlashers-(flashersInZone*(zones-1)); |
| 1466 | |||
| 1467 |
2/2✓ Branch 0 taken 2747 times.
✓ Branch 1 taken 455 times.
|
3202 | for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) { |
| 1468 | 2747 | unsigned stateTime = uint16_t(now16 - flashers[f].stateStart); | |
| 1469 | //random on/off time reached, switch state | ||
| 1470 |
2/2✓ Branch 0 taken 793 times.
✓ Branch 1 taken 1954 times.
|
2747 | if (stateTime > flashers[f].stateDur * 10) { |
| 1471 | 793 | flashers[f].stateOn = !flashers[f].stateOn; | |
| 1472 |
2/2✓ Branch 0 taken 652 times.
✓ Branch 1 taken 141 times.
|
793 | if (flashers[f].stateOn) { |
| 1473 |
2/4✓ Branch 0 taken 652 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 652 times.
✗ Branch 3 not taken.
|
652 | flashers[f].stateDur = 12 + hw_random8(12 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms |
| 1474 | } else { | ||
| 1475 |
2/4✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
|
141 | flashers[f].stateDur = 20 + hw_random8(6 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms |
| 1476 | } | ||
| 1477 | //flashers[f].stateDur = 51 + hw_random8(2 + ((255 - SEGMENT.speed) >> 1)); | ||
| 1478 | 793 | flashers[f].stateStart = now16; | |
| 1479 |
2/2✓ Branch 0 taken 141 times.
✓ Branch 1 taken 652 times.
|
793 | if (stateTime < 255) { |
| 1480 | 141 | flashers[f].stateStart -= 255 -stateTime; //start early to get correct bri | |
| 1481 | 141 | flashers[f].stateDur += 26 - stateTime/10; | |
| 1482 | 141 | stateTime = 255 - stateTime; | |
| 1483 | } else { | ||
| 1484 | 652 | stateTime = 0; | |
| 1485 | } | ||
| 1486 | } | ||
| 1487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2747 times.
|
2747 | if (stateTime > 255) stateTime = 255; //for flasher brightness calculation, fades in first 255 ms of state |
| 1488 | //flasherBri[f - firstFlasher] = (flashers[f].stateOn) ? 255-SEGMENT.gamma8((510 - stateTime) >> 1) : SEGMENT.gamma8((510 - stateTime) >> 1); | ||
| 1489 |
2/2✓ Branch 0 taken 2598 times.
✓ Branch 1 taken 149 times.
|
2747 | flasherBri[f - firstFlasher] = (flashers[f].stateOn) ? stateTime : 255 - (stateTime >> 0); |
| 1490 | 2747 | flasherBriSum += flasherBri[f - firstFlasher]; | |
| 1491 | } | ||
| 1492 | //dim factor, to create "shimmer" as other pixels get less voltage if a lot of flashers are on | ||
| 1493 | 455 | unsigned avgFlasherBri = flasherBriSum / flashersInZone; | |
| 1494 | 455 | unsigned globalPeakBri = 255 - ((avgFlasherBri * MAX_SHIMMER) >> 8); //183-255, suitable for 1/5th of LEDs flashers | |
| 1495 | |||
| 1496 |
2/2✓ Branch 0 taken 2747 times.
✓ Branch 1 taken 455 times.
|
3202 | for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) { |
| 1497 | 2747 | uint8_t bri = (flasherBri[f - firstFlasher] * globalPeakBri) / 255; | |
| 1498 | 2747 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number | |
| 1499 | 2747 | unsigned flasherPos = f*flasherDistance; | |
| 1500 |
7/14✓ Branch 0 taken 2747 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2747 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2747 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2747 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2747 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2747 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2747 times.
✗ Branch 13 not taken.
|
2747 | SEGMENT.setPixelColor(flasherPos, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0), bri)); |
| 1501 |
6/6✓ Branch 0 taken 2740 times.
✓ Branch 1 taken 2732 times.
✓ Branch 2 taken 2725 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 2725 times.
✓ Branch 5 taken 2747 times.
|
5472 | for (unsigned i = flasherPos+1; i < flasherPos+flasherDistance && i < SEGLEN; i++) { |
| 1502 | 2725 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number | |
| 1503 |
6/12✓ Branch 0 taken 2725 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2725 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2725 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2725 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2725 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2725 times.
✗ Branch 11 not taken.
|
2725 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0, globalPeakBri)); |
| 1504 | } | ||
| 1505 | } | ||
| 1506 | } | ||
| 1507 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | return FRAMETIME; |
| 1508 | } | ||
| 1509 | static const char _data_FX_MODE_FAIRY[] PROGMEM = "Fairy@!,# of flashers;!,!;!"; | ||
| 1510 | |||
| 1511 | |||
| 1512 | /* | ||
| 1513 | * Fairytwinkle. Like Colortwinkle, but starting from all lit and not relying on strip().getPixelColor | ||
| 1514 | * Warning: Uses 4 bytes of segment data per pixel | ||
| 1515 | */ | ||
| 1516 | 23 | uint16_t mode_fairytwinkle() { | |
| 1517 | 23 | unsigned dataSize = sizeof(flasher) * SEGLEN; | |
| 1518 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 1519 | 23 | Flasher* flashers = reinterpret_cast<Flasher*>(SEGENV.data); | |
| 1520 | 23 | unsigned now16 = strip().now & 0xFFFF; | |
| 1521 | 23 | uint16_t PRNG16 = 5100 + strip().getCurrSegmentId(); | |
| 1522 | |||
| 1523 | 23 | unsigned riseFallTime = 400 + (255-SEGMENT.speed)*3; | |
| 1524 | 23 | unsigned maxDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + 13 + ((255 - SEGMENT.intensity) >> 1); | |
| 1525 | |||
| 1526 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned f = 0; f < SEGLEN; f++) { |
| 1527 | 7511 | uint16_t stateTime = now16 - flashers[f].stateStart; | |
| 1528 | //random on/off time reached, switch state | ||
| 1529 |
2/2✓ Branch 0 taken 1707 times.
✓ Branch 1 taken 5804 times.
|
7511 | if (stateTime > flashers[f].stateDur * 100) { |
| 1530 | 1707 | flashers[f].stateOn = !flashers[f].stateOn; | |
| 1531 | 1707 | bool init = !flashers[f].stateDur; | |
| 1532 |
1/2✓ Branch 0 taken 1707 times.
✗ Branch 1 not taken.
|
1707 | if (flashers[f].stateOn) { |
| 1533 | 1707 | flashers[f].stateDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + hw_random8(12 + ((255 - SEGMENT.intensity) >> 1)) +1; | |
| 1534 | } else { | ||
| 1535 | ✗ | flashers[f].stateDur = riseFallTime/100 + hw_random8(3 + ((255 - SEGMENT.speed) >> 6)) +1; | |
| 1536 | } | ||
| 1537 | 1707 | flashers[f].stateStart = now16; | |
| 1538 | 1707 | stateTime = 0; | |
| 1539 |
1/2✓ Branch 0 taken 1707 times.
✗ Branch 1 not taken.
|
1707 | if (init) { |
| 1540 | 1707 | flashers[f].stateStart -= riseFallTime; //start lit | |
| 1541 | 1707 | flashers[f].stateDur = riseFallTime/100 + hw_random8(12 + ((255 - SEGMENT.intensity) >> 1)) +5; //fire up a little quicker | |
| 1542 | 1707 | stateTime = riseFallTime; | |
| 1543 | } | ||
| 1544 | } | ||
| 1545 |
3/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 7386 times.
|
7511 | if (flashers[f].stateOn && flashers[f].stateDur > maxDur) flashers[f].stateDur = maxDur; //react more quickly on intensity change |
| 1546 |
2/2✓ Branch 0 taken 5804 times.
✓ Branch 1 taken 1707 times.
|
7511 | if (stateTime > riseFallTime) stateTime = riseFallTime; //for flasher brightness calculation, fades in first 255 ms of state |
| 1547 | 7511 | unsigned fadeprog = 255 - ((stateTime * 255) / riseFallTime); | |
| 1548 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
7511 | uint8_t flasherBri = (flashers[f].stateOn) ? 255-gamma8(fadeprog) : gamma8(fadeprog); |
| 1549 | 7511 | unsigned lastR = PRNG16; | |
| 1550 | 7511 | unsigned diff = 0; | |
| 1551 |
2/2✓ Branch 0 taken 14004 times.
✓ Branch 1 taken 7511 times.
|
21515 | while (diff < 0x4000) { //make sure colors of two adjacent LEDs differ enough |
| 1552 | 14004 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number | |
| 1553 |
2/2✓ Branch 0 taken 7250 times.
✓ Branch 1 taken 6754 times.
|
14004 | diff = (PRNG16 > lastR) ? PRNG16 - lastR : lastR - PRNG16; |
| 1554 | } | ||
| 1555 | 7511 | SEGMENT.setPixelColor(f, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0), flasherBri)); | |
| 1556 | } | ||
| 1557 | 23 | return FRAMETIME; | |
| 1558 | } | ||
| 1559 | static const char _data_FX_MODE_FAIRYTWINKLE[] PROGMEM = "Fairytwinkle@!,!;!,!;!;;m12=0"; //pixels | ||
| 1560 | |||
| 1561 | |||
| 1562 | /* | ||
| 1563 | * Tricolor chase function | ||
| 1564 | */ | ||
| 1565 | 23 | uint16_t tricolor_chase(uint32_t color1, uint32_t color2) { | |
| 1566 | 23 | uint32_t cycleTime = 50 + ((255 - SEGMENT.speed)<<1); | |
| 1567 | 23 | uint32_t it = strip().now / cycleTime; // iterator | |
| 1568 | 23 | unsigned width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour | |
| 1569 | 23 | unsigned index = it % (width*3); | |
| 1570 | |||
| 1571 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++, index++) { |
| 1572 |
2/2✓ Branch 0 taken 845 times.
✓ Branch 1 taken 6666 times.
|
7511 | if (index > (width*3)-1) index = 0; |
| 1573 | |||
| 1574 | 7511 | uint32_t color = color1; | |
| 1575 |
4/6✓ Branch 0 taken 2461 times.
✓ Branch 1 taken 5050 times.
✓ Branch 2 taken 2461 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2461 times.
|
7511 | if (index > (width<<1)-1) color = SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1); |
| 1576 |
2/2✓ Branch 0 taken 2553 times.
✓ Branch 1 taken 2497 times.
|
5050 | else if (index > width-1) color = color2; |
| 1577 | |||
| 1578 | 7511 | SEGMENT.setPixelColor(SEGLEN - i -1, color); | |
| 1579 | } | ||
| 1580 | 23 | return FRAMETIME; | |
| 1581 | } | ||
| 1582 | |||
| 1583 | |||
| 1584 | /* | ||
| 1585 | * Tricolor chase mode | ||
| 1586 | */ | ||
| 1587 | 23 | uint16_t mode_tricolor_chase(void) { | |
| 1588 | 23 | return tricolor_chase(SEGCOLOR(2), SEGCOLOR(0)); | |
| 1589 | } | ||
| 1590 | static const char _data_FX_MODE_TRICOLOR_CHASE[] PROGMEM = "Chase 3@!,Size;1,2,3;!"; | ||
| 1591 | |||
| 1592 | |||
| 1593 | /* | ||
| 1594 | * ICU mode | ||
| 1595 | */ | ||
| 1596 | 23 | uint16_t mode_icu(void) { | |
| 1597 | 23 | unsigned dest = SEGENV.step & 0xFFFF; | |
| 1598 | 23 | unsigned space = (SEGMENT.intensity >> 3) +2; | |
| 1599 | |||
| 1600 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); |
| 1601 | |||
| 1602 | 23 | byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255); | |
| 1603 | 23 | uint32_t col = SEGMENT.color_from_palette(pindex, false, false, 0); | |
| 1604 | |||
| 1605 | 23 | SEGMENT.setPixelColor(dest, col); | |
| 1606 | 23 | SEGMENT.setPixelColor(dest + SEGLEN/space, col); | |
| 1607 | |||
| 1608 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if(SEGENV.aux0 == dest) { // pause between eye movements |
| 1609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if(hw_random8(6) == 0) { // blink once in a while |
| 1610 | ✗ | SEGMENT.setPixelColor(dest, SEGCOLOR(1)); | |
| 1611 | ✗ | SEGMENT.setPixelColor(dest + SEGLEN/space, SEGCOLOR(1)); | |
| 1612 | ✗ | return 200; | |
| 1613 | } | ||
| 1614 | 5 | SEGENV.aux0 = hw_random16(SEGLEN-SEGLEN/space); | |
| 1615 | 5 | return 1000 + hw_random16(2000); | |
| 1616 | } | ||
| 1617 | |||
| 1618 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | if(SEGENV.aux0 > SEGENV.step) { |
| 1619 | 18 | SEGENV.step++; | |
| 1620 | 18 | dest++; | |
| 1621 | ✗ | } else if (SEGENV.aux0 < SEGENV.step) { | |
| 1622 | ✗ | SEGENV.step--; | |
| 1623 | ✗ | dest--; | |
| 1624 | } | ||
| 1625 | |||
| 1626 | 18 | SEGMENT.setPixelColor(dest, col); | |
| 1627 | 18 | SEGMENT.setPixelColor(dest + SEGLEN/space, col); | |
| 1628 | |||
| 1629 | 18 | return SPEED_FORMULA_L; | |
| 1630 | } | ||
| 1631 | static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!,,,,,Overlay;!,!;!"; | ||
| 1632 | |||
| 1633 | |||
| 1634 | /* | ||
| 1635 | * Custom mode by Aircoookie. Color Wipe, but with 3 colors | ||
| 1636 | */ | ||
| 1637 | 23 | uint16_t mode_tricolor_wipe(void) { | |
| 1638 | 23 | uint32_t cycleTime = 1000 + (255 - SEGMENT.speed)*200; | |
| 1639 | 23 | uint32_t perc = strip().now % cycleTime; | |
| 1640 | 23 | unsigned prog = (perc * 65535) / cycleTime; | |
| 1641 | 23 | unsigned ledIndex = (prog * SEGLEN * 3) >> 16; | |
| 1642 | 23 | unsigned ledOffset = ledIndex; | |
| 1643 | |||
| 1644 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) |
| 1645 | { | ||
| 1646 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2)); |
| 1647 | } | ||
| 1648 | |||
| 1649 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | if(ledIndex < SEGLEN) { //wipe from 0 to 1 |
| 1650 |
2/2✓ Branch 0 taken 2391 times.
✓ Branch 1 taken 13 times.
|
2404 | for (unsigned i = 0; i < SEGLEN; i++) |
| 1651 | { | ||
| 1652 |
2/2✓ Branch 0 taken 983 times.
✓ Branch 1 taken 1408 times.
|
2391 | SEGMENT.setPixelColor(i, (i > ledOffset)? SEGCOLOR(0) : SEGCOLOR(1)); |
| 1653 | } | ||
| 1654 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | } else if (ledIndex < SEGLEN*2) { //wipe from 1 to 2 |
| 1655 | 5 | ledOffset = ledIndex - SEGLEN; | |
| 1656 |
2/2✓ Branch 0 taken 1304 times.
✓ Branch 1 taken 5 times.
|
1309 | for (unsigned i = ledOffset +1; i < SEGLEN; i++) |
| 1657 | { | ||
| 1658 | 1304 | SEGMENT.setPixelColor(i, SEGCOLOR(1)); | |
| 1659 | } | ||
| 1660 | } else //wipe from 2 to 0 | ||
| 1661 | { | ||
| 1662 | 5 | ledOffset = ledIndex - SEGLEN*2; | |
| 1663 |
2/2✓ Branch 0 taken 2474 times.
✓ Branch 1 taken 5 times.
|
2479 | for (unsigned i = 0; i <= ledOffset; i++) |
| 1664 | { | ||
| 1665 | 2474 | SEGMENT.setPixelColor(i, SEGCOLOR(0)); | |
| 1666 | } | ||
| 1667 | } | ||
| 1668 | |||
| 1669 | 23 | return FRAMETIME; | |
| 1670 | } | ||
| 1671 | static const char _data_FX_MODE_TRICOLOR_WIPE[] PROGMEM = "Tri Wipe@!;1,2,3;!"; | ||
| 1672 | |||
| 1673 | |||
| 1674 | /* | ||
| 1675 | * Fades between 3 colors | ||
| 1676 | * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/TriFade.h | ||
| 1677 | * Modified by Aircoookie | ||
| 1678 | */ | ||
| 1679 | 23 | uint16_t mode_tricolor_fade(void) { | |
| 1680 | 23 | unsigned counter = strip().now * ((SEGMENT.speed >> 3) +1); | |
| 1681 | 23 | uint16_t prog = (counter * 768) >> 16; | |
| 1682 | |||
| 1683 | 23 | uint32_t color1 = 0, color2 = 0; | |
| 1684 | 23 | unsigned stage = 0; | |
| 1685 | |||
| 1686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if(prog < 256) { |
| 1687 | ✗ | color1 = SEGCOLOR(0); | |
| 1688 | ✗ | color2 = SEGCOLOR(1); | |
| 1689 | ✗ | stage = 0; | |
| 1690 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | } else if(prog < 512) { |
| 1691 | ✗ | color1 = SEGCOLOR(1); | |
| 1692 | ✗ | color2 = SEGCOLOR(2); | |
| 1693 | ✗ | stage = 1; | |
| 1694 | } else { | ||
| 1695 | 23 | color1 = SEGCOLOR(2); | |
| 1696 | 23 | color2 = SEGCOLOR(0); | |
| 1697 | 23 | stage = 2; | |
| 1698 | } | ||
| 1699 | |||
| 1700 | 23 | byte stp = prog; // % 256 | |
| 1701 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 1702 | uint32_t color; | ||
| 1703 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
7511 | if (stage == 2) { |
| 1704 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | color = color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), color2, stp); |
| 1705 | ✗ | } else if (stage == 1) { | |
| 1706 | ✗ | color = color_blend(color1, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), stp); | |
| 1707 | } else { | ||
| 1708 | ✗ | color = color_blend(color1, color2, stp); | |
| 1709 | } | ||
| 1710 | 7511 | SEGMENT.setPixelColor(i, color); | |
| 1711 | } | ||
| 1712 | |||
| 1713 | 23 | return FRAMETIME; | |
| 1714 | } | ||
| 1715 | static const char _data_FX_MODE_TRICOLOR_FADE[] PROGMEM = "Tri Fade@!;1,2,3;!"; | ||
| 1716 | |||
| 1717 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 1718 | /* | ||
| 1719 | * Creates random comets | ||
| 1720 | * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h | ||
| 1721 | */ | ||
| 1722 | #define MAX_COMETS 8 | ||
| 1723 | 23 | uint16_t mode_multi_comet(void) { | |
| 1724 | 23 | uint32_t cycleTime = 10 + (uint32_t)(255 - SEGMENT.speed); | |
| 1725 | 23 | uint32_t it = strip().now / cycleTime; | |
| 1726 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 13 times.
|
23 | if (SEGENV.step == it) return FRAMETIME; |
| 1727 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (!SEGENV.allocateData(sizeof(uint16_t) * MAX_COMETS)) return mode_static(); //allocation failed |
| 1728 | |||
| 1729 | 13 | SEGMENT.fade_out(SEGMENT.intensity/2 + 128); | |
| 1730 | |||
| 1731 | 13 | uint16_t* comets = reinterpret_cast<uint16_t*>(SEGENV.data); | |
| 1732 | |||
| 1733 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 13 times.
|
117 | for (unsigned i=0; i < MAX_COMETS; i++) { |
| 1734 |
1/2✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
|
104 | if(comets[i] < SEGLEN) { |
| 1735 | 104 | unsigned index = comets[i]; | |
| 1736 |
1/2✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
|
104 | if (SEGCOLOR(2) != 0) |
| 1737 | { | ||
| 1738 |
4/6✓ Branch 0 taken 52 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 52 times.
|
104 | SEGMENT.setPixelColor(index, i % 2 ? SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(2)); |
| 1739 | } else | ||
| 1740 | { | ||
| 1741 | ✗ | SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); | |
| 1742 | } | ||
| 1743 | 104 | comets[i]++; | |
| 1744 | } else { | ||
| 1745 | ✗ | if(!hw_random16(SEGLEN)) { | |
| 1746 | ✗ | comets[i] = 0; | |
| 1747 | } | ||
| 1748 | } | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | 13 | SEGENV.step = it; | |
| 1752 | 13 | return FRAMETIME; | |
| 1753 | } | ||
| 1754 | static const char _data_FX_MODE_MULTI_COMET[] PROGMEM = "Multi Comet@!,Fade;!,!;!;1"; | ||
| 1755 | #undef MAX_COMETS | ||
| 1756 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 1757 | |||
| 1758 | /* | ||
| 1759 | * Running random pixels ("Stream 2") | ||
| 1760 | * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/RandomChase.h | ||
| 1761 | */ | ||
| 1762 | 23 | uint16_t mode_random_chase(void) { | |
| 1763 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 1764 | 5 | SEGENV.step = RGBW32(random8(), random8(), random8(), 0); | |
| 1765 | 5 | SEGENV.aux0 = random16(); | |
| 1766 | } | ||
| 1767 | 23 | unsigned prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function | |
| 1768 | 23 | uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed)); | |
| 1769 | 23 | uint32_t it = strip().now / cycleTime; | |
| 1770 | 23 | uint32_t color = SEGENV.step; | |
| 1771 | 23 | random16_set_seed(SEGENV.aux0); | |
| 1772 | |||
| 1773 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (int i = SEGLEN -1; i >= 0; i--) { |
| 1774 |
2/2✓ Branch 0 taken 6403 times.
✓ Branch 1 taken 1108 times.
|
7511 | uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8(); |
| 1775 |
2/2✓ Branch 0 taken 6221 times.
✓ Branch 1 taken 1290 times.
|
7511 | uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8(); |
| 1776 |
2/2✓ Branch 0 taken 6186 times.
✓ Branch 1 taken 1325 times.
|
7511 | uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8(); |
| 1777 | 7511 | color = RGBW32(r, g, b, 0); | |
| 1778 | 7511 | SEGMENT.setPixelColor(i, color); | |
| 1779 |
6/6✓ Branch 0 taken 23 times.
✓ Branch 1 taken 7488 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 7503 times.
|
7511 | if (i == SEGLEN -1U && SEGENV.aux1 != (it & 0xFFFFU)) { //new first color in next frame |
| 1780 | 8 | SEGENV.step = color; | |
| 1781 | 8 | SEGENV.aux0 = random16_get_seed(); | |
| 1782 | } | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | 23 | SEGENV.aux1 = it & 0xFFFF; | |
| 1786 | |||
| 1787 | 23 | random16_set_seed(prevSeed); // restore original seed so other effects can use "random" PRNG | |
| 1788 | 23 | return FRAMETIME; | |
| 1789 | } | ||
| 1790 | static const char _data_FX_MODE_RANDOM_CHASE[] PROGMEM = "Stream 2@!;;"; | ||
| 1791 | |||
| 1792 | |||
| 1793 | //7 bytes | ||
| 1794 | typedef struct Oscillator { | ||
| 1795 | uint16_t pos; | ||
| 1796 | uint8_t size; | ||
| 1797 | int8_t dir; | ||
| 1798 | uint8_t speed; | ||
| 1799 | } oscillator; | ||
| 1800 | |||
| 1801 | /* | ||
| 1802 | / Oscillating bars of color, updated with standard framerate | ||
| 1803 | */ | ||
| 1804 | 23 | uint16_t mode_oscillate(void) { | |
| 1805 | 23 | constexpr unsigned numOscillators = 3; | |
| 1806 | 23 | constexpr unsigned dataSize = sizeof(oscillator) * numOscillators; | |
| 1807 | |||
| 1808 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 1809 | |||
| 1810 | 23 | Oscillator* oscillators = reinterpret_cast<Oscillator*>(SEGENV.data); | |
| 1811 | |||
| 1812 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) |
| 1813 | { | ||
| 1814 | 5 | oscillators[0] = {(uint16_t)(SEGLEN/4), (uint8_t)(SEGLEN/8), 1, 1}; | |
| 1815 | 5 | oscillators[1] = {(uint16_t)(SEGLEN/4*3), (uint8_t)(SEGLEN/8), 1, 2}; | |
| 1816 | 5 | oscillators[2] = {(uint16_t)(SEGLEN/4*2), (uint8_t)(SEGLEN/8), -1, 1}; | |
| 1817 | } | ||
| 1818 | |||
| 1819 | 23 | uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed)); | |
| 1820 | 23 | uint32_t it = strip().now / cycleTime; | |
| 1821 | |||
| 1822 |
2/2✓ Branch 0 taken 69 times.
✓ Branch 1 taken 23 times.
|
92 | for (unsigned i = 0; i < numOscillators; i++) { |
| 1823 | // if the counter has increased, move the oscillator by the random step | ||
| 1824 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 39 times.
|
69 | if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed; |
| 1825 | 69 | oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8); | |
| 1826 |
4/6✓ Branch 0 taken 23 times.
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 69 times.
|
69 | if((oscillators[i].dir == -1) && (oscillators[i].pos > SEGLEN << 1)) { // use integer overflow |
| 1827 | ✗ | oscillators[i].pos = 0; | |
| 1828 | ✗ | oscillators[i].dir = 1; | |
| 1829 | // make bigger steps for faster speeds | ||
| 1830 | ✗ | oscillators[i].speed = SEGMENT.speed > 100 ? hw_random8(2, 4):hw_random8(1, 3); | |
| 1831 | } | ||
| 1832 |
4/6✓ Branch 0 taken 46 times.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 69 times.
|
69 | if((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGLEN - 1))) { |
| 1833 | ✗ | oscillators[i].pos = SEGLEN - 1; | |
| 1834 | ✗ | oscillators[i].dir = -1; | |
| 1835 | ✗ | oscillators[i].speed = SEGMENT.speed > 100 ? hw_random8(2, 4):hw_random8(1, 3); | |
| 1836 | } | ||
| 1837 | } | ||
| 1838 | |||
| 1839 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 1840 | 7511 | uint32_t color = BLACK; | |
| 1841 |
2/2✓ Branch 0 taken 22533 times.
✓ Branch 1 taken 7511 times.
|
30044 | for (unsigned j = 0; j < numOscillators; j++) { |
| 1842 |
4/4✓ Branch 0 taken 13783 times.
✓ Branch 1 taken 8750 times.
✓ Branch 2 taken 5185 times.
✓ Branch 3 taken 8598 times.
|
22533 | if((int)i >= (int)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { |
| 1843 |
2/2✓ Branch 0 taken 3485 times.
✓ Branch 1 taken 1700 times.
|
5185 | color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128)); |
| 1844 | } | ||
| 1845 | } | ||
| 1846 | 7511 | SEGMENT.setPixelColor(i, color); | |
| 1847 | } | ||
| 1848 | |||
| 1849 | 23 | SEGENV.step = it; | |
| 1850 | 23 | return FRAMETIME; | |
| 1851 | } | ||
| 1852 | static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate"; | ||
| 1853 | |||
| 1854 | |||
| 1855 | //TODO | ||
| 1856 | 23 | uint16_t mode_lightning(void) { | |
| 1857 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1858 | 23 | unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash | |
| 1859 | 23 | unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) | |
| 1860 | 23 | uint8_t bri = 255/hw_random8(1, 3); | |
| 1861 | |||
| 1862 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.aux1 == 0) //init, leader flash |
| 1863 | { | ||
| 1864 | 5 | SEGENV.aux1 = hw_random8(4, 4 + SEGMENT.intensity/20); //number of flashes | |
| 1865 | 5 | SEGENV.aux1 *= 2; | |
| 1866 | |||
| 1867 | 5 | bri = 52; //leader has lower brightness | |
| 1868 | 5 | SEGENV.aux0 = 200; //200ms delay after leader | |
| 1869 | } | ||
| 1870 | |||
| 1871 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); |
| 1872 | |||
| 1873 |
5/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2 |
| 1874 |
2/2✓ Branch 0 taken 183 times.
✓ Branch 1 taken 5 times.
|
188 | for (unsigned i = ledstart; i < ledstart + ledlen; i++) |
| 1875 | { | ||
| 1876 |
2/4✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
|
183 | SEGMENT.setPixelColor(i,SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri)); |
| 1877 | } | ||
| 1878 | 5 | SEGENV.aux1--; | |
| 1879 | |||
| 1880 | 5 | SEGENV.step = strip().now; | |
| 1881 | //return hw_random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds | ||
| 1882 | } else { | ||
| 1883 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (strip().now - SEGENV.step > SEGENV.aux0) { |
| 1884 | ✗ | SEGENV.aux1--; | |
| 1885 | ✗ | if (SEGENV.aux1 < 2) SEGENV.aux1 = 0; | |
| 1886 | |||
| 1887 | ✗ | SEGENV.aux0 = (50 + hw_random8(100)); //delay between flashes | |
| 1888 | ✗ | if (SEGENV.aux1 == 2) { | |
| 1889 | ✗ | SEGENV.aux0 = (hw_random8(255 - SEGMENT.speed) * 100); // delay between strikes | |
| 1890 | } | ||
| 1891 | ✗ | SEGENV.step = strip().now; | |
| 1892 | } | ||
| 1893 | } | ||
| 1894 | 23 | return FRAMETIME; | |
| 1895 | } | ||
| 1896 | static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!"; | ||
| 1897 | |||
| 1898 | // combined function from original pride and colorwaves | ||
| 1899 | 46 | uint16_t mode_colorwaves_pride_base(bool isPride2015) { | |
| 1900 | 46 | unsigned duration = 10 + SEGMENT.speed; | |
| 1901 | 46 | unsigned sPseudotime = SEGENV.step; | |
| 1902 | 46 | unsigned sHue16 = SEGENV.aux0; | |
| 1903 | |||
| 1904 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | uint8_t sat8 = isPride2015 ? beatsin88_t(87, 220, 250) : 255; |
| 1905 | 46 | unsigned brightdepth = beatsin88_t(341, 96, 224); | |
| 1906 | 46 | unsigned brightnessthetainc16 = beatsin88_t(203, (25 * 256), (40 * 256)); | |
| 1907 | 46 | unsigned msmultiplier = beatsin88_t(147, 23, 60); | |
| 1908 | |||
| 1909 | 46 | unsigned hue16 = sHue16; | |
| 1910 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | unsigned hueinc16 = isPride2015 ? beatsin88_t(113, 1, 3000) : |
| 1911 | 23 | beatsin88_t(113, 60, 300) * SEGMENT.intensity * 10 / 255; | |
| 1912 | |||
| 1913 | 46 | sPseudotime += duration * msmultiplier; | |
| 1914 | 46 | sHue16 += duration * beatsin88_t(400, 5, 9); | |
| 1915 | 46 | unsigned brightnesstheta16 = sPseudotime; | |
| 1916 | |||
| 1917 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 46 times.
|
15068 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 1918 | 15022 | hue16 += hueinc16; | |
| 1919 | uint8_t hue8; | ||
| 1920 | |||
| 1921 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 7511 times.
|
15022 | if (isPride2015) { |
| 1922 | 7511 | hue8 = hue16 >> 8; | |
| 1923 | } else { | ||
| 1924 | 7511 | unsigned h16_128 = hue16 >> 7; | |
| 1925 |
2/2✓ Branch 0 taken 2489 times.
✓ Branch 1 taken 5022 times.
|
7511 | hue8 = (h16_128 & 0x100) ? (255 - (h16_128 >> 1)) : (h16_128 >> 1); |
| 1926 | } | ||
| 1927 | |||
| 1928 | 15022 | brightnesstheta16 += brightnessthetainc16; | |
| 1929 | 15022 | unsigned b16 = sin16_t(brightnesstheta16) + 32768; | |
| 1930 | 15022 | unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; | |
| 1931 | 15022 | uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; | |
| 1932 | 15022 | bri8 += (255 - brightdepth); | |
| 1933 | |||
| 1934 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 7511 times.
|
15022 | if (isPride2015) { |
| 1935 | 7511 | CRGB newcolor = CHSV(hue8, sat8, bri8); | |
| 1936 |
3/6✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
|
7511 | SEGMENT.blendPixelColor(i, newcolor, 64); |
| 1937 | } else { | ||
| 1938 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.blendPixelColor(i, SEGMENT.color_from_palette(hue8, false, PALETTE_SOLID_WRAP, 0, bri8), 128); |
| 1939 | } | ||
| 1940 | } | ||
| 1941 | |||
| 1942 | 46 | SEGENV.step = sPseudotime; | |
| 1943 | 46 | SEGENV.aux0 = sHue16; | |
| 1944 | |||
| 1945 | 46 | return FRAMETIME; | |
| 1946 | } | ||
| 1947 | |||
| 1948 | // Pride2015 | ||
| 1949 | // Animated, ever-changing rainbows. | ||
| 1950 | // by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 | ||
| 1951 | 23 | uint16_t mode_pride_2015(void) { | |
| 1952 | 23 | return mode_colorwaves_pride_base(true); | |
| 1953 | } | ||
| 1954 | static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; | ||
| 1955 | |||
| 1956 | // ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb | ||
| 1957 | // This function draws color waves with an ever-changing, | ||
| 1958 | // widely-varying set of parameters, using a color palette. | ||
| 1959 | 23 | uint16_t mode_colorwaves() { | |
| 1960 | 23 | return mode_colorwaves_pride_base(false); | |
| 1961 | } | ||
| 1962 | static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!;;pal=26"; | ||
| 1963 | |||
| 1964 | |||
| 1965 | //eight colored dots, weaving in and out of sync with each other | ||
| 1966 | 23 | uint16_t mode_juggle(void) { | |
| 1967 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 1968 | |||
| 1969 |
5/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
|
23 | SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4)); |
| 1970 | CRGB fastled_col; | ||
| 1971 | 23 | byte dothue = 0; | |
| 1972 |
2/2✓ Branch 0 taken 184 times.
✓ Branch 1 taken 23 times.
|
207 | for (int i = 0; i < 8; i++) { |
| 1973 |
3/6✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 184 times.
✗ Branch 5 not taken.
|
184 | int index = 0 + beatsin88_t((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); |
| 1974 |
3/6✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 184 times.
✗ Branch 5 not taken.
|
184 | fastled_col = CRGB(SEGMENT.getPixelColor(index)); |
| 1975 |
3/8✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 184 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
184 | fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):CRGB(ColorFromPalette(SEGPALETTE, dothue, 255)); |
| 1976 |
3/6✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 184 times.
✗ Branch 5 not taken.
|
184 | SEGMENT.setPixelColor(index, fastled_col); |
| 1977 | 184 | dothue += 32; | |
| 1978 | } | ||
| 1979 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 1980 | } | ||
| 1981 | static const char _data_FX_MODE_JUGGLE[] PROGMEM = "Juggle@!,Trail;;!;;sx=64,ix=128"; | ||
| 1982 | |||
| 1983 | |||
| 1984 | 174 | uint16_t mode_palette() { | |
| 1985 | // Set up some compile time constants so that we can handle integer and float based modes using the same code base. | ||
| 1986 | #ifdef ESP8266 | ||
| 1987 | using mathType = int32_t; | ||
| 1988 | using wideMathType = int64_t; | ||
| 1989 | using angleType = unsigned; | ||
| 1990 | constexpr mathType sInt16Scale = 0x7FFF; | ||
| 1991 | constexpr mathType maxAngle = 0x8000; | ||
| 1992 | constexpr mathType staticRotationScale = 256; | ||
| 1993 | constexpr mathType animatedRotationScale = 1; | ||
| 1994 | constexpr int16_t (*sinFunction)(uint16_t) = &sin16_t; | ||
| 1995 | constexpr int16_t (*cosFunction)(uint16_t) = &cos16_t; | ||
| 1996 | #else | ||
| 1997 | using mathType = float; | ||
| 1998 | using wideMathType = float; | ||
| 1999 | using angleType = float; | ||
| 2000 | 174 | constexpr mathType sInt16Scale = 1.0f; | |
| 2001 | 174 | constexpr mathType maxAngle = M_PI / 256.0; | |
| 2002 | 174 | constexpr mathType staticRotationScale = 1.0f; | |
| 2003 | 174 | constexpr mathType animatedRotationScale = M_TWOPI / double(0xFFFF); | |
| 2004 | 174 | constexpr float (*sinFunction)(float) = &sin_t; | |
| 2005 | 174 | constexpr float (*cosFunction)(float) = &cos_t; | |
| 2006 | #endif | ||
| 2007 | 174 | const bool isMatrix = strip().isMatrix; | |
| 2008 | 174 | const int cols = SEG_W; | |
| 2009 |
2/2✓ Branch 0 taken 169 times.
✓ Branch 1 taken 5 times.
|
174 | const int rows = isMatrix ? SEG_H : strip().getActiveSegmentsNum(); |
| 2010 | |||
| 2011 | 174 | const int inputShift = SEGMENT.speed; | |
| 2012 | 174 | const int inputSize = SEGMENT.intensity; | |
| 2013 | 174 | const int inputRotation = SEGMENT.custom1; | |
| 2014 | 174 | const bool inputAnimateShift = SEGMENT.check1; | |
| 2015 | 174 | const bool inputAnimateRotation = SEGMENT.check2; | |
| 2016 | 174 | const bool inputAssumeSquare = SEGMENT.check3; | |
| 2017 | |||
| 2018 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | const angleType theta = (!inputAnimateRotation) ? ((inputRotation + 128) * maxAngle / staticRotationScale) : (((strip().now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); |
| 2019 | 174 | const mathType sinTheta = sinFunction(theta); | |
| 2020 | 174 | const mathType cosTheta = cosFunction(theta); | |
| 2021 | |||
| 2022 | 174 | const mathType maxX = std::max(1, cols-1); | |
| 2023 | 174 | const mathType maxY = std::max(1, rows-1); | |
| 2024 | // Set up some parameters according to inputAssumeSquare, so that we can handle anamorphic mode using the same code base. | ||
| 2025 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | const mathType maxXIn = inputAssumeSquare ? maxX : mathType(1); |
| 2026 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | const mathType maxYIn = inputAssumeSquare ? maxY : mathType(1); |
| 2027 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | const mathType maxXOut = !inputAssumeSquare ? maxX : mathType(1); |
| 2028 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | const mathType maxYOut = !inputAssumeSquare ? maxY : mathType(1); |
| 2029 | 174 | const mathType centerX = sInt16Scale * maxXOut / mathType(2); | |
| 2030 | 174 | const mathType centerY = sInt16Scale * maxYOut / mathType(2); | |
| 2031 | // The basic idea for this effect is to rotate a rectangle that is filled with the palette along one axis, then map our | ||
| 2032 | // display to it, to find what color a pixel should have. | ||
| 2033 | // However, we want a) no areas of solid color (in front of or behind the palette), and b) we want to make use of the full palette. | ||
| 2034 | // So the rectangle needs to have exactly the right size. That size depends on the rotation. | ||
| 2035 | // This scale computation here only considers one dimension. You can think of it like the rectangle is always scaled so that | ||
| 2036 | // the left and right most points always match the left and right side of the display. | ||
| 2037 | 174 | const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); | |
| 2038 | // 2D simulation: | ||
| 2039 | // If we are dealing with a 1D setup, we assume that each segment represents one line on a 2-dimensional display. | ||
| 2040 | // The function is called once per segments, so we need to handle one line at a time. | ||
| 2041 |
2/2✓ Branch 0 taken 169 times.
✓ Branch 1 taken 5 times.
|
174 | const int yFrom = isMatrix ? 0 : strip().getCurrSegmentId(); |
| 2042 |
2/2✓ Branch 0 taken 169 times.
✓ Branch 1 taken 5 times.
|
174 | const int yTo = isMatrix ? maxY : yFrom; |
| 2043 |
2/2✓ Branch 0 taken 2644 times.
✓ Branch 1 taken 174 times.
|
2818 | for (int y = yFrom; y <= yTo; ++y) { |
| 2044 | // translate, scale, rotate | ||
| 2045 | 2644 | const mathType ytCosTheta = mathType((wideMathType(cosTheta) * wideMathType(y * sInt16Scale - centerY * maxYIn))/wideMathType(maxYIn * scale)); | |
| 2046 |
2/2✓ Branch 0 taken 84823 times.
✓ Branch 1 taken 2644 times.
|
87467 | for (int x = 0; x < cols; ++x) { |
| 2047 | // translate, scale, rotate | ||
| 2048 | 84823 | const mathType xtSinTheta = mathType((wideMathType(sinTheta) * wideMathType(x * sInt16Scale - centerX * maxXIn))/wideMathType(maxXIn * scale)); | |
| 2049 | // Map the pixel coordinate to an imaginary-rectangle-coordinate. | ||
| 2050 | // The y coordinate doesn't actually matter, as our imaginary rectangle is filled with the palette from left to right, | ||
| 2051 | // so all points at a given x-coordinate have the same color. | ||
| 2052 | 84823 | const mathType sourceX = xtSinTheta + ytCosTheta + centerX; | |
| 2053 | // The computation was scaled just right so that the result should always be in range [0, maxXOut], but enforce this anyway | ||
| 2054 | // to account for imprecision. Then scale it so that the range is [0, 255], which we can use with the palette. | ||
| 2055 | 84823 | int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * wideMathType(255)) / (sInt16Scale * maxXOut); | |
| 2056 | // inputSize determines by how much we want to scale the palette: | ||
| 2057 | // values < 128 display a fraction of a palette, | ||
| 2058 | // values > 128 display multiple palettes. | ||
| 2059 |
2/2✓ Branch 0 taken 82775 times.
✓ Branch 1 taken 2048 times.
|
84823 | if (inputSize <= 128) { |
| 2060 | 82775 | colorIndex = (colorIndex * inputSize) / 128; | |
| 2061 | } else { | ||
| 2062 | // Linear function that maps colorIndex 128=>1, 256=>9. | ||
| 2063 | // With this function every full palette repetition is exactly 16 configuration steps wide. | ||
| 2064 | // That allows displaying exactly 2 repetitions for example. | ||
| 2065 | 2048 | colorIndex = ((inputSize - 112) * colorIndex) / 16; | |
| 2066 | } | ||
| 2067 | // Finally, shift the palette a bit. | ||
| 2068 |
2/4✓ Branch 0 taken 84823 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84823 times.
✗ Branch 3 not taken.
|
84823 | const int paletteOffset = (!inputAnimateShift) ? (inputShift) : (((strip().now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); |
| 2069 | 84823 | colorIndex -= paletteOffset; | |
| 2070 |
3/6✓ Branch 0 taken 84823 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84823 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84823 times.
✗ Branch 5 not taken.
|
84823 | const uint32_t color = SEGMENT.color_wheel((uint8_t)colorIndex); |
| 2071 |
2/2✓ Branch 0 taken 84073 times.
✓ Branch 1 taken 750 times.
|
84823 | if (isMatrix) { |
| 2072 |
3/6✓ Branch 0 taken 84073 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84073 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84073 times.
✗ Branch 5 not taken.
|
84073 | SEGMENT.setPixelColorXY(x, y, color); |
| 2073 | } else { | ||
| 2074 |
3/6✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 750 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 750 times.
✗ Branch 5 not taken.
|
750 | SEGMENT.setPixelColor(x, color); |
| 2075 | } | ||
| 2076 | } | ||
| 2077 | } | ||
| 2078 | 174 | return FRAMETIME; | |
| 2079 | } | ||
| 2080 | static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;ix=112,c1=0,o1=1,o2=0,o3=1"; | ||
| 2081 | |||
| 2082 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 2083 | // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active | ||
| 2084 | // Fire2012 by Mark Kriegsman, July 2012 | ||
| 2085 | // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY | ||
| 2086 | //// | ||
| 2087 | // This basic one-dimensional 'fire' simulation works roughly as follows: | ||
| 2088 | // There's a underlying array of 'heat' cells, that model the temperature | ||
| 2089 | // at each point along the line. Every cycle through the simulation, | ||
| 2090 | // four steps are performed: | ||
| 2091 | // 1) All cells cool down a little bit, losing heat to the air | ||
| 2092 | // 2) The heat from each cell drifts 'up' and diffuses a little | ||
| 2093 | // 3) Sometimes randomly new 'sparks' of heat are added at the bottom | ||
| 2094 | // 4) The heat from each cell is rendered as a color into the leds array | ||
| 2095 | // The heat-to-color mapping uses a black-body radiation approximation. | ||
| 2096 | // | ||
| 2097 | // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). | ||
| 2098 | // | ||
| 2099 | // This simulation scales it self a bit depending on SEGLEN; it should look | ||
| 2100 | // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. | ||
| 2101 | // | ||
| 2102 | // I recommend running this simulation at anywhere from 30-100 frames per second, | ||
| 2103 | // meaning an interframe delay of about 10-35 milliseconds. | ||
| 2104 | // | ||
| 2105 | // Looks best on a high-density LED setup (60+ pixels/meter). | ||
| 2106 | // | ||
| 2107 | // | ||
| 2108 | // There are two main parameters you can play with to control the look and | ||
| 2109 | // feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used | ||
| 2110 | // in step 3 above) (Effect Intensity = Sparking). | ||
| 2111 | 23 | uint16_t mode_fire_2012() { | |
| 2112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2113 | 23 | const unsigned strips = SEGMENT.nrOfVStrips(); | |
| 2114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed |
| 2115 | 23 | byte* heat = SEGENV.data; | |
| 2116 | |||
| 2117 | 23 | const uint32_t it = strip().now >> 5; //div 32 | |
| 2118 | |||
| 2119 | struct virtualStrip { | ||
| 2120 | 456 | static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) { | |
| 2121 | |||
| 2122 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 451 times.
|
456 | const uint8_t ignition = MAX(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels |
| 2123 | |||
| 2124 | // Step 1. Cool down every cell a little | ||
| 2125 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 456 times.
|
7967 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2126 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
7511 | uint8_t cool = (it != SEGENV.step) ? hw_random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : hw_random8(4); |
| 2127 |
2/2✓ Branch 0 taken 1428 times.
✓ Branch 1 taken 6083 times.
|
7511 | uint8_t minTemp = (i<ignition) ? (ignition-i)/4 + 16 : 0; // should not become black in ignition area |
| 2128 |
2/2✓ Branch 0 taken 6000 times.
✓ Branch 1 taken 1511 times.
|
7511 | uint8_t temp = qsub8(heat[i], cool); |
| 2129 |
2/2✓ Branch 0 taken 1015 times.
✓ Branch 1 taken 6496 times.
|
7511 | heat[i] = temp<minTemp ? minTemp : temp; |
| 2130 | } | ||
| 2131 | |||
| 2132 |
1/2✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
|
456 | if (it != SEGENV.step) { |
| 2133 | // Step 2. Heat from each cell drifts 'up' and diffuses a little | ||
| 2134 |
2/2✓ Branch 0 taken 6599 times.
✓ Branch 1 taken 456 times.
|
7055 | for (int k = SEGLEN -1; k > 1; k--) { |
| 2135 | 6599 | heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3; // heat[k-2] multiplied by 2 | |
| 2136 | } | ||
| 2137 | |||
| 2138 | // Step 3. Randomly ignite new 'sparks' of heat near the bottom | ||
| 2139 |
2/2✓ Branch 0 taken 261 times.
✓ Branch 1 taken 195 times.
|
456 | if (hw_random8() <= SEGMENT.intensity) { |
| 2140 | 261 | uint8_t y = hw_random8(ignition); | |
| 2141 | 261 | uint8_t boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math! | |
| 2142 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 157 times.
|
522 | heat[y] = qadd8(heat[y], hw_random8(96+2*boost,207+boost)); |
| 2143 | } | ||
| 2144 | } | ||
| 2145 | |||
| 2146 | // Step 4. Map from heat cells to LED colors | ||
| 2147 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 456 times.
|
7967 | for (unsigned j = 0; j < SEGLEN; j++) { |
| 2148 | 7511 | SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j], byte(240)), 255, NOBLEND)); | |
| 2149 | } | ||
| 2150 | 456 | } | |
| 2151 | }; | ||
| 2152 | |||
| 2153 |
2/2✓ Branch 0 taken 456 times.
✓ Branch 1 taken 23 times.
|
479 | for (unsigned stripNr=0; stripNr<strips; stripNr++) |
| 2154 | 456 | virtualStrip::runStrip(stripNr, &heat[stripNr * SEGLEN], it); | |
| 2155 | |||
| 2156 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
|
23 | if (SEGMENT.is2D()) { |
| 2157 | 18 | uint8_t blurAmount = SEGMENT.custom2 >> 2; | |
| 2158 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (blurAmount > 48) blurAmount += blurAmount-48; // extra blur when slider > 192 (bush burn) |
| 2159 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (blurAmount < 16) SEGMENT.blurCols(SEGMENT.custom2 >> 1); // no side-burn when slider < 64 (faster) |
| 2160 | 14 | else SEGMENT.blur(blurAmount); | |
| 2161 | } | ||
| 2162 | |||
| 2163 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (it != SEGENV.step) |
| 2164 | 23 | SEGENV.step = it; | |
| 2165 | |||
| 2166 | 23 | return FRAMETIME; | |
| 2167 | } | ||
| 2168 | static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;pal=35,sx=64,ix=160,m12=1,c2=128"; // bars | ||
| 2169 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 2170 | |||
| 2171 | // colored stripes pulsing at a defined Beats-Per-Minute (BPM) | ||
| 2172 | 23 | uint16_t mode_bpm() { | |
| 2173 | 23 | uint32_t stp = (strip().now / 20) & 0xFF; | |
| 2174 | 23 | uint8_t beat = beatsin8_t(SEGMENT.speed, 64, 255); | |
| 2175 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2176 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); |
| 2177 | } | ||
| 2178 | |||
| 2179 | 23 | return FRAMETIME; | |
| 2180 | } | ||
| 2181 | static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64"; | ||
| 2182 | |||
| 2183 | |||
| 2184 | 23 | uint16_t mode_fillnoise8() { | |
| 2185 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) SEGENV.step = hw_random(); |
| 2186 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2187 | 7511 | unsigned index = perlin8(i * SEGLEN, SEGENV.step + i * SEGLEN); | |
| 2188 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 2189 | } | ||
| 2190 | 23 | SEGENV.step += beatsin8_t(SEGMENT.speed, 1, 6); //10,1,4 | |
| 2191 | |||
| 2192 | 23 | return FRAMETIME; | |
| 2193 | } | ||
| 2194 | static const char _data_FX_MODE_FILLNOISE8[] PROGMEM = "Fill Noise@!;!;!"; | ||
| 2195 | |||
| 2196 | |||
| 2197 | 23 | uint16_t mode_noise16_1() { | |
| 2198 | 23 | unsigned scale = 320; // the "zoom factor" for the noise | |
| 2199 | 23 | SEGENV.step += (1 + SEGMENT.speed/16); | |
| 2200 | |||
| 2201 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2202 | 7511 | unsigned shift_x = beatsin8_t(11); // the x position of the noise field swings @ 17 bpm | |
| 2203 | 7511 | unsigned shift_y = SEGENV.step/42; // the y position becomes slowly incremented | |
| 2204 | 7511 | unsigned real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm | |
| 2205 | 7511 | unsigned real_y = (i + shift_y) * scale; // the y position becomes slowly incremented | |
| 2206 | 7511 | uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented | |
| 2207 | 7511 | unsigned noise = perlin16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down | |
| 2208 | 7511 | unsigned index = sin8_t(noise * 3); // map LED color based on noise data | |
| 2209 | |||
| 2210 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 2211 | } | ||
| 2212 | |||
| 2213 | 23 | return FRAMETIME; | |
| 2214 | } | ||
| 2215 | static const char _data_FX_MODE_NOISE16_1[] PROGMEM = "Noise 1@!;!;!;;pal=20"; | ||
| 2216 | |||
| 2217 | |||
| 2218 | 23 | uint16_t mode_noise16_2() { | |
| 2219 | 23 | unsigned scale = 1000; // the "zoom factor" for the noise | |
| 2220 | 23 | SEGENV.step += (1 + (SEGMENT.speed >> 1)); | |
| 2221 | |||
| 2222 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2223 | 7511 | unsigned shift_x = SEGENV.step >> 6; // x as a function of time | |
| 2224 | 7511 | uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field | |
| 2225 | 7511 | unsigned noise = perlin16(real_x, 0, 4223) >> 8; // get the noise data and scale it down | |
| 2226 | 7511 | unsigned index = sin8_t(noise * 3); // map led color based on noise data | |
| 2227 | |||
| 2228 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); |
| 2229 | } | ||
| 2230 | |||
| 2231 | 23 | return FRAMETIME; | |
| 2232 | } | ||
| 2233 | static const char _data_FX_MODE_NOISE16_2[] PROGMEM = "Noise 2@!;!;!;;pal=43"; | ||
| 2234 | |||
| 2235 | |||
| 2236 | 23 | uint16_t mode_noise16_3() { | |
| 2237 | 23 | unsigned scale = 800; // the "zoom factor" for the noise | |
| 2238 | 23 | SEGENV.step += (1 + SEGMENT.speed); | |
| 2239 | |||
| 2240 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2241 | 7511 | unsigned shift_x = 4223; // no movement along x and y | |
| 2242 | 7511 | unsigned shift_y = 1234; | |
| 2243 | 7511 | uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field | |
| 2244 | 7511 | uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions | |
| 2245 | 7511 | uint32_t real_z = SEGENV.step*8; | |
| 2246 | 7511 | unsigned noise = perlin16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down | |
| 2247 | 7511 | unsigned index = sin8_t(noise * 3); // map led color based on noise data | |
| 2248 | |||
| 2249 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); |
| 2250 | } | ||
| 2251 | |||
| 2252 | 23 | return FRAMETIME; | |
| 2253 | } | ||
| 2254 | static const char _data_FX_MODE_NOISE16_3[] PROGMEM = "Noise 3@!;!;!;;pal=35"; | ||
| 2255 | |||
| 2256 | |||
| 2257 | //https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip().ino | ||
| 2258 | 23 | uint16_t mode_noise16_4() { | |
| 2259 | 23 | uint32_t stp = (strip().now * SEGMENT.speed) >> 7; | |
| 2260 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2261 | 7511 | int index = perlin16(uint32_t(i) << 12, stp); | |
| 2262 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 2263 | } | ||
| 2264 | 23 | return FRAMETIME; | |
| 2265 | } | ||
| 2266 | static const char _data_FX_MODE_NOISE16_4[] PROGMEM = "Noise 4@!;!;!;;pal=26"; | ||
| 2267 | |||
| 2268 | |||
| 2269 | //based on https://gist.github.com/kriegsman/5408ecd397744ba0393e | ||
| 2270 | 23 | uint16_t mode_colortwinkle() { | |
| 2271 | 23 | unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED | |
| 2272 |
4/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 2273 | |||
| 2274 | CRGBW col, prev; | ||
| 2275 |
4/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
23 | fract8 fadeUpAmount = strip().getBrightness()>28 ? 8 + (SEGMENT.speed>>2) : 68-strip().getBrightness(); |
| 2276 |
4/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
23 | fract8 fadeDownAmount = strip().getBrightness()>28 ? 8 + (SEGMENT.speed>>3) : 68-strip().getBrightness(); |
| 2277 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2278 |
3/6✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
|
7511 | CRGBW cur = SEGMENT.getPixelColor(i); |
| 2279 | 7511 | prev = cur; | |
| 2280 | 7511 | unsigned index = i >> 3; | |
| 2281 | 7511 | unsigned bitNum = i & 0x07; | |
| 2282 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
|
7511 | bool fadeUp = bitRead(SEGENV.data[index], bitNum); |
| 2283 | |||
| 2284 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7511 times.
|
7511 | if (fadeUp) { |
| 2285 | ✗ | CRGBW incrementalColor = color_fade(cur, fadeUpAmount, true); | |
| 2286 | ✗ | col = color_add(cur, incrementalColor); | |
| 2287 | |||
| 2288 | ✗ | if (col.r == 255 || col.g == 255 || col.b == 255) { | |
| 2289 | ✗ | bitWrite(SEGENV.data[index], bitNum, false); | |
| 2290 | } | ||
| 2291 | |||
| 2292 | ✗ | if (cur == prev) { //fix "stuck" pixels | |
| 2293 | ✗ | color_add(col, col); | |
| 2294 | ✗ | SEGMENT.setPixelColor(i, col); | |
| 2295 | } | ||
| 2296 | ✗ | else SEGMENT.setPixelColor(i, col); | |
| 2297 | } | ||
| 2298 | else { | ||
| 2299 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
15022 | col = color_fade(cur, 255 - fadeDownAmount); |
| 2300 |
3/6✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
|
15022 | SEGMENT.setPixelColor(i, col); |
| 2301 | } | ||
| 2302 | } | ||
| 2303 | |||
| 2304 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 23 times.
|
191 | for (unsigned j = 0; j <= SEGLEN / 50; j++) { |
| 2305 |
4/6✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 93 times.
✓ Branch 5 taken 75 times.
|
168 | if (hw_random8() <= SEGMENT.intensity) { |
| 2306 |
2/2✓ Branch 0 taken 465 times.
✓ Branch 1 taken 93 times.
|
558 | for (unsigned times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times |
| 2307 | 465 | int i = hw_random16(SEGLEN); | |
| 2308 |
4/8✓ Branch 0 taken 465 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 465 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 465 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 465 times.
|
465 | if (SEGMENT.getPixelColor(i) == 0) { |
| 2309 | ✗ | unsigned index = i >> 3; | |
| 2310 | ✗ | unsigned bitNum = i & 0x07; | |
| 2311 | ✗ | bitWrite(SEGENV.data[index], bitNum, true); | |
| 2312 | ✗ | SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, hw_random8(), 64, NOBLEND)); | |
| 2313 | ✗ | break; //only spawn 1 new pixel per frame per 50 LEDs | |
| 2314 | } | ||
| 2315 | } | ||
| 2316 | } | ||
| 2317 | } | ||
| 2318 | 23 | return FRAMETIME_FIXED; | |
| 2319 | } | ||
| 2320 | static const char _data_FX_MODE_COLORTWINKLE[] PROGMEM = "Colortwinkles@Fade speed,Spawn speed;;!;;m12=0"; //pixels | ||
| 2321 | |||
| 2322 | |||
| 2323 | //Calm effect, like a lake at night | ||
| 2324 | 23 | uint16_t mode_lake() { | |
| 2325 | 23 | unsigned sp = SEGMENT.speed/10; | |
| 2326 | 23 | int wave1 = beatsin8_t(sp +2, -64,64); | |
| 2327 | 23 | int wave2 = beatsin8_t(sp +1, -64,64); | |
| 2328 | 23 | int wave3 = beatsin8_t(sp +2, 0,80); | |
| 2329 | |||
| 2330 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) |
| 2331 | { | ||
| 2332 | 7511 | int index = cos8_t((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; | |
| 2333 |
2/2✓ Branch 0 taken 6247 times.
✓ Branch 1 taken 1264 times.
|
7511 | uint8_t lum = (index > wave3) ? index - wave3 : 0; |
| 2334 | 7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum)); | |
| 2335 | } | ||
| 2336 | |||
| 2337 | 23 | return FRAMETIME; | |
| 2338 | } | ||
| 2339 | static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!"; | ||
| 2340 | |||
| 2341 | |||
| 2342 | // meteor effect & meteor smooth (merged by @dedehai) | ||
| 2343 | // send a meteor from begining to to the end of the strip with a trail that randomly decays. | ||
| 2344 | // adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain | ||
| 2345 | 23 | uint16_t mode_meteor() { | |
| 2346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed |
| 2348 | 23 | const bool meteorSmooth = SEGMENT.check3; | |
| 2349 | 23 | byte* trail = SEGENV.data; | |
| 2350 | |||
| 2351 | 23 | const unsigned meteorSize = 1 + SEGLEN / 20; // 5% | |
| 2352 | uint16_t meteorstart; | ||
| 2353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if(meteorSmooth) meteorstart = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1); |
| 2354 | else { | ||
| 2355 | 23 | unsigned counter = strip().now * ((SEGMENT.speed >> 2) + 8); | |
| 2356 | 23 | meteorstart = (counter * SEGLEN) >> 16; | |
| 2357 | } | ||
| 2358 | |||
| 2359 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | const int max = SEGMENT.palette==5 || !SEGMENT.check1 ? 240 : 255; |
| 2360 | // fade all leds to colors[1] in LEDs one step | ||
| 2361 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2362 | uint32_t col; | ||
| 2363 |
2/2✓ Branch 0 taken 3732 times.
✓ Branch 1 taken 3779 times.
|
7511 | if (hw_random8() <= 255 - SEGMENT.intensity) { |
| 2364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3732 times.
|
3732 | if(meteorSmooth) { |
| 2365 | ✗ | if (trail[i] > 0) { | |
| 2366 | ✗ | int change = trail[i] + 4 - hw_random8(24); //change each time between -20 and +4 | |
| 2367 | ✗ | trail[i] = constrain(change, 0, max); | |
| 2368 | } | ||
| 2369 | ✗ | col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); | |
| 2370 | } | ||
| 2371 | else { | ||
| 2372 | 3732 | trail[i] = scale8(trail[i], 128 + hw_random8(127)); | |
| 2373 | 3732 | int index = trail[i]; | |
| 2374 | 3732 | int idx = 255; | |
| 2375 |
2/4✓ Branch 0 taken 3732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3732 times.
✗ Branch 3 not taken.
|
3732 | int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i]; |
| 2376 |
1/2✓ Branch 0 taken 3732 times.
✗ Branch 1 not taken.
|
3732 | if (!SEGMENT.check1) { |
| 2377 | 3732 | idx = 0; | |
| 2378 | 3732 | index = map(i,0,SEGLEN,0,max); | |
| 2379 | 3732 | bri = trail[i]; | |
| 2380 | } | ||
| 2381 | 3732 | col = SEGMENT.color_from_palette(index, false, false, idx, bri); // full brightness for Fire | |
| 2382 | } | ||
| 2383 | 3732 | SEGMENT.setPixelColor(i, col); | |
| 2384 | } | ||
| 2385 | } | ||
| 2386 | |||
| 2387 | // draw meteor | ||
| 2388 |
2/2✓ Branch 0 taken 388 times.
✓ Branch 1 taken 23 times.
|
411 | for (unsigned j = 0; j < meteorSize; j++) { |
| 2389 | 388 | unsigned index = (meteorstart + j) % SEGLEN; | |
| 2390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 388 times.
|
388 | if(meteorSmooth) { |
| 2391 | ✗ | trail[index] = max; | |
| 2392 | ✗ | uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); | |
| 2393 | ✗ | SEGMENT.setPixelColor(index, col); | |
| 2394 | } | ||
| 2395 | else{ | ||
| 2396 | 388 | int idx = 255; | |
| 2397 | 388 | int i = trail[index] = max; | |
| 2398 |
1/2✓ Branch 0 taken 388 times.
✗ Branch 1 not taken.
|
388 | if (!SEGMENT.check1) { |
| 2399 | 388 | i = map(index,0,SEGLEN,0,max); | |
| 2400 | 388 | idx = 0; | |
| 2401 | } | ||
| 2402 | 388 | uint32_t col = SEGMENT.color_from_palette(i, false, false, idx, 255); // full brightness | |
| 2403 | 388 | SEGMENT.setPixelColor(index, col); | |
| 2404 | } | ||
| 2405 | } | ||
| 2406 | |||
| 2407 | 23 | SEGENV.step += SEGMENT.speed +1; | |
| 2408 | 23 | return FRAMETIME; | |
| 2409 | } | ||
| 2410 | static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient,,Smooth;;!;1"; | ||
| 2411 | |||
| 2412 | |||
| 2413 | //Railway Crossing / Christmas Fairy lights | ||
| 2414 | 23 | uint16_t mode_railway() { | |
| 2415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2416 | 23 | unsigned dur = (256 - SEGMENT.speed) * 40; | |
| 2417 | 23 | uint16_t rampdur = (dur * SEGMENT.intensity) >> 8; | |
| 2418 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (SEGENV.step > dur) |
| 2419 | { | ||
| 2420 | //reverse direction | ||
| 2421 | 1 | SEGENV.step = 0; | |
| 2422 | 1 | SEGENV.aux0 = !SEGENV.aux0; | |
| 2423 | } | ||
| 2424 | 23 | unsigned pos = 255; | |
| 2425 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (rampdur != 0) |
| 2426 | { | ||
| 2427 | 19 | unsigned p0 = (SEGENV.step * 255) / rampdur; | |
| 2428 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (p0 < 255) pos = p0; |
| 2429 | } | ||
| 2430 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
|
23 | if (SEGENV.aux0) pos = 255 - pos; |
| 2431 |
2/2✓ Branch 0 taken 3758 times.
✓ Branch 1 taken 23 times.
|
3781 | for (unsigned i = 0; i < SEGLEN; i += 2) |
| 2432 | { | ||
| 2433 | 3758 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(255 - pos, false, false, 255)); // do not use color 1 or 2, always use palette | |
| 2434 |
2/2✓ Branch 0 taken 3753 times.
✓ Branch 1 taken 5 times.
|
3758 | if (i < SEGLEN -1) |
| 2435 | { | ||
| 2436 | 3753 | SEGMENT.setPixelColor(i + 1, SEGMENT.color_from_palette(pos, false, false, 255)); // do not use color 1 or 2, always use palette | |
| 2437 | } | ||
| 2438 | } | ||
| 2439 | 23 | SEGENV.step += FRAMETIME; | |
| 2440 | 23 | return FRAMETIME; | |
| 2441 | } | ||
| 2442 | static const char _data_FX_MODE_RAILWAY[] PROGMEM = "Railway@!,Smoothness;1,2;!;;pal=3"; | ||
| 2443 | |||
| 2444 | |||
| 2445 | //Water ripple | ||
| 2446 | //propagation velocity from speed | ||
| 2447 | //drop rate from intensity | ||
| 2448 | |||
| 2449 | //4 bytes | ||
| 2450 | typedef struct Ripple { | ||
| 2451 | uint8_t state; | ||
| 2452 | uint8_t color; | ||
| 2453 | uint16_t pos; | ||
| 2454 | } ripple; | ||
| 2455 | |||
| 2456 | #ifdef ESP8266 | ||
| 2457 | #define MAX_RIPPLES 56 | ||
| 2458 | #else | ||
| 2459 | #define MAX_RIPPLES 100 | ||
| 2460 | #endif | ||
| 2461 | 46 | static uint16_t ripple_base(uint8_t blurAmount = 0) { | |
| 2462 | 46 | unsigned maxRipples = min(1 + (int)(SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 | |
| 2463 | 46 | unsigned dataSize = sizeof(ripple) * maxRipples; | |
| 2464 | |||
| 2465 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 2466 | |||
| 2467 | 46 | Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data); | |
| 2468 | |||
| 2469 | //draw wave | ||
| 2470 |
2/2✓ Branch 0 taken 3040 times.
✓ Branch 1 taken 46 times.
|
3086 | for (unsigned i = 0; i < maxRipples; i++) { |
| 2471 | 3040 | unsigned ripplestate = ripples[i].state; | |
| 2472 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3029 times.
|
3040 | if (ripplestate) { |
| 2473 | 11 | unsigned rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation | |
| 2474 | 11 | unsigned rippleorigin = ripples[i].pos; | |
| 2475 | 11 | uint32_t col = SEGMENT.color_from_palette(ripples[i].color, false, false, 255); | |
| 2476 | 11 | unsigned propagation = ((ripplestate/rippledecay - 1) * (SEGMENT.speed + 1)); | |
| 2477 | 11 | int propI = propagation >> 8; | |
| 2478 | 11 | unsigned propF = propagation & 0xFF; | |
| 2479 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
|
11 | unsigned amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2); |
| 2480 | |||
| 2481 | #ifndef WLED_DISABLE_2D | ||
| 2482 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | if (SEGMENT.is2D()) { |
| 2483 | 5 | propI /= 2; | |
| 2484 | 5 | unsigned cx = rippleorigin >> 8; | |
| 2485 | 5 | unsigned cy = rippleorigin & 0xFF; | |
| 2486 | 5 | unsigned mag = scale8(sin8_t((propF>>2)), amp); | |
| 2487 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); |
| 2488 | } else | ||
| 2489 | #endif | ||
| 2490 | { | ||
| 2491 | 6 | int left = rippleorigin - propI -1; | |
| 2492 | 6 | int right = rippleorigin + propI +2; | |
| 2493 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
|
30 | for (int v = 0; v < 4; v++) { |
| 2494 | 24 | uint8_t mag = scale8(cubicwave8((propF>>2) + v * 64), amp); | |
| 2495 | 24 | SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO | |
| 2496 | 24 | SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO | |
| 2497 | } | ||
| 2498 | } | ||
| 2499 | 11 | ripplestate += rippledecay; | |
| 2500 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | ripples[i].state = (ripplestate > 254) ? 0 : ripplestate; |
| 2501 | } else {//randomly create new wave | ||
| 2502 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3024 times.
|
3029 | if (hw_random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) { |
| 2503 | 5 | ripples[i].state = 1; | |
| 2504 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | ripples[i].pos = SEGMENT.is2D() ? ((hw_random8(SEG_W)<<8) | (hw_random8(SEG_H))) : hw_random16(SEGLEN); |
| 2505 | 5 | ripples[i].color = hw_random8(); //color | |
| 2506 | } | ||
| 2507 | } | ||
| 2508 | } | ||
| 2509 | 46 | SEGMENT.blur(blurAmount); | |
| 2510 | 46 | return FRAMETIME; | |
| 2511 | } | ||
| 2512 | #undef MAX_RIPPLES | ||
| 2513 | |||
| 2514 | |||
| 2515 | 23 | uint16_t mode_ripple(void) { | |
| 2516 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2517 |
5/6✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
|
23 | if(SEGMENT.custom1 || SEGMENT.check2) // blur or overlay |
| 2518 | 4 | SEGMENT.fade_out(250); | |
| 2519 | else | ||
| 2520 | 19 | SEGMENT.fill(SEGCOLOR(1)); | |
| 2521 | |||
| 2522 | 23 | return ripple_base(SEGMENT.custom1>>1); | |
| 2523 | } | ||
| 2524 | static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Overlay;,!;!;12;c1=0"; | ||
| 2525 | |||
| 2526 | |||
| 2527 | 23 | uint16_t mode_ripple_rainbow(void) { | |
| 2528 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2529 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call ==0) { |
| 2530 | 5 | SEGENV.aux0 = hw_random8(); | |
| 2531 | 5 | SEGENV.aux1 = hw_random8(); | |
| 2532 | } | ||
| 2533 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (SEGENV.aux0 == SEGENV.aux1) { |
| 2534 | 1 | SEGENV.aux1 = hw_random8(); | |
| 2535 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 13 times.
|
22 | } else if (SEGENV.aux1 > SEGENV.aux0) { |
| 2536 | 9 | SEGENV.aux0++; | |
| 2537 | } else { | ||
| 2538 | 13 | SEGENV.aux0--; | |
| 2539 | } | ||
| 2540 | 23 | SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,uint8_t(235))); | |
| 2541 | 23 | return ripple_base(); | |
| 2542 | } | ||
| 2543 | static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12"; | ||
| 2544 | |||
| 2545 | |||
| 2546 | // TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a | ||
| 2547 | // | ||
| 2548 | // TwinkleFOX: Twinkling 'holiday' lights that fade in and out. | ||
| 2549 | // Colors are chosen from a palette. Read more about this effect using the link above! | ||
| 2550 | 15022 | static CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) | |
| 2551 | { | ||
| 2552 | // Overall twinkle speed (changed) | ||
| 2553 |
2/4✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15022 times.
✗ Branch 3 not taken.
|
15022 | unsigned ticks = ms / SEGENV.aux0; |
| 2554 | 15022 | unsigned fastcycle8 = uint8_t(ticks); | |
| 2555 | 15022 | uint16_t slowcycle16 = (ticks >> 8) + salt; | |
| 2556 |
1/2✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
|
15022 | slowcycle16 += sin8_t(slowcycle16); |
| 2557 | 15022 | slowcycle16 = (slowcycle16 * 2053) + 1384; | |
| 2558 | 15022 | uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); | |
| 2559 | |||
| 2560 | // Overall twinkle density. | ||
| 2561 | // 0 (NONE lit) to 8 (ALL lit at once). | ||
| 2562 | // Default is 5. | ||
| 2563 |
2/4✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15022 times.
✗ Branch 3 not taken.
|
15022 | unsigned twinkleDensity = (SEGMENT.intensity >> 5) +1; |
| 2564 | |||
| 2565 | 15022 | unsigned bright = 0; | |
| 2566 |
2/2✓ Branch 0 taken 9141 times.
✓ Branch 1 taken 5881 times.
|
15022 | if (((slowcycle8 & 0x0E)/2) < twinkleDensity) { |
| 2567 | 9141 | unsigned ph = fastcycle8; | |
| 2568 | // This is like 'triwave8', which produces a | ||
| 2569 | // symmetrical up-and-down triangle sawtooth waveform, except that this | ||
| 2570 | // function produces a triangle wave with a faster attack and a slower decay | ||
| 2571 |
2/2✓ Branch 0 taken 4573 times.
✓ Branch 1 taken 4568 times.
|
9141 | if (cat) //twinklecat, variant where the leds instantly turn on |
| 2572 | { | ||
| 2573 | 4573 | bright = 255 - ph; | |
| 2574 | } else { //vanilla twinklefox | ||
| 2575 |
2/2✓ Branch 0 taken 1610 times.
✓ Branch 1 taken 2958 times.
|
4568 | if (ph < 86) { |
| 2576 | 1610 | bright = ph * 3; | |
| 2577 | } else { | ||
| 2578 | 2958 | ph -= 86; | |
| 2579 | 2958 | bright = 255 - (ph + (ph/2)); | |
| 2580 | } | ||
| 2581 | } | ||
| 2582 | } | ||
| 2583 | |||
| 2584 | 15022 | unsigned hue = slowcycle8 - salt; | |
| 2585 | CRGB c; | ||
| 2586 |
2/2✓ Branch 0 taken 9110 times.
✓ Branch 1 taken 5912 times.
|
15022 | if (bright > 0) { |
| 2587 |
1/2✓ Branch 0 taken 9110 times.
✗ Branch 1 not taken.
|
9110 | c = ColorFromPalette(SEGPALETTE, hue, bright, NOBLEND); |
| 2588 |
3/6✓ Branch 0 taken 9110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9110 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9110 times.
✗ Branch 5 not taken.
|
9110 | if (!SEGMENT.check1) { |
| 2589 | // This code takes a pixel, and if its in the 'fading down' | ||
| 2590 | // part of the cycle, it adjusts the color a little bit like the | ||
| 2591 | // way that incandescent bulbs fade toward 'red' as they dim. | ||
| 2592 |
2/2✓ Branch 0 taken 4469 times.
✓ Branch 1 taken 4641 times.
|
9110 | if (fastcycle8 >= 128) |
| 2593 | { | ||
| 2594 | 4469 | unsigned cooling = (fastcycle8 - 128) >> 4; | |
| 2595 |
2/2✓ Branch 0 taken 2681 times.
✓ Branch 1 taken 1788 times.
|
4469 | c.g = qsub8(c.g, cooling); |
| 2596 |
2/2✓ Branch 0 taken 2157 times.
✓ Branch 1 taken 2312 times.
|
8938 | c.b = qsub8(c.b, cooling * 2); |
| 2597 | } | ||
| 2598 | } | ||
| 2599 | } else { | ||
| 2600 | c = CRGB::Black; | ||
| 2601 | } | ||
| 2602 | 15022 | return c; | |
| 2603 | } | ||
| 2604 | |||
| 2605 | // This function loops over each pixel, calculates the | ||
| 2606 | // adjusted 'clock' that this pixel should use, and calls | ||
| 2607 | // "CalculateOneTwinkle" on each pixel. It then displays | ||
| 2608 | // either the twinkle color of the background color, | ||
| 2609 | // whichever is brighter. | ||
| 2610 | 46 | static uint16_t twinklefox_base(bool cat) | |
| 2611 | { | ||
| 2612 | // "PRNG16" is the pseudorandom number generator | ||
| 2613 | // It MUST be reset to the same starting value each time | ||
| 2614 | // this function is called, so that the sequence of 'random' | ||
| 2615 | // numbers that it generates is (paradoxically) stable. | ||
| 2616 | 46 | uint16_t PRNG16 = 11337; | |
| 2617 | |||
| 2618 | // Calculate speed | ||
| 2619 |
8/14✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 38 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 38 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 38 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 38 times.
✗ Branch 13 not taken.
|
46 | if (SEGMENT.speed > 100) SEGENV.aux0 = 3 + ((255 - SEGMENT.speed) >> 3); |
| 2620 |
4/8✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
|
8 | else SEGENV.aux0 = 22 + ((100 - SEGMENT.speed) >> 1); |
| 2621 | |||
| 2622 | // Set up the background color, "bg". | ||
| 2623 | 46 | CRGB bg = CRGB(SEGCOLOR(1)); | |
| 2624 | 46 | unsigned bglight = bg.getAverageLight(); | |
| 2625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (bglight > 64) { |
| 2626 | bg.nscale8_video(16); // very bright, so scale to 1/16th | ||
| 2627 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 30 times.
|
46 | } else if (bglight > 16) { |
| 2628 | bg.nscale8_video(64); // not that bright, so scale to 1/4th | ||
| 2629 | } else { | ||
| 2630 | bg.nscale8_video(86); // dim, scale to 1/3rd. | ||
| 2631 | } | ||
| 2632 | |||
| 2633 | 46 | unsigned backgroundBrightness = bg.getAverageLight(); | |
| 2634 | |||
| 2635 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 46 times.
|
15068 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2636 | |||
| 2637 | 15022 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number | |
| 2638 | 15022 | unsigned myclockoffset16= PRNG16; // use that number as clock offset | |
| 2639 | 15022 | PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number | |
| 2640 | // use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths) | ||
| 2641 | 15022 | unsigned myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08; | |
| 2642 |
1/2✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
|
15022 | uint32_t myclock30 = (uint32_t)((strip().now * myspeedmultiplierQ5_3) >> 3) + myclockoffset16; |
| 2643 | 15022 | unsigned myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel | |
| 2644 | |||
| 2645 | // We now have the adjusted 'clock' for this pixel, now we call | ||
| 2646 | // the function that computes what color the pixel should be based | ||
| 2647 | // on the "brightness = f( time )" idea. | ||
| 2648 |
1/2✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
|
15022 | CRGB c = twinklefox_one_twinkle(myclock30, myunique8, cat); |
| 2649 | |||
| 2650 | 15022 | unsigned cbright = c.getAverageLight(); | |
| 2651 | 15022 | int deltabright = cbright - backgroundBrightness; | |
| 2652 |
5/6✓ Branch 0 taken 9771 times.
✓ Branch 1 taken 5251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9771 times.
✓ Branch 4 taken 5251 times.
✓ Branch 5 taken 9771 times.
|
15022 | if (deltabright >= 32 || (!bg)) { |
| 2653 | // If the new pixel is significantly brighter than the background color, | ||
| 2654 | // use the new color. | ||
| 2655 |
3/6✓ Branch 0 taken 5251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5251 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5251 times.
✗ Branch 5 not taken.
|
5251 | SEGMENT.setPixelColor(i, c); |
| 2656 |
2/2✓ Branch 0 taken 3190 times.
✓ Branch 1 taken 6581 times.
|
9771 | } else if (deltabright > 0) { |
| 2657 | // If the new pixel is just slightly brighter than the background color, | ||
| 2658 | // mix a blend of the new color and the background color | ||
| 2659 |
4/8✓ Branch 0 taken 3190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3190 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3190 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3190 times.
✗ Branch 7 not taken.
|
3190 | SEGMENT.setPixelColor(i, color_blend(RGBW32(bg.r,bg.g,bg.b,0), RGBW32(c.r,c.g,c.b,0), uint8_t(deltabright * 8))); |
| 2660 | } else { | ||
| 2661 | // if the new pixel is not at all brighter than the background color, | ||
| 2662 | // just use the background color. | ||
| 2663 |
3/6✓ Branch 0 taken 6581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6581 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6581 times.
✗ Branch 5 not taken.
|
6581 | SEGMENT.setPixelColor(i, bg); |
| 2664 | } | ||
| 2665 | } | ||
| 2666 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
92 | return FRAMETIME; |
| 2667 | } | ||
| 2668 | |||
| 2669 | |||
| 2670 | 23 | uint16_t mode_twinklefox() | |
| 2671 | { | ||
| 2672 | 23 | return twinklefox_base(false); | |
| 2673 | } | ||
| 2674 | static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate,,,,Cool;!,!;!"; | ||
| 2675 | |||
| 2676 | |||
| 2677 | 23 | uint16_t mode_twinklecat() | |
| 2678 | { | ||
| 2679 | 23 | return twinklefox_base(true); | |
| 2680 | } | ||
| 2681 | static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate,,,,Cool;!,!;!"; | ||
| 2682 | |||
| 2683 | |||
| 2684 | 23 | uint16_t mode_halloween_eyes() | |
| 2685 | { | ||
| 2686 | enum eyeState : uint8_t { | ||
| 2687 | initializeOn = 0, | ||
| 2688 | on, | ||
| 2689 | blink, | ||
| 2690 | initializeOff, | ||
| 2691 | off, | ||
| 2692 | |||
| 2693 | count | ||
| 2694 | }; | ||
| 2695 | struct EyeData { | ||
| 2696 | eyeState state; | ||
| 2697 | uint8_t color; | ||
| 2698 | uint16_t startPos; | ||
| 2699 | // duration + endTime could theoretically be replaced by a single endTime, however we would lose | ||
| 2700 | // the ability to end the animation early when the user reduces the animation time. | ||
| 2701 | uint16_t duration; | ||
| 2702 | uint32_t startTime; | ||
| 2703 | uint32_t blinkEndTime; | ||
| 2704 | }; | ||
| 2705 | |||
| 2706 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2707 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
|
23 | const unsigned maxWidth = strip().isMatrix ? SEG_W : SEGLEN; |
| 2708 |
6/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 5 times.
|
23 | const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip().isMatrix ? SEG_W>>4: SEGLEN>>5); |
| 2709 | 23 | const unsigned HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2; | |
| 2710 | 23 | unsigned eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE; | |
| 2711 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short |
| 2712 | |||
| 2713 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(sizeof(EyeData))) return mode_static(); //allocation failed |
| 2714 | 23 | EyeData& data = *reinterpret_cast<EyeData*>(SEGENV.data); | |
| 2715 | |||
| 2716 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); //fill background |
| 2717 | |||
| 2718 | 23 | data.state = static_cast<eyeState>(data.state % eyeState::count); | |
| 2719 | 23 | unsigned duration = max(uint16_t{1u}, data.duration); | |
| 2720 | 23 | const uint32_t elapsedTime = strip().now - data.startTime; | |
| 2721 | |||
| 2722 |
4/7✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
23 | switch (data.state) { |
| 2723 | 6 | case eyeState::initializeOn: { | |
| 2724 | // initialize the eyes-on state: | ||
| 2725 | // - select eye position and color | ||
| 2726 | // - select a duration | ||
| 2727 | // - immediately switch to eyes on state. | ||
| 2728 | |||
| 2729 | 6 | data.startPos = hw_random16(0, maxWidth - eyeLength - 1); | |
| 2730 | 6 | data.color = hw_random8(); | |
| 2731 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | if (strip().isMatrix) SEGMENT.offset = hw_random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices |
| 2732 | 6 | duration = 128u + hw_random16(SEGMENT.intensity*64u); | |
| 2733 | 6 | data.duration = duration; | |
| 2734 | 6 | data.state = eyeState::on; | |
| 2735 | [[fallthrough]]; | ||
| 2736 | } | ||
| 2737 | 7 | case eyeState::on: { | |
| 2738 | // eyes-on steate: | ||
| 2739 | // - fade eyes in for some time | ||
| 2740 | // - keep eyes on until the pre-selected duration is over | ||
| 2741 | // - randomly switch to the blink (sub-)state, and initialize it with a blink duration (more precisely, a blink end time stamp) | ||
| 2742 | // - never switch to the blink state if the animation just started or is about to end | ||
| 2743 | |||
| 2744 | 7 | unsigned start2ndEye = data.startPos + HALLOWEEN_EYE_WIDTH + HALLOWEEN_EYE_SPACE; | |
| 2745 | // If the user reduces the input while in this state, limit the duration. | ||
| 2746 | 7 | duration = min(duration, (128u + (SEGMENT.intensity * 64u))); | |
| 2747 | |||
| 2748 | 7 | constexpr uint32_t minimumOnTimeBegin = 1024u; | |
| 2749 | 7 | constexpr uint32_t minimumOnTimeEnd = 1024u; | |
| 2750 | 7 | const uint32_t fadeInAnimationState = elapsedTime * uint32_t{256u * 8u} / duration; | |
| 2751 | 7 | const uint32_t backgroundColor = SEGCOLOR(1); | |
| 2752 | 7 | const uint32_t eyeColor = SEGMENT.color_from_palette(data.color, false, false, 0); | |
| 2753 | 7 | uint32_t c = eyeColor; | |
| 2754 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (fadeInAnimationState < 256u) { |
| 2755 | ✗ | c = color_blend(backgroundColor, eyeColor, uint8_t(fadeInAnimationState)); | |
| 2756 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
|
7 | } else if (elapsedTime > minimumOnTimeBegin) { |
| 2757 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime); |
| 2758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (remainingTime > minimumOnTimeEnd) { |
| 2759 | ✗ | if (hw_random8() < 4u) | |
| 2760 | { | ||
| 2761 | ✗ | c = backgroundColor; | |
| 2762 | ✗ | data.state = eyeState::blink; | |
| 2763 | ✗ | data.blinkEndTime = strip().now + hw_random8(8, 128); | |
| 2764 | } | ||
| 2765 | } | ||
| 2766 | } | ||
| 2767 | |||
| 2768 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (c != backgroundColor) { |
| 2769 | // render eyes | ||
| 2770 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7 times.
|
15 | for (unsigned i = 0; i < HALLOWEEN_EYE_WIDTH; i++) { |
| 2771 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | if (strip().isMatrix) { |
| 2772 | 6 | SEGMENT.setPixelColorXY(data.startPos + i, (unsigned)SEGMENT.offset, c); | |
| 2773 | 6 | SEGMENT.setPixelColorXY(start2ndEye + i, (unsigned)SEGMENT.offset, c); | |
| 2774 | } else { | ||
| 2775 | 2 | SEGMENT.setPixelColor(data.startPos + i, c); | |
| 2776 | 2 | SEGMENT.setPixelColor(start2ndEye + i, c); | |
| 2777 | } | ||
| 2778 | } | ||
| 2779 | } | ||
| 2780 | 7 | break; | |
| 2781 | } | ||
| 2782 | ✗ | case eyeState::blink: { | |
| 2783 | // eyes-on but currently blinking state: | ||
| 2784 | // - wait until the blink time is over, then switch back to eyes-on | ||
| 2785 | |||
| 2786 | ✗ | if (strip().now >= data.blinkEndTime) { | |
| 2787 | ✗ | data.state = eyeState::on; | |
| 2788 | } | ||
| 2789 | ✗ | break; | |
| 2790 | } | ||
| 2791 | 5 | case eyeState::initializeOff: { | |
| 2792 | // initialize eyes-off state: | ||
| 2793 | // - select a duration | ||
| 2794 | // - immediately switch to eyes-off state | ||
| 2795 | |||
| 2796 | 5 | const unsigned eyeOffTimeBase = SEGMENT.speed*128u; | |
| 2797 | 5 | duration = eyeOffTimeBase + hw_random16(eyeOffTimeBase); | |
| 2798 | 5 | data.duration = duration; | |
| 2799 | 5 | data.state = eyeState::off; | |
| 2800 | [[fallthrough]]; | ||
| 2801 | } | ||
| 2802 | 16 | case eyeState::off: { | |
| 2803 | // eyes-off state: | ||
| 2804 | // - not much to do here | ||
| 2805 | |||
| 2806 | // If the user reduces the input while in this state, limit the duration. | ||
| 2807 | 16 | const unsigned eyeOffTimeBase = SEGMENT.speed*128u; | |
| 2808 | 16 | duration = min(duration, (2u * eyeOffTimeBase)); | |
| 2809 | 16 | break; | |
| 2810 | } | ||
| 2811 | ✗ | case eyeState::count: { | |
| 2812 | // Can't happen, not an actual state. | ||
| 2813 | ✗ | data.state = eyeState::initializeOn; | |
| 2814 | ✗ | break; | |
| 2815 | } | ||
| 2816 | } | ||
| 2817 | |||
| 2818 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 17 times.
|
23 | if (elapsedTime > duration) { |
| 2819 | // The current state duration is over, switch to the next state. | ||
| 2820 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | switch (data.state) { |
| 2821 | 5 | case eyeState::initializeOn: | |
| 2822 | case eyeState::on: | ||
| 2823 | case eyeState::blink: | ||
| 2824 | 5 | data.state = eyeState::initializeOff; | |
| 2825 | 5 | break; | |
| 2826 | 1 | case eyeState::initializeOff: | |
| 2827 | case eyeState::off: | ||
| 2828 | case eyeState::count: | ||
| 2829 | default: | ||
| 2830 | 1 | data.state = eyeState::initializeOn; | |
| 2831 | 1 | break; | |
| 2832 | } | ||
| 2833 | 6 | data.startTime = strip().now; | |
| 2834 | } | ||
| 2835 | |||
| 2836 | 23 | return FRAMETIME; | |
| 2837 | } | ||
| 2838 | static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Eye off time,Eye on time,,,,,Overlay;!,!;!;12"; | ||
| 2839 | |||
| 2840 | |||
| 2841 | //Speed slider sets amount of LEDs lit, intensity sets unlit | ||
| 2842 | 23 | uint16_t mode_static_pattern() | |
| 2843 | { | ||
| 2844 | 23 | unsigned lit = 1 + SEGMENT.speed; | |
| 2845 | 23 | unsigned unlit = 1 + SEGMENT.intensity; | |
| 2846 | 23 | bool drawingLit = true; | |
| 2847 | 23 | unsigned cnt = 0; | |
| 2848 | |||
| 2849 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2850 |
4/6✓ Branch 0 taken 4088 times.
✓ Branch 1 taken 3423 times.
✓ Branch 2 taken 4088 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4088 times.
|
7511 | SEGMENT.setPixelColor(i, (drawingLit) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(1)); |
| 2851 | 7511 | cnt++; | |
| 2852 |
4/4✓ Branch 0 taken 4088 times.
✓ Branch 1 taken 3423 times.
✓ Branch 2 taken 2076 times.
✓ Branch 3 taken 5435 times.
|
7511 | if (cnt >= ((drawingLit) ? lit : unlit)) { |
| 2853 | 2076 | cnt = 0; | |
| 2854 | 2076 | drawingLit = !drawingLit; | |
| 2855 | } | ||
| 2856 | } | ||
| 2857 | |||
| 2858 | 23 | return FRAMETIME; | |
| 2859 | } | ||
| 2860 | static const char _data_FX_MODE_STATIC_PATTERN[] PROGMEM = "Solid Pattern@Fg size,Bg size;Fg,!;!;;pal=0"; | ||
| 2861 | |||
| 2862 | |||
| 2863 | 23 | uint16_t mode_tri_static_pattern() | |
| 2864 | { | ||
| 2865 | 23 | unsigned segSize = (SEGMENT.intensity >> 5) +1; | |
| 2866 | 23 | unsigned currSeg = 0; | |
| 2867 | 23 | unsigned currSegCount = 0; | |
| 2868 | |||
| 2869 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 2870 |
2/2✓ Branch 0 taken 2548 times.
✓ Branch 1 taken 4963 times.
|
7511 | if ( currSeg % 3 == 0 ) { |
| 2871 | 2548 | SEGMENT.setPixelColor(i, SEGCOLOR(0)); | |
| 2872 |
2/2✓ Branch 0 taken 2486 times.
✓ Branch 1 taken 2477 times.
|
4963 | } else if( currSeg % 3 == 1) { |
| 2873 | 2486 | SEGMENT.setPixelColor(i, SEGCOLOR(1)); | |
| 2874 | } else { | ||
| 2875 | 2477 | SEGMENT.setPixelColor(i, SEGCOLOR(2)); | |
| 2876 | } | ||
| 2877 | 7511 | currSegCount += 1; | |
| 2878 |
2/2✓ Branch 0 taken 2984 times.
✓ Branch 1 taken 4527 times.
|
7511 | if (currSegCount >= segSize) { |
| 2879 | 2984 | currSeg +=1; | |
| 2880 | 2984 | currSegCount = 0; | |
| 2881 | } | ||
| 2882 | } | ||
| 2883 | |||
| 2884 | 23 | return FRAMETIME; | |
| 2885 | } | ||
| 2886 | static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tri@,Size;1,2,3;;;pal=0"; | ||
| 2887 | |||
| 2888 | |||
| 2889 | 46 | static uint16_t spots_base(uint16_t threshold) | |
| 2890 | { | ||
| 2891 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGLEN <= 1) return mode_static(); |
| 2892 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); |
| 2893 | |||
| 2894 | 46 | unsigned maxZones = SEGLEN >> 2; | |
| 2895 | 46 | unsigned zones = 1 + ((SEGMENT.intensity * maxZones) >> 8); | |
| 2896 | 46 | unsigned zoneLen = SEGLEN / zones; | |
| 2897 | 46 | unsigned offset = (SEGLEN - zones * zoneLen) >> 1; | |
| 2898 | |||
| 2899 |
2/2✓ Branch 0 taken 1902 times.
✓ Branch 1 taken 46 times.
|
1948 | for (unsigned z = 0; z < zones; z++) |
| 2900 | { | ||
| 2901 | 1902 | unsigned pos = offset + z * zoneLen; | |
| 2902 |
2/2✓ Branch 0 taken 14282 times.
✓ Branch 1 taken 1902 times.
|
16184 | for (unsigned i = 0; i < zoneLen; i++) |
| 2903 | { | ||
| 2904 | 14282 | unsigned wave = triwave16((i * 0xFFFF) / zoneLen); | |
| 2905 |
2/2✓ Branch 0 taken 7548 times.
✓ Branch 1 taken 6734 times.
|
14282 | if (wave > threshold) { |
| 2906 | 7548 | unsigned index = 0 + pos + i; | |
| 2907 | 7548 | unsigned s = (wave - threshold)*255 / (0xFFFF - threshold); | |
| 2908 |
2/4✓ Branch 0 taken 7548 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7548 times.
|
7548 | SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s))); |
| 2909 | } | ||
| 2910 | } | ||
| 2911 | } | ||
| 2912 | |||
| 2913 | 46 | return FRAMETIME; | |
| 2914 | } | ||
| 2915 | |||
| 2916 | |||
| 2917 | //Intensity slider sets number of "lights", speed sets LEDs per light | ||
| 2918 | 23 | uint16_t mode_spots() | |
| 2919 | { | ||
| 2920 | 23 | return spots_base((255 - SEGMENT.speed) << 8); | |
| 2921 | } | ||
| 2922 | static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@Spread,Width,,,,,Overlay;!,!;!"; | ||
| 2923 | |||
| 2924 | |||
| 2925 | //Intensity slider sets number of "lights", LEDs per light fade in and out | ||
| 2926 | 23 | uint16_t mode_spots_fade() | |
| 2927 | { | ||
| 2928 | 23 | unsigned counter = strip().now * ((SEGMENT.speed >> 2) +8); | |
| 2929 | 23 | unsigned t = triwave16(counter); | |
| 2930 | 23 | unsigned tr = (t >> 1) + (t >> 2); | |
| 2931 | 23 | return spots_base(tr); | |
| 2932 | } | ||
| 2933 | static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!"; | ||
| 2934 | |||
| 2935 | //each needs 12 bytes | ||
| 2936 | typedef struct Ball { | ||
| 2937 | unsigned long lastBounceTime; | ||
| 2938 | float impactVelocity; | ||
| 2939 | float height; | ||
| 2940 | } ball; | ||
| 2941 | |||
| 2942 | /* | ||
| 2943 | * Bouncing Balls Effect | ||
| 2944 | */ | ||
| 2945 | 23 | uint16_t mode_bouncing_balls(void) { | |
| 2946 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 2947 | //allocate segment data | ||
| 2948 | 23 | const unsigned strips = SEGMENT.nrOfVStrips(); // adapt for 2D | |
| 2949 | 23 | const size_t maxNumBalls = 16; | |
| 2950 | 23 | unsigned dataSize = sizeof(ball) * maxNumBalls; | |
| 2951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed |
| 2952 | |||
| 2953 | 23 | Ball* balls = reinterpret_cast<Ball*>(SEGENV.data); | |
| 2954 | |||
| 2955 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1)); |
| 2956 | |||
| 2957 | // virtualStrip idea by @ewowi (Ewoud Wijma) | ||
| 2958 | // requires virtual strip # to be embedded into upper 16 bits of index in setPixelColor() | ||
| 2959 | // the following functions will not work on virtual strips: fill(), fade_out(), fadeToBlack(), blur() | ||
| 2960 | struct virtualStrip { | ||
| 2961 | 456 | static void runStrip(size_t stripNr, Ball* balls) { | |
| 2962 | // number of balls based on intensity setting to max of 7 (cycles colors) | ||
| 2963 | // non-chosen color is a random color | ||
| 2964 | 456 | unsigned numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball | |
| 2965 | 456 | const float gravity = -9.81f; // standard value of gravity | |
| 2966 | 456 | const bool hasCol2 = SEGCOLOR(2); | |
| 2967 | 456 | const unsigned long time = strip().now; | |
| 2968 | |||
| 2969 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 352 times.
|
456 | if (SEGENV.call == 0) { |
| 2970 |
2/2✓ Branch 0 taken 1664 times.
✓ Branch 1 taken 104 times.
|
1768 | for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time; |
| 2971 | } | ||
| 2972 | |||
| 2973 |
2/2✓ Branch 0 taken 3776 times.
✓ Branch 1 taken 456 times.
|
4232 | for (size_t i = 0; i < numBalls; i++) { |
| 2974 | 3776 | float timeSinceLastBounce = (time - balls[i].lastBounceTime)/((255-SEGMENT.speed)/64 +1); | |
| 2975 | 3776 | float timeSec = timeSinceLastBounce/1000.0f; | |
| 2976 | 3776 | balls[i].height = (0.5f * gravity * timeSec + balls[i].impactVelocity) * timeSec; // avoid use pow(x, 2) - its extremely slow ! | |
| 2977 | |||
| 2978 |
2/2✓ Branch 0 taken 864 times.
✓ Branch 1 taken 2912 times.
|
3776 | if (balls[i].height <= 0.0f) { |
| 2979 | 864 | balls[i].height = 0.0f; | |
| 2980 | //damping for better effect using multiple balls | ||
| 2981 | 864 | float dampening = 0.9f - float(i)/float(numBalls * numBalls); // avoid use pow(x, 2) - its extremely slow ! | |
| 2982 | 864 | balls[i].impactVelocity = dampening * balls[i].impactVelocity; | |
| 2983 | 864 | balls[i].lastBounceTime = time; | |
| 2984 | |||
| 2985 |
1/2✓ Branch 0 taken 864 times.
✗ Branch 1 not taken.
|
864 | if (balls[i].impactVelocity < 0.015f) { |
| 2986 | 864 | float impactVelocityStart = sqrtf(-2.0f * gravity) * hw_random8(5,11)/10.0f; // randomize impact velocity | |
| 2987 | 864 | balls[i].impactVelocity = impactVelocityStart; | |
| 2988 | } | ||
| 2989 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2912 times.
|
2912 | } else if (balls[i].height > 1.0f) { |
| 2990 | ✗ | continue; // do not draw OOB ball | |
| 2991 | } | ||
| 2992 | |||
| 2993 | 3776 | uint32_t color = SEGCOLOR(0); | |
| 2994 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3776 times.
|
3776 | if (SEGMENT.palette) { |
| 2995 | ✗ | color = SEGMENT.color_wheel(i*(256/MAX(numBalls, 8))); | |
| 2996 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3776 times.
|
3776 | } else if (hasCol2) { |
| 2997 | ✗ | color = SEGCOLOR(i % NUM_COLORS); | |
| 2998 | } | ||
| 2999 | |||
| 3000 | 3776 | int pos = roundf(balls[i].height * (SEGLEN - 1)); | |
| 3001 | #ifdef WLED_USE_AA_PIXELS | ||
| 3002 | if (SEGLEN<32) SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color); // encode virtual strip into index | ||
| 3003 | else SEGMENT.setPixelColor(balls[i].height + (stripNr+1)*10.0f, color); | ||
| 3004 | #else | ||
| 3005 | 3776 | SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color); // encode virtual strip into index | |
| 3006 | #endif | ||
| 3007 | } | ||
| 3008 | 456 | } | |
| 3009 | }; | ||
| 3010 | |||
| 3011 |
2/2✓ Branch 0 taken 456 times.
✓ Branch 1 taken 23 times.
|
479 | for (unsigned stripNr=0; stripNr<strips; stripNr++) |
| 3012 | 456 | virtualStrip::runStrip(stripNr, &balls[stripNr * maxNumBalls]); | |
| 3013 | |||
| 3014 | 23 | return FRAMETIME; | |
| 3015 | } | ||
| 3016 | static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls,,,,,Overlay;!,!,!;!;1;m12=1"; //bar | ||
| 3017 | |||
| 3018 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 3019 | /* | ||
| 3020 | * bouncing balls on a track track Effect modified from Aircoookie's bouncing balls | ||
| 3021 | * Courtesy of pjhatch (https://github.com/pjhatch) | ||
| 3022 | * https://github.com/wled-dev/WLED/pull/1039 | ||
| 3023 | */ | ||
| 3024 | // modified for balltrack mode | ||
| 3025 | typedef struct RollingBall { | ||
| 3026 | unsigned long lastBounceUpdate; | ||
| 3027 | float mass; // could fix this to be = 1. if memory is an issue | ||
| 3028 | float velocity; | ||
| 3029 | float height; | ||
| 3030 | } rball_t; | ||
| 3031 | |||
| 3032 | 23 | static uint16_t rolling_balls(void) { | |
| 3033 | //allocate segment data | ||
| 3034 | 23 | const unsigned maxNumBalls = 16; // 255/16 + 1 | |
| 3035 | 23 | unsigned dataSize = sizeof(rball_t) * maxNumBalls; | |
| 3036 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 3037 | |||
| 3038 | 23 | rball_t *balls = reinterpret_cast<rball_t *>(SEGENV.data); | |
| 3039 | |||
| 3040 | // number of balls based on intensity setting to max of 16 (cycles colors) | ||
| 3041 | // non-chosen color is a random color | ||
| 3042 | 23 | unsigned numBalls = SEGMENT.intensity/16 + 1; | |
| 3043 | 23 | bool hasCol2 = SEGCOLOR(2); | |
| 3044 | |||
| 3045 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 3046 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // start clean |
| 3047 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 5 times.
|
85 | for (unsigned i = 0; i < maxNumBalls; i++) { |
| 3048 | 80 | balls[i].lastBounceUpdate = strip().now; | |
| 3049 | 80 | balls[i].velocity = 20.0f * float(hw_random16(1000, 10000))/10000.0f; // number from 1 to 10 | |
| 3050 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 48 times.
|
80 | if (hw_random8()<128) balls[i].velocity = -balls[i].velocity; // 50% chance of reverse direction |
| 3051 | 80 | balls[i].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1. | |
| 3052 | 80 | balls[i].mass = (float(hw_random16(1000, 10000)) / 10000.0f); // from .1 to 1. | |
| 3053 | } | ||
| 3054 | } | ||
| 3055 | |||
| 3056 | 23 | float cfac = float(scale8(8, 255-SEGMENT.speed) +1)*20000.0f; // this uses the Aircoookie conversion factor for scaling time using speed slider | |
| 3057 | |||
| 3058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGMENT.check3) SEGMENT.fade_out(250); // 2-8 pixel trails (optional) |
| 3059 | else { | ||
| 3060 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // don't fill with background color if user wants to see trails |
| 3061 | } | ||
| 3062 | |||
| 3063 |
2/2✓ Branch 0 taken 203 times.
✓ Branch 1 taken 23 times.
|
226 | for (unsigned i = 0; i < numBalls; i++) { |
| 3064 | 203 | float timeSinceLastUpdate = float((strip().now - balls[i].lastBounceUpdate))/cfac; | |
| 3065 | 203 | float thisHeight = balls[i].height + balls[i].velocity * timeSinceLastUpdate; // this method keeps higher resolution | |
| 3066 | // test if intensity level was increased and some balls are way off the track then put them back | ||
| 3067 |
2/4✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
|
203 | if (thisHeight < -0.5f || thisHeight > 1.5f) { |
| 3068 | ✗ | thisHeight = balls[i].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1. | |
| 3069 | ✗ | balls[i].lastBounceUpdate = strip().now; | |
| 3070 | } | ||
| 3071 | // check if reached ends of the strip | ||
| 3072 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 202 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
203 | if ((thisHeight <= 0.0f && balls[i].velocity < 0.0f) || (thisHeight >= 1.0f && balls[i].velocity > 0.0f)) { |
| 3073 | 1 | balls[i].velocity = -balls[i].velocity; // reverse velocity | |
| 3074 | 1 | balls[i].lastBounceUpdate = strip().now; | |
| 3075 | 1 | balls[i].height = thisHeight; | |
| 3076 | } | ||
| 3077 | // check for collisions | ||
| 3078 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | if (SEGMENT.check1) { |
| 3079 | ✗ | for (unsigned j = i+1; j < numBalls; j++) { | |
| 3080 | ✗ | if (balls[j].velocity != balls[i].velocity) { | |
| 3081 | // tcollided + balls[j].lastBounceUpdate is acutal time of collision (this keeps precision with long to float conversions) | ||
| 3082 | ✗ | float tcollided = (cfac*(balls[i].height - balls[j].height) + | |
| 3083 | ✗ | balls[i].velocity*float(balls[j].lastBounceUpdate - balls[i].lastBounceUpdate))/(balls[j].velocity - balls[i].velocity); | |
| 3084 | |||
| 3085 | ✗ | if ((tcollided > 2.0f) && (tcollided < float(strip().now - balls[j].lastBounceUpdate))) { // 2ms minimum to avoid duplicate bounces | |
| 3086 | ✗ | balls[i].height = balls[i].height + balls[i].velocity*(tcollided + float(balls[j].lastBounceUpdate - balls[i].lastBounceUpdate))/cfac; | |
| 3087 | ✗ | balls[j].height = balls[i].height; | |
| 3088 | ✗ | balls[i].lastBounceUpdate = (unsigned long)(tcollided + 0.5f) + balls[j].lastBounceUpdate; | |
| 3089 | ✗ | balls[j].lastBounceUpdate = balls[i].lastBounceUpdate; | |
| 3090 | ✗ | float vtmp = balls[i].velocity; | |
| 3091 | ✗ | balls[i].velocity = ((balls[i].mass - balls[j].mass)*vtmp + 2.0f*balls[j].mass*balls[j].velocity)/(balls[i].mass + balls[j].mass); | |
| 3092 | ✗ | balls[j].velocity = ((balls[j].mass - balls[i].mass)*balls[j].velocity + 2.0f*balls[i].mass*vtmp) /(balls[i].mass + balls[j].mass); | |
| 3093 | ✗ | thisHeight = balls[i].height + balls[i].velocity*(strip().now - balls[i].lastBounceUpdate)/cfac; | |
| 3094 | } | ||
| 3095 | } | ||
| 3096 | } | ||
| 3097 | } | ||
| 3098 | |||
| 3099 | 203 | uint32_t color = SEGCOLOR(0); | |
| 3100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | if (SEGMENT.palette) { |
| 3101 | //color = SEGMENT.color_wheel(i*(256/MAX(numBalls, 8))); | ||
| 3102 | ✗ | color = SEGMENT.color_from_palette(i*255/numBalls, false, PALETTE_SOLID_WRAP, 0); | |
| 3103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | } else if (hasCol2) { |
| 3104 | ✗ | color = SEGCOLOR(i % NUM_COLORS); | |
| 3105 | } | ||
| 3106 | |||
| 3107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
|
203 | if (thisHeight < 0.0f) thisHeight = 0.0f; |
| 3108 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 202 times.
|
203 | if (thisHeight > 1.0f) thisHeight = 1.0f; |
| 3109 | 203 | unsigned pos = round(thisHeight * (SEGLEN - 1)); | |
| 3110 | 203 | SEGMENT.setPixelColor(pos, color); | |
| 3111 | 203 | balls[i].lastBounceUpdate = strip().now; | |
| 3112 | 203 | balls[i].height = thisHeight; | |
| 3113 | } | ||
| 3114 | |||
| 3115 | 23 | return FRAMETIME; | |
| 3116 | } | ||
| 3117 | static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of balls,,,,Collide,Overlay,Trails;!,!,!;!;1;m12=1"; //bar | ||
| 3118 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 3119 | |||
| 3120 | /* | ||
| 3121 | * Shimmer (ported from upstream WLED) | ||
| 3122 | * A pulse of light moves across the segment. Pulses appear at randomized intervals. | ||
| 3123 | */ | ||
| 3124 | 33 | static uint16_t mode_shimmer() { | |
| 3125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | if (!SEGENV.allocateData(sizeof(uint32_t))) return mode_static(); |
| 3126 | 33 | uint32_t* lastTime = reinterpret_cast<uint32_t*>(SEGENV.data); | |
| 3127 | |||
| 3128 | 33 | uint32_t radius = (SEGMENT.custom1 * SEGLEN >> 7) + 1; // [1, 2*SEGLEN+1] pixels | |
| 3129 | 33 | uint32_t traversalDistance = (SEGLEN + 2 * radius) << 8; // total subpixels to cross, 1 pixel = 256 subpixels | |
| 3130 | 33 | uint32_t traversalTime = 200 + (255 - SEGMENT.speed) * 80; // [200, 20600] ms | |
| 3131 | 33 | uint32_t speed = ((traversalDistance << 5) / traversalTime); // subpixels/512ms | |
| 3132 | 33 | int32_t position = static_cast<int32_t>(SEGENV.step); // current position in subpixels | |
| 3133 | 33 | uint16_t inputstate = (uint16_t(SEGMENT.intensity) << 8) | uint16_t(SEGMENT.custom1); | |
| 3134 | |||
| 3135 |
5/6✓ Branch 0 taken 27 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 27 times.
|
33 | if (SEGENV.call == 0 || inputstate != SEGENV.aux1) { |
| 3136 | 6 | position = -(int32_t)(radius << 8); | |
| 3137 | 6 | SEGENV.aux0 = 0; // pause timer | |
| 3138 | 6 | *lastTime = strip().now; | |
| 3139 | 6 | SEGENV.aux1 = inputstate; | |
| 3140 | } | ||
| 3141 | |||
| 3142 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4 times.
|
33 | if (SEGMENT.speed) { |
| 3143 | 29 | uint32_t deltaTime = (strip().now - *lastTime) & 0x7F; // clamp to 127ms | |
| 3144 | 29 | *lastTime = strip().now; | |
| 3145 | |||
| 3146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (SEGENV.aux0 > 0) { |
| 3147 | ✗ | SEGENV.aux0 = (SEGENV.aux0 > deltaTime) ? SEGENV.aux0 - deltaTime : 0; | |
| 3148 | } else { | ||
| 3149 | 29 | int32_t step = 1 + ((speed * deltaTime) >> 5); | |
| 3150 | 29 | position += step; | |
| 3151 | 29 | int endposition = (SEGLEN + radius) << 8; | |
| 3152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (position > endposition) { |
| 3153 | ✗ | SEGENV.aux0 = SEGMENT.intensity * 236; // [0, 60180] ms pause | |
| 3154 | ✗ | if (SEGMENT.check3) SEGENV.aux0 = hw_random(SEGENV.aux0 + 1000); | |
| 3155 | ✗ | position = -(int32_t)(radius << 8); | |
| 3156 | } | ||
| 3157 | 29 | SEGENV.step = (uint32_t)position; | |
| 3158 | } | ||
| 3159 | |||
| 3160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (SEGMENT.check2) |
| 3161 | ✗ | position = (SEGLEN << 8) - position; // invert position | |
| 3162 | } else { | ||
| 3163 | 4 | position = (SEGLEN << 7); // static center | |
| 3164 | } | ||
| 3165 | |||
| 3166 |
2/2✓ Branch 0 taken 12631 times.
✓ Branch 1 taken 33 times.
|
12664 | for (int i = 0; i < (int)SEGLEN; i++) { |
| 3167 | 12631 | uint32_t dist = abs(position - (i << 8)); | |
| 3168 |
2/2✓ Branch 0 taken 3055 times.
✓ Branch 1 taken 9576 times.
|
12631 | if (dist < (radius << 8)) { |
| 3169 | 3055 | uint32_t color = SEGMENT.color_from_palette(i * 255 / SEGLEN, false, false, 0); | |
| 3170 | 3055 | uint8_t blend = dist / radius; // [0, 255] | |
| 3171 |
2/2✓ Branch 0 taken 1537 times.
✓ Branch 1 taken 1518 times.
|
3055 | if (SEGMENT.custom2) { |
| 3172 | uint8_t modVal; | ||
| 3173 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1537 times.
|
1537 | if (SEGMENT.check1) { |
| 3174 | ✗ | modVal = (sin16_t((i * SEGMENT.custom2 << 6) + (strip().now * SEGMENT.custom3 << 5)) >> 8) + 128; | |
| 3175 | } else { | ||
| 3176 | 1537 | modVal = perlin16((i * SEGMENT.custom2 << 7), strip().now * SEGMENT.custom3 << 5) >> 8; | |
| 3177 | } | ||
| 3178 | 1537 | color = color_fade(color, modVal, true); | |
| 3179 | } | ||
| 3180 | 3055 | SEGMENT.setPixelColor(i, color_blend(color, SEGCOLOR(1), blend)); | |
| 3181 | } else { | ||
| 3182 | 9576 | SEGMENT.setPixelColor(i, SEGCOLOR(1)); | |
| 3183 | } | ||
| 3184 | } | ||
| 3185 | 33 | return FRAMETIME; | |
| 3186 | } | ||
| 3187 | static const char _data_FX_MODE_SHIMMER[] PROGMEM = "Shimmer@Speed,Interval,Size,Granular,Flow,Zebra,Reverse,Sporadic;Fx,Bg,Cx;!;1;pal=15,sx=220,ix=10,c2=0,c3=0"; | ||
| 3188 | |||
| 3189 | |||
| 3190 | ///////////////////////// | ||
| 3191 | // Copy Segment // | ||
| 3192 | ///////////////////////// | ||
| 3193 | // Mirrors another segment into this one, with optional hue/saturation/value adjustment. | ||
| 3194 | // Ported from upstream WLED. Note: upstream reads either the source segment's own pixel | ||
| 3195 | // buffer or the global (last rendered frame) buffer depending on check2. This fork has no | ||
| 3196 | // per-segment buffers -- Segment::getPixelColor* already reads the shared strip buffer -- | ||
| 3197 | // so both paths resolve to the same source here and check2 has no visible effect. The | ||
| 3198 | // option is kept so the mode data stays in step with upstream. | ||
| 3199 | ✗ | uint16_t mode_copy_segment(void) { | |
| 3200 | ✗ | const unsigned sourceid = SEGMENT.custom3; | |
| 3201 | ✗ | if (sourceid >= strip().getSegmentsNum() || sourceid == strip().getCurrSegmentId()) { // invalid source | |
| 3202 | ✗ | SEGMENT.fadeToBlackBy(5); // fade out | |
| 3203 | ✗ | return FRAMETIME; | |
| 3204 | } | ||
| 3205 | ✗ | Segment& sourcesegment = strip().getSegment(sourceid); | |
| 3206 | ✗ | if (!sourcesegment.isActive()) return FRAMETIME; | |
| 3207 | |||
| 3208 | uint32_t color; | ||
| 3209 | ✗ | if (sourcesegment.is2D()) { // 2D source; copying 2D to 1D takes the first row (or column if 'Switch axis' is set) | |
| 3210 | ✗ | const unsigned vH = SEGMENT.vHeight(); | |
| 3211 | ✗ | const unsigned vW = SEGMENT.vWidth(); | |
| 3212 | ✗ | for (unsigned y = 0; y < vH; y++) { | |
| 3213 | ✗ | for (unsigned x = 0; x < vW; x++) { | |
| 3214 | ✗ | unsigned sx = x; // source coordinates | |
| 3215 | ✗ | unsigned sy = y; | |
| 3216 | ✗ | if (SEGMENT.check1) std::swap(sx, sy); // flip axis | |
| 3217 | ✗ | sourcesegment.setDrawDimensions(); // address the source segment | |
| 3218 | ✗ | color = sourcesegment.getPixelColorXY(sx, sy); | |
| 3219 | ✗ | adjust_color(color, SEGMENT.intensity, SEGMENT.custom1, SEGMENT.custom2); // hue shift, sat change, value change | |
| 3220 | ✗ | SEGMENT.setDrawDimensions(); // back to this segment | |
| 3221 | ✗ | SEGMENT.setPixelColorXY(x, y, color); | |
| 3222 | } | ||
| 3223 | } | ||
| 3224 | } else { // 1D source, can be expanded into 2D | ||
| 3225 | ✗ | const unsigned vL = SEGMENT.vLength(); | |
| 3226 | ✗ | for (unsigned i = 0; i < vL; i++) { | |
| 3227 | ✗ | sourcesegment.setDrawDimensions(); | |
| 3228 | ✗ | color = sourcesegment.getPixelColor(i); | |
| 3229 | ✗ | adjust_color(color, SEGMENT.intensity, SEGMENT.custom1, SEGMENT.custom2); | |
| 3230 | ✗ | SEGMENT.setDrawDimensions(); | |
| 3231 | ✗ | SEGMENT.setPixelColor(i, color); | |
| 3232 | } | ||
| 3233 | } | ||
| 3234 | |||
| 3235 | ✗ | return FRAMETIME; | |
| 3236 | } | ||
| 3237 | static const char _data_FX_MODE_COPY[] PROGMEM = "Copy Segment@,Color shift,Lighten,Brighten,ID,Axis(2D),FullStack(last frame);;;12;ix=0,c1=0,c2=0,c3=0"; | ||
| 3238 | |||
| 3239 | /* | ||
| 3240 | * Color Clouds (ported from upstream WLED) | ||
| 3241 | * Soft, drifting cloud-like colors driven by 2D perlin noise. | ||
| 3242 | */ | ||
| 3243 | 34 | static uint16_t mode_ColorClouds() { | |
| 3244 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 28 times.
|
34 | if (SEGENV.call == 0) { |
| 3245 | 6 | SEGENV.aux0 = hw_random16(); | |
| 3246 | 6 | SEGENV.aux1 = hw_random16(); | |
| 3247 | } | ||
| 3248 | 34 | const uint32_t volX0 = SEGENV.aux0; | |
| 3249 | 34 | const uint32_t hueX0 = SEGENV.aux1; | |
| 3250 | 34 | const uint8_t hueOffset0 = volX0 + hueX0; | |
| 3251 | |||
| 3252 | 34 | const bool cozy = SEGMENT.check3; | |
| 3253 | |||
| 3254 | 34 | const uint32_t volSpeed = 1 + SEGMENT.speed; | |
| 3255 | 34 | const uint32_t hueSpeed = 1 + SEGMENT.intensity; | |
| 3256 | 34 | const uint32_t volSqueeze = 8 + SEGMENT.custom1; | |
| 3257 | 34 | const uint32_t hueSqueeze = SEGMENT.custom2; | |
| 3258 | |||
| 3259 | 34 | const int32_t volCutoff = 12500 + SEGMENT.custom3 * 900; | |
| 3260 | 34 | const int32_t volSaturate = 52000; | |
| 3261 | |||
| 3262 | 34 | const uint32_t now = strip().now; | |
| 3263 | 34 | const uint32_t volT = now * volSpeed / 8; | |
| 3264 | 34 | const uint32_t hueT = now * hueSpeed / 8; | |
| 3265 | 34 | const uint8_t hueOffset = beat88(64) >> 8; | |
| 3266 | |||
| 3267 |
2/2✓ Branch 0 taken 13143 times.
✓ Branch 1 taken 34 times.
|
13177 | for (int i = 0; i < (int)SEGLEN; i++) { |
| 3268 | 13143 | const uint32_t volX = i * volSqueeze * 64; | |
| 3269 | 13143 | int32_t vol = perlin16(volX0 + volX, volT); | |
| 3270 | 13143 | vol = map(vol, volCutoff, volSaturate, 0, 255); | |
| 3271 |
2/2✓ Branch 0 taken 10331 times.
✓ Branch 1 taken 2812 times.
|
13143 | vol = constrain(vol, 0, 255); |
| 3272 | |||
| 3273 | 13143 | const uint32_t hueX = i * hueSqueeze * 8; | |
| 3274 | 13143 | uint8_t hue = perlin16(hueX0 + hueX, hueT) >> 7; | |
| 3275 | 13143 | hue += hueOffset0; | |
| 3276 | 13143 | hue += hueOffset; | |
| 3277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13143 times.
|
13143 | if (cozy) { |
| 3278 | ✗ | hue = cos8_t(128 + hue / 2); | |
| 3279 | } | ||
| 3280 | |||
| 3281 | uint32_t pixel; | ||
| 3282 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13143 times.
|
13143 | if (SEGMENT.palette) { |
| 3283 | ✗ | pixel = SEGMENT.color_from_palette(hue, false, true, 0, vol); | |
| 3284 | } else { | ||
| 3285 | // CHSV(hue, 255, vol) -> CRGB -> CRGBW (FPP doesn't have CHSV32 ctor for CRGBW) | ||
| 3286 | CRGB tmp; | ||
| 3287 |
1/2✓ Branch 0 taken 13143 times.
✗ Branch 1 not taken.
|
13143 | hsv2rgb_rainbow(CHSV((uint8_t)hue, (uint8_t)255, (uint8_t)vol), tmp); |
| 3288 | 26286 | pixel = CRGBW(tmp); | |
| 3289 | } | ||
| 3290 | |||
| 3291 |
2/2✓ Branch 0 taken 3349 times.
✓ Branch 1 taken 9794 times.
|
13143 | if (int(R(pixel)) + G(pixel) + B(pixel) <= 2) { |
| 3292 | 3349 | pixel = 0; | |
| 3293 | } | ||
| 3294 | |||
| 3295 | 13143 | SEGMENT.setPixelColor(i, pixel); | |
| 3296 | } | ||
| 3297 | 34 | return FRAMETIME; | |
| 3298 | } | ||
| 3299 | static const char _data_FX_MODE_COLORCLOUDS[] PROGMEM = "Color Clouds@!,!,Clouds,Colors,Distance,,,Cozy;;!;;sx=24,ix=32,c1=48,c2=64,c3=12,pal=0"; | ||
| 3300 | |||
| 3301 | /* | ||
| 3302 | * PacMan (ported from upstream WLED) | ||
| 3303 | * The classic chase across the strip — PacMan + ghosts + power dots. | ||
| 3304 | */ | ||
| 3305 | typedef struct PacManChars { | ||
| 3306 | signed pos; | ||
| 3307 | signed topPos; // LED position of farthest PacMan has moved | ||
| 3308 | uint32_t color; | ||
| 3309 | bool direction; // true = moving away from first LED | ||
| 3310 | bool blue; // used for ghosts only | ||
| 3311 | bool eaten; // used for power dots only | ||
| 3312 | } pacmancharacters_t; | ||
| 3313 | |||
| 3314 | 33 | static uint16_t mode_pacman(void) { | |
| 3315 | 33 | constexpr unsigned ORANGEYELLOW = 0xFFCC00; | |
| 3316 | 33 | constexpr unsigned PURPLEISH = 0xB000B0; | |
| 3317 | 33 | constexpr unsigned ORANGEISH = 0xFF8800; | |
| 3318 | 33 | constexpr unsigned WHITEISH = 0x999999; | |
| 3319 | 33 | constexpr unsigned PACMAN = 0; | |
| 3320 | 33 | constexpr uint32_t ghostColors[] = {RED, PURPLEISH, CYAN, ORANGEISH}; | |
| 3321 | |||
| 3322 | 33 | unsigned maxPowerDots = std::min<unsigned>(SEGLEN / 10U, 255U); | |
| 3323 |
2/4✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 | unsigned numPowerDots = map(SEGMENT.intensity, 0, 255, 1, maxPowerDots); |
| 3324 |
2/4✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 | unsigned numGhosts = map(SEGMENT.custom3, 0, 31, 2, 8); |
| 3325 |
2/4✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 | bool smearMode = SEGMENT.check2; |
| 3326 | |||
| 3327 | 33 | uint16_t combined_value = uint16_t(((numPowerDots & 0xFF) << 8) | (numGhosts & 0xFF)); | |
| 3328 |
6/10✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
|
33 | if (combined_value != SEGENV.aux0) SEGENV.call = 0; |
| 3329 |
2/4✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 | SEGENV.aux0 = combined_value; |
| 3330 | |||
| 3331 | 33 | unsigned dataSize = sizeof(pacmancharacters_t) * (numGhosts + maxPowerDots + 1); | |
| 3332 |
9/14✓ Branch 0 taken 28 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 28 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 28 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
33 | if (SEGLEN <= 16 + (2 * numGhosts) || !SEGENV.allocateData(dataSize)) return mode_static(); |
| 3333 |
2/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | pacmancharacters_t *character = reinterpret_cast<pacmancharacters_t *>(SEGENV.data); |
| 3334 | |||
| 3335 |
4/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 23 times.
|
28 | int maxBlinkPos = (SEGENV.call == 0) ? (int)SEGLEN - 1 : character[PACMAN].topPos; |
| 3336 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 5 times.
|
28 | if (maxBlinkPos < 20) maxBlinkPos = 20; |
| 3337 | 28 | int startBlinkingGhostsLED = (SEGLEN < 64) | |
| 3338 | ✗ | ? (int)SEGLEN / 3 | |
| 3339 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | : map(SEGMENT.custom1, 0, 255, 20, maxBlinkPos); |
| 3340 | |||
| 3341 |
4/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 23 times.
|
28 | if (SEGENV.call == 0) { |
| 3342 | 5 | character[PACMAN].color = YELLOW; | |
| 3343 | 5 | character[PACMAN].pos = 0; | |
| 3344 | 5 | character[PACMAN].topPos = 0; | |
| 3345 | 5 | character[PACMAN].direction = true; | |
| 3346 | 5 | character[PACMAN].blue = false; | |
| 3347 | |||
| 3348 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 5 times.
|
27 | for (unsigned i = 1; i <= numGhosts; i++) { |
| 3349 | 22 | character[i].color = ghostColors[(i - 1) % 4]; | |
| 3350 | 22 | character[i].pos = -2 * (int)(i + 1); | |
| 3351 | 22 | character[i].direction = true; | |
| 3352 | 22 | character[i].blue = false; | |
| 3353 | } | ||
| 3354 | |||
| 3355 |
2/2✓ Branch 0 taken 82 times.
✓ Branch 1 taken 5 times.
|
87 | for (unsigned i = 0; i < numPowerDots; i++) { |
| 3356 | 82 | character[i + numGhosts + 1].color = ORANGEYELLOW; | |
| 3357 | 82 | character[i + numGhosts + 1].eaten = false; | |
| 3358 | } | ||
| 3359 | 5 | character[numGhosts + 1].pos = SEGLEN - 1; | |
| 3360 | } | ||
| 3361 | |||
| 3362 |
4/8✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
|
28 | if (strip().now > SEGENV.step) { |
| 3363 |
3/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | SEGENV.step = strip().now; |
| 3364 |
2/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | SEGENV.aux1++; |
| 3365 | } | ||
| 3366 | |||
| 3367 |
4/8✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
|
28 | if (!smearMode) SEGMENT.fill(BLACK); |
| 3368 | |||
| 3369 |
3/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | if (SEGMENT.check1) { |
| 3370 |
3/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
|
28 | int step = SEGMENT.check3 ? 1 : 2; |
| 3371 |
2/2✓ Branch 0 taken 6254 times.
✓ Branch 1 taken 28 times.
|
6282 | for (int i = (int)SEGLEN - 1; i > character[PACMAN].topPos; i -= step) { |
| 3372 |
3/6✓ Branch 0 taken 6254 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6254 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6254 times.
✗ Branch 5 not taken.
|
6254 | SEGMENT.setPixelColor(i, WHITEISH); |
| 3373 | } | ||
| 3374 | } | ||
| 3375 | |||
| 3376 | 28 | uint32_t everyXLeds = (((uint32_t)SEGLEN - 10U) << 8) / numPowerDots; | |
| 3377 |
2/2✓ Branch 0 taken 395 times.
✓ Branch 1 taken 28 times.
|
423 | for (unsigned i = 1; i < numPowerDots; i++) { |
| 3378 | 395 | character[i + numGhosts + 1].pos = 10 + ((i * everyXLeds) >> 8); | |
| 3379 | } | ||
| 3380 | |||
| 3381 |
4/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 27 times.
|
28 | if (SEGENV.aux1 % 10 == 0) { |
| 3382 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | uint32_t dotColor = (character[numGhosts + 1].color == ORANGEYELLOW) ? BLACK : ORANGEYELLOW; |
| 3383 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
|
14 | for (unsigned i = 0; i < numPowerDots; i++) { |
| 3384 | 13 | character[i + numGhosts + 1].color = dotColor; | |
| 3385 | } | ||
| 3386 | } | ||
| 3387 | |||
| 3388 |
4/12✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 28 times.
|
28 | if (SEGENV.aux1 % 15 == 0 && character[1].blue && character[PACMAN].pos <= startBlinkingGhostsLED) { |
| 3389 | ✗ | uint32_t ghostColor = (character[1].color == BLUE) ? WHITEISH : BLUE; | |
| 3390 | ✗ | for (unsigned i = 1; i <= numGhosts; i++) { | |
| 3391 | ✗ | character[i].color = ghostColor; | |
| 3392 | } | ||
| 3393 | } | ||
| 3394 | |||
| 3395 |
2/2✓ Branch 0 taken 423 times.
✓ Branch 1 taken 28 times.
|
451 | for (unsigned i = 0; i < numPowerDots; i++) { |
| 3396 |
3/6✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 423 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 423 times.
✗ Branch 5 not taken.
|
423 | if (!character[i + numGhosts + 1].eaten && (unsigned)character[i + numGhosts + 1].pos < SEGLEN) { |
| 3397 |
3/6✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 423 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 423 times.
✗ Branch 5 not taken.
|
423 | SEGMENT.setPixelColor(character[i + numGhosts + 1].pos, character[i + numGhosts + 1].color); |
| 3398 | } | ||
| 3399 | } | ||
| 3400 | |||
| 3401 |
2/2✓ Branch 0 taken 423 times.
✓ Branch 1 taken 28 times.
|
451 | for (unsigned j = 0; j < numPowerDots; j++) { |
| 3402 | 423 | auto &dot = character[j + numGhosts + 1]; | |
| 3403 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
423 | if (character[PACMAN].pos == dot.pos && !dot.eaten) { |
| 3404 | ✗ | for (unsigned i = 0; i <= numGhosts; i++) { | |
| 3405 | ✗ | character[i].direction = false; | |
| 3406 | } | ||
| 3407 | ✗ | for (unsigned i = 1; i <= numGhosts; i++) { | |
| 3408 | ✗ | character[i].color = BLUE; | |
| 3409 | ✗ | character[i].blue = true; | |
| 3410 | } | ||
| 3411 | ✗ | dot.eaten = true; | |
| 3412 | ✗ | break; | |
| 3413 | } | ||
| 3414 | } | ||
| 3415 | |||
| 3416 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
28 | if (character[1].blue && character[PACMAN].pos <= 0) { |
| 3417 | ✗ | for (unsigned i = 0; i <= numGhosts; i++) { | |
| 3418 | ✗ | character[i].direction = true; | |
| 3419 | } | ||
| 3420 | ✗ | for (unsigned i = 1; i <= numGhosts; i++) { | |
| 3421 | ✗ | character[i].color = ghostColors[(i - 1) % 4]; | |
| 3422 | ✗ | character[i].blue = false; | |
| 3423 | } | ||
| 3424 | ✗ | if (character[numGhosts + 1].eaten) { | |
| 3425 | ✗ | for (unsigned i = 0; i < numPowerDots; i++) { | |
| 3426 | ✗ | character[i + numGhosts + 1].eaten = false; | |
| 3427 | } | ||
| 3428 | ✗ | character[PACMAN].topPos = 0; | |
| 3429 | } | ||
| 3430 | } | ||
| 3431 | |||
| 3432 |
4/8✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
|
28 | bool updatePositions = (SEGENV.aux1 % map(SEGMENT.speed, 0, 255, 15, 1) == 0); |
| 3433 | |||
| 3434 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 20 times.
|
28 | if (updatePositions) { |
| 3435 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | character[PACMAN].pos += character[PACMAN].direction ? 1 : -1; |
| 3436 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 8 times.
|
56 | for (unsigned i = 1; i <= numGhosts; i++) { |
| 3437 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | character[i].pos += character[i].direction ? 1 : -1; |
| 3438 | } | ||
| 3439 | } | ||
| 3440 | |||
| 3441 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if ((unsigned)character[PACMAN].pos < SEGLEN) { |
| 3442 |
3/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | SEGMENT.setPixelColor(character[PACMAN].pos, character[PACMAN].color); |
| 3443 | } | ||
| 3444 | |||
| 3445 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 28 times.
|
148 | for (unsigned i = 1; i <= numGhosts; i++) { |
| 3446 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 119 times.
|
120 | if ((unsigned)character[i].pos < SEGLEN) { |
| 3447 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | SEGMENT.setPixelColor(character[i].pos, character[i].color); |
| 3448 | } | ||
| 3449 | } | ||
| 3450 | |||
| 3451 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 20 times.
|
28 | if (character[PACMAN].topPos < character[PACMAN].pos) { |
| 3452 | 8 | character[PACMAN].topPos = character[PACMAN].pos; | |
| 3453 | } | ||
| 3454 | |||
| 3455 |
5/10✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 9 not taken.
|
28 | SEGMENT.blur(SEGMENT.custom2 >> 1); |
| 3456 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | return FRAMETIME; |
| 3457 | } | ||
| 3458 | static const char _data_FX_MODE_PACMAN[] PROGMEM = "PacMan@Speed,# of PowerDots,Blink distance,Blur,# of Ghosts,Dots,Smear,Compact;;!;1;m12=0,sx=192,ix=64,c1=64,c2=0,c3=12,o1=1,o2=0"; | ||
| 3459 | |||
| 3460 | /* | ||
| 3461 | * Slow Transition (ported from upstream WLED) | ||
| 3462 | * Smoothly cross-fades the current palette / white / CCT to the selected target | ||
| 3463 | * over a user-specified time window (1-255 minutes). When the user changes the | ||
| 3464 | * palette mid-transition, blending re-anchors to the current state. | ||
| 3465 | */ | ||
| 3466 | typedef struct SlowTransitionData { | ||
| 3467 | CRGBPalette16 startPalette; | ||
| 3468 | CRGBPalette16 currentPalette; | ||
| 3469 | CRGBPalette16 endPalette; | ||
| 3470 | uint8_t startWhite; | ||
| 3471 | uint8_t currentWhite; | ||
| 3472 | uint8_t endWhite; | ||
| 3473 | uint8_t startCCT; | ||
| 3474 | uint8_t currentCCT; | ||
| 3475 | uint8_t endCCT; | ||
| 3476 | } slow_transition_data; | ||
| 3477 | |||
| 3478 | 34 | static uint16_t mode_slow_transition(void) { | |
| 3479 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | uint32_t* startTime = &SEGMENT.step; |
| 3480 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | uint16_t* stepsDone = &SEGMENT.aux0; |
| 3481 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | uint16_t* startSpeed = &SEGMENT.aux1; |
| 3482 | |||
| 3483 | 34 | size_t dataSize = sizeof(slow_transition_data); | |
| 3484 |
4/10✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 34 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
34 | if (!SEGMENT.allocateData(dataSize)) return mode_static(); |
| 3485 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | slow_transition_data* data = reinterpret_cast<slow_transition_data*>(SEGMENT.data); |
| 3486 | 34 | bool changed = (data->endPalette != SEGPALETTE | |
| 3487 | ✗ | || *startSpeed != SEGMENT.speed | |
| 3488 | ✗ | || data->endWhite != W(SEGCOLOR(0)) | |
| 3489 |
1/8✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
34 | || data->currentCCT != SEGMENT.cct); |
| 3490 | |||
| 3491 |
2/10✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 34 times.
✗ Branch 9 not taken.
|
34 | if (changed || SEGMENT.call == 0) { |
| 3492 |
4/6✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 28 times.
|
34 | if (SEGMENT.call == 0) { |
| 3493 | 6 | data->startPalette = SEGPALETTE; | |
| 3494 | 6 | data->currentPalette = SEGPALETTE; | |
| 3495 | 6 | data->endPalette = SEGPALETTE; | |
| 3496 | 6 | data->startWhite = data->currentWhite = data->endWhite = W(SEGCOLOR(0)); | |
| 3497 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | data->startCCT = data->currentCCT = data->endCCT = SEGMENT.cct; |
| 3498 | 6 | *stepsDone = 0xFFFF; | |
| 3499 | } else { | ||
| 3500 | 28 | data->startPalette = data->currentPalette; | |
| 3501 | 28 | data->endPalette = SEGPALETTE; | |
| 3502 | 28 | data->startWhite = data->currentWhite; | |
| 3503 | 28 | data->endWhite = W(SEGCOLOR(0)); | |
| 3504 | 28 | data->startCCT = data->currentCCT; | |
| 3505 |
2/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | data->endCCT = SEGMENT.cct; |
| 3506 | 28 | *stepsDone = 0; | |
| 3507 | } | ||
| 3508 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | *startSpeed = SEGMENT.speed; |
| 3509 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | *startTime = millis(); |
| 3510 | } | ||
| 3511 | |||
| 3512 |
3/6✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
|
34 | uint32_t totalSteps = SEGMENT.check2 ? 16 * 255 : 255; |
| 3513 |
6/10✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
34 | uint32_t duration = (SEGMENT.speed == 0) ? 10000 : (uint32_t)SEGMENT.speed * 60000; |
| 3514 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | uint32_t elapsed = millis() - *startTime; |
| 3515 | 34 | uint32_t expectedSteps = (uint64_t)elapsed * totalSteps / duration; | |
| 3516 | 34 | expectedSteps = std::min<uint32_t>(expectedSteps, totalSteps); | |
| 3517 | |||
| 3518 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 28 times.
|
34 | if (*stepsDone > expectedSteps) |
| 3519 | 6 | *stepsDone = expectedSteps; | |
| 3520 | |||
| 3521 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (*stepsDone < expectedSteps) { |
| 3522 | ✗ | *stepsDone = expectedSteps; | |
| 3523 | uint8_t blendAmount; | ||
| 3524 | ✗ | if (SEGMENT.check2) { | |
| 3525 | ✗ | uint8_t i = *stepsDone % 16; | |
| 3526 | ✗ | blendAmount = *stepsDone / 16; | |
| 3527 | ✗ | data->currentPalette[i] = CRGB(color_blend((uint32_t)CRGBW(data->startPalette[i]), | |
| 3528 | ✗ | (uint32_t)CRGBW(data->endPalette[i]), | |
| 3529 | ✗ | blendAmount)); | |
| 3530 | } else { | ||
| 3531 | ✗ | blendAmount = (uint8_t)*stepsDone; | |
| 3532 | ✗ | for (uint8_t i = 0; i < 16; i++) { | |
| 3533 | ✗ | data->currentPalette[i] = CRGB(color_blend((uint32_t)CRGBW(data->startPalette[i]), | |
| 3534 | ✗ | (uint32_t)CRGBW(data->endPalette[i]), | |
| 3535 | ✗ | blendAmount)); | |
| 3536 | } | ||
| 3537 | } | ||
| 3538 | ✗ | data->currentWhite = (data->startWhite * (255 - blendAmount) + data->endWhite * blendAmount) / 255; | |
| 3539 | ✗ | data->currentCCT = (data->startCCT * (255 - blendAmount) + data->endCCT * blendAmount) / 255; | |
| 3540 | ✗ | if (*stepsDone >= totalSteps) { | |
| 3541 | ✗ | data->currentPalette = data->endPalette; | |
| 3542 | ✗ | data->currentWhite = data->endWhite; | |
| 3543 | ✗ | data->currentCCT = data->endCCT; | |
| 3544 | } | ||
| 3545 | } | ||
| 3546 | |||
| 3547 |
2/2✓ Branch 0 taken 13143 times.
✓ Branch 1 taken 34 times.
|
13177 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 3548 | 13143 | uint8_t paletteIndex = (i * 255) / SEGLEN; | |
| 3549 |
1/2✓ Branch 0 taken 13143 times.
✗ Branch 1 not taken.
|
13143 | CRGBW palcol = ColorFromPalette(data->currentPalette, paletteIndex, 255, LINEARBLEND_NOWRAP); |
| 3550 | 13143 | palcol.w = data->currentWhite; | |
| 3551 |
3/6✓ Branch 0 taken 13143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13143 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13143 times.
✗ Branch 5 not taken.
|
13143 | SEGMENT.setPixelColor(i, palcol.color32); |
| 3552 | } | ||
| 3553 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | SEGMENT.cct = data->currentCCT; |
| 3554 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | return FRAMETIME; |
| 3555 | } | ||
| 3556 | static const char _data_FX_MODE_SLOW_TRANSITION[] PROGMEM = "Slow Transition@Time (min),,,,,,Sweep;!;!;1;pal=2,sx=0,ix=0"; | ||
| 3557 | |||
| 3558 | /* | ||
| 3559 | * Sinelon stolen from FASTLED examples | ||
| 3560 | */ | ||
| 3561 | 69 | static uint16_t sinelon_base(bool dual, bool rainbow=false) { | |
| 3562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
|
69 | if (SEGLEN <= 1) return mode_static(); |
| 3563 | 69 | SEGMENT.fade_out(SEGMENT.intensity); | |
| 3564 | 69 | unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1); | |
| 3565 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 54 times.
|
69 | if (SEGENV.call == 0) SEGENV.aux0 = pos; |
| 3566 | 69 | uint32_t color1 = SEGMENT.color_from_palette(pos, true, false, 0); | |
| 3567 | 69 | uint32_t color2 = SEGCOLOR(2); | |
| 3568 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 46 times.
|
69 | if (rainbow) { |
| 3569 | 23 | color1 = SEGMENT.color_wheel((pos & 0x07) * 32); | |
| 3570 | } | ||
| 3571 | 69 | SEGMENT.setPixelColor(pos, color1); | |
| 3572 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 46 times.
|
69 | if (dual) { |
| 3573 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!color2) color2 = SEGMENT.color_from_palette(pos, true, false, 0); |
| 3574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (rainbow) color2 = color1; //rainbow |
| 3575 | 23 | SEGMENT.setPixelColor(SEGLEN-1-pos, color2); | |
| 3576 | } | ||
| 3577 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 29 times.
|
69 | if (SEGENV.aux0 != pos) { |
| 3578 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | if (SEGENV.aux0 < pos) { |
| 3579 |
2/2✓ Branch 0 taken 450 times.
✓ Branch 1 taken 40 times.
|
490 | for (unsigned i = SEGENV.aux0; i < pos ; i++) { |
| 3580 | 450 | SEGMENT.setPixelColor(i, color1); | |
| 3581 |
2/2✓ Branch 0 taken 163 times.
✓ Branch 1 taken 287 times.
|
450 | if (dual) SEGMENT.setPixelColor(SEGLEN-1-i, color2); |
| 3582 | } | ||
| 3583 | } else { | ||
| 3584 | ✗ | for (unsigned i = SEGENV.aux0; i > pos ; i--) { | |
| 3585 | ✗ | SEGMENT.setPixelColor(i, color1); | |
| 3586 | ✗ | if (dual) SEGMENT.setPixelColor(SEGLEN-1-i, color2); | |
| 3587 | } | ||
| 3588 | } | ||
| 3589 | 40 | SEGENV.aux0 = pos; | |
| 3590 | } | ||
| 3591 | |||
| 3592 | 69 | return FRAMETIME; | |
| 3593 | } | ||
| 3594 | |||
| 3595 | |||
| 3596 | 23 | uint16_t mode_sinelon(void) { | |
| 3597 | 23 | return sinelon_base(false); | |
| 3598 | } | ||
| 3599 | static const char _data_FX_MODE_SINELON[] PROGMEM = "Sinelon@!,Trail;!,!,!;!"; | ||
| 3600 | |||
| 3601 | |||
| 3602 | 23 | uint16_t mode_sinelon_dual(void) { | |
| 3603 | 23 | return sinelon_base(true); | |
| 3604 | } | ||
| 3605 | static const char _data_FX_MODE_SINELON_DUAL[] PROGMEM = "Sinelon Dual@!,Trail;!,!,!;!"; | ||
| 3606 | |||
| 3607 | |||
| 3608 | 23 | uint16_t mode_sinelon_rainbow(void) { | |
| 3609 | 23 | return sinelon_base(false, true); | |
| 3610 | } | ||
| 3611 | static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!"; | ||
| 3612 | |||
| 3613 | |||
| 3614 | // utility function that will add random glitter to SEGMENT | ||
| 3615 | 46 | void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) { | |
| 3616 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 19 times.
|
46 | if (intensity > hw_random8()) SEGMENT.setPixelColor(hw_random16(SEGLEN), col); |
| 3617 | 46 | } | |
| 3618 | |||
| 3619 | //Glitter with palette background, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6 | ||
| 3620 | 23 | uint16_t mode_glitter() | |
| 3621 | { | ||
| 3622 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) { // use "* Color 1" palette for solid background (replacing "Solid glitter") |
| 3623 | 23 | unsigned counter = 0; | |
| 3624 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (SEGMENT.speed != 0) { |
| 3625 | 19 | counter = (strip().now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; | |
| 3626 | 19 | counter = counter >> 8; | |
| 3627 | } | ||
| 3628 | |||
| 3629 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
|
23 | bool noWrap = (strip().paletteBlend == 2 || (strip().paletteBlend == 0 && SEGMENT.speed == 0)); |
| 3630 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 3631 | 7511 | unsigned colorIndex = (i * 255 / SEGLEN) - counter; | |
| 3632 |
2/2✓ Branch 0 taken 2048 times.
✓ Branch 1 taken 5463 times.
|
7511 | if (noWrap) colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end" |
| 3633 | 7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, true, 255)); | |
| 3634 | } | ||
| 3635 | } | ||
| 3636 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE); |
| 3637 | 23 | return FRAMETIME; | |
| 3638 | } | ||
| 3639 | static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;,,Glitter color;!;;pal=11,m12=0"; //pixels | ||
| 3640 | |||
| 3641 | |||
| 3642 | //Solid colour background with glitter (can be replaced by Glitter) | ||
| 3643 | 23 | uint16_t mode_solid_glitter() | |
| 3644 | { | ||
| 3645 | 23 | SEGMENT.fill(SEGCOLOR(0)); | |
| 3646 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE); |
| 3647 | 23 | return FRAMETIME; | |
| 3648 | } | ||
| 3649 | static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;Bg,,Glitter color;;;m12=0"; | ||
| 3650 | |||
| 3651 | //each needs 20 bytes | ||
| 3652 | //Spark type is used for popcorn, 1D fireworks, and drip | ||
| 3653 | typedef struct Spark { | ||
| 3654 | float pos, posX; | ||
| 3655 | float vel, velX; | ||
| 3656 | uint16_t col; | ||
| 3657 | uint8_t colIndex; | ||
| 3658 | } spark; | ||
| 3659 | |||
| 3660 | #define maxNumPopcorn 21 // max 21 on 16 segment ESP8266 | ||
| 3661 | /* | ||
| 3662 | * POPCORN | ||
| 3663 | * modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h | ||
| 3664 | */ | ||
| 3665 | 23 | uint16_t mode_popcorn(void) { | |
| 3666 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 3667 | //allocate segment data | ||
| 3668 | 23 | unsigned strips = SEGMENT.nrOfVStrips(); | |
| 3669 | 23 | unsigned usablePopcorns = maxNumPopcorn; | |
| 3670 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
|
23 | if (usablePopcorns * strips * sizeof(spark) > FAIR_DATA_PER_SEG) usablePopcorns = FAIR_DATA_PER_SEG / (strips * sizeof(spark)) + 1; // at least 1 popcorn per vstrip |
| 3671 | 23 | unsigned dataSize = sizeof(spark) * usablePopcorns; // on a matrix 64x64 this could consume a little less than 27kB when Bar expansion is used | |
| 3672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed |
| 3673 | |||
| 3674 | 23 | Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data); | |
| 3675 | |||
| 3676 | 23 | bool hasCol2 = SEGCOLOR(2); | |
| 3677 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); |
| 3678 | |||
| 3679 | struct virtualStrip { | ||
| 3680 | 456 | static void runStrip(uint16_t stripNr, Spark* popcorn, unsigned usablePopcorns) { | |
| 3681 | 456 | float gravity = -0.0001f - (SEGMENT.speed/200000.0f); // m/s/s | |
| 3682 | 456 | gravity *= SEGLEN; | |
| 3683 | |||
| 3684 | 456 | unsigned numPopcorn = SEGMENT.intensity * usablePopcorns / 255; | |
| 3685 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 328 times.
|
456 | if (numPopcorn == 0) numPopcorn = 1; |
| 3686 | |||
| 3687 |
2/2✓ Branch 0 taken 897 times.
✓ Branch 1 taken 456 times.
|
1353 | for (unsigned i = 0; i < numPopcorn; i++) { |
| 3688 |
2/2✓ Branch 0 taken 415 times.
✓ Branch 1 taken 482 times.
|
897 | if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position |
| 3689 | 415 | popcorn[i].pos += popcorn[i].vel; | |
| 3690 | 415 | popcorn[i].vel += gravity; | |
| 3691 | } else { // if kernel is inactive, randomly pop it | ||
| 3692 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 479 times.
|
482 | if (hw_random8() < 2) { // POP!!! |
| 3693 | 3 | popcorn[i].pos = 0.01f; | |
| 3694 | |||
| 3695 | 3 | unsigned peakHeight = 128 + hw_random8(128); //0-255 | |
| 3696 | 3 | peakHeight = (peakHeight * (SEGLEN -1)) >> 8; | |
| 3697 | 3 | popcorn[i].vel = sqrtf(-2.0f * gravity * peakHeight); | |
| 3698 | |||
| 3699 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (SEGMENT.palette) |
| 3700 | { | ||
| 3701 | ✗ | popcorn[i].colIndex = hw_random8(); | |
| 3702 | } else { | ||
| 3703 | 3 | byte col = hw_random8(0, NUM_COLORS); | |
| 3704 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | if (!SEGCOLOR(2) || !SEGCOLOR(col)) col = 0; |
| 3705 | 3 | popcorn[i].colIndex = col; | |
| 3706 | } | ||
| 3707 | } | ||
| 3708 | } | ||
| 3709 |
2/2✓ Branch 0 taken 213 times.
✓ Branch 1 taken 684 times.
|
897 | if (popcorn[i].pos >= 0.0f) { // draw now active popcorn (either active before or just popped) |
| 3710 | 213 | uint32_t col = SEGMENT.color_wheel(popcorn[i].colIndex); | |
| 3711 |
3/6✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 213 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 213 times.
✗ Branch 5 not taken.
|
213 | if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex); |
| 3712 | 213 | unsigned ledIndex = popcorn[i].pos; | |
| 3713 |
1/2✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
|
213 | if (ledIndex < SEGLEN) SEGMENT.setPixelColor(indexToVStrip(ledIndex, stripNr), col); |
| 3714 | } | ||
| 3715 | } | ||
| 3716 | 456 | } | |
| 3717 | }; | ||
| 3718 | |||
| 3719 |
2/2✓ Branch 0 taken 456 times.
✓ Branch 1 taken 23 times.
|
479 | for (unsigned stripNr=0; stripNr<strips; stripNr++) |
| 3720 | 456 | virtualStrip::runStrip(stripNr, &popcorn[stripNr * usablePopcorns], usablePopcorns); | |
| 3721 | |||
| 3722 | 23 | return FRAMETIME; | |
| 3723 | } | ||
| 3724 | static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!,,,,,Overlay;!,!,!;!;;m12=1"; //bar | ||
| 3725 | |||
| 3726 | //values close to 100 produce 5Hz flicker, which looks very candle-y | ||
| 3727 | //Inspired by https://github.com/avanhanegem/ArduinoCandleEffectNeoPixel | ||
| 3728 | //and https://cpldcpu.wordpress.com/2016/01/05/reverse-engineering-a-real-candle/ | ||
| 3729 | |||
| 3730 | 46 | uint16_t candle(bool multi) | |
| 3731 | { | ||
| 3732 |
5/6✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 23 times.
|
46 | if (multi && SEGLEN > 1) { |
| 3733 | //allocate segment data | ||
| 3734 | 23 | unsigned dataSize = max(1, (int)SEGLEN -1) *3; //max. 1365 pixels (ESP8266) | |
| 3735 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed |
| 3736 | } | ||
| 3737 | |||
| 3738 | //max. flicker range controlled by intensity | ||
| 3739 | 46 | unsigned valrange = SEGMENT.intensity; | |
| 3740 | 46 | unsigned rndval = valrange >> 1; //max 127 | |
| 3741 | |||
| 3742 | //step (how much to move closer to target per frame) coarsely set by speed | ||
| 3743 | 46 | unsigned speedFactor = 4; | |
| 3744 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 38 times.
|
46 | if (SEGMENT.speed > 252) { //epilepsy |
| 3745 | 8 | speedFactor = 1; | |
| 3746 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | } else if (SEGMENT.speed > 99) { //regular candle (mode called every ~25 ms, so 4 frames to have a new target every 100ms) |
| 3747 | ✗ | speedFactor = 2; | |
| 3748 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 8 times.
|
38 | } else if (SEGMENT.speed > 49) { //slower fade |
| 3749 | 30 | speedFactor = 3; | |
| 3750 | } //else 4 (slowest) | ||
| 3751 | |||
| 3752 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | unsigned numCandles = (multi) ? SEGLEN : 1; |
| 3753 | |||
| 3754 |
2/2✓ Branch 0 taken 7534 times.
✓ Branch 1 taken 46 times.
|
7580 | for (unsigned i = 0; i < numCandles; i++) |
| 3755 | { | ||
| 3756 | 7534 | unsigned d = 0; //data location | |
| 3757 | |||
| 3758 | 7534 | unsigned s = SEGENV.aux0, s_target = SEGENV.aux1, fadeStep = SEGENV.step; | |
| 3759 |
2/2✓ Branch 0 taken 7488 times.
✓ Branch 1 taken 46 times.
|
7534 | if (i > 0) { |
| 3760 | 7488 | d = (i-1) *3; | |
| 3761 | 7488 | s = SEGENV.data[d]; s_target = SEGENV.data[d+1]; fadeStep = SEGENV.data[d+2]; | |
| 3762 | } | ||
| 3763 |
2/2✓ Branch 0 taken 1712 times.
✓ Branch 1 taken 5822 times.
|
7534 | if (fadeStep == 0) { //init vals |
| 3764 | 1712 | s = 128; s_target = 130 + hw_random8(4); fadeStep = 1; | |
| 3765 | } | ||
| 3766 | |||
| 3767 | 7534 | bool newTarget = false; | |
| 3768 |
2/2✓ Branch 0 taken 6977 times.
✓ Branch 1 taken 557 times.
|
7534 | if (s_target > s) { //fade up |
| 3769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6977 times.
|
6977 | s = qadd8(s, fadeStep); |
| 3770 |
2/2✓ Branch 0 taken 1492 times.
✓ Branch 1 taken 5485 times.
|
6977 | if (s >= s_target) newTarget = true; |
| 3771 | } else { | ||
| 3772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 557 times.
|
557 | s = qsub8(s, fadeStep); |
| 3773 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 497 times.
|
557 | if (s <= s_target) newTarget = true; |
| 3774 | } | ||
| 3775 | |||
| 3776 |
2/2✓ Branch 0 taken 1552 times.
✓ Branch 1 taken 5982 times.
|
7534 | if (newTarget) { |
| 3777 | 1552 | s_target = hw_random8(rndval) + hw_random8(rndval); //between 0 and rndval*2 -2 = 252 | |
| 3778 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 1395 times.
|
1552 | if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + hw_random8(rndval); |
| 3779 | 1552 | unsigned offset = (255 - valrange); | |
| 3780 | 1552 | s_target += offset; | |
| 3781 | |||
| 3782 |
2/2✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 484 times.
|
1552 | unsigned dif = (s_target > s) ? s_target - s : s - s_target; |
| 3783 | |||
| 3784 | 1552 | fadeStep = dif >> speedFactor; | |
| 3785 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 1447 times.
|
1552 | if (fadeStep == 0) fadeStep = 1; |
| 3786 | } | ||
| 3787 | |||
| 3788 |
2/2✓ Branch 0 taken 7488 times.
✓ Branch 1 taken 46 times.
|
7534 | if (i > 0) { |
| 3789 |
2/4✓ Branch 0 taken 7488 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7488 times.
|
7488 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), uint8_t(s))); |
| 3790 | |||
| 3791 | 7488 | SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep; | |
| 3792 | } else { | ||
| 3793 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 46 times.
|
15068 | for (unsigned j = 0; j < SEGLEN; j++) { |
| 3794 |
2/4✓ Branch 0 taken 15022 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15022 times.
|
15022 | SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), uint8_t(s))); |
| 3795 | } | ||
| 3796 | |||
| 3797 | 46 | SEGENV.aux0 = s; SEGENV.aux1 = s_target; SEGENV.step = fadeStep; | |
| 3798 | } | ||
| 3799 | } | ||
| 3800 | |||
| 3801 | 46 | return FRAMETIME_FIXED; | |
| 3802 | } | ||
| 3803 | |||
| 3804 | |||
| 3805 | 23 | uint16_t mode_candle() | |
| 3806 | { | ||
| 3807 | 23 | return candle(false); | |
| 3808 | } | ||
| 3809 | static const char _data_FX_MODE_CANDLE[] PROGMEM = "Candle@!,!;!,!;!;01;sx=96,ix=224,pal=0"; | ||
| 3810 | |||
| 3811 | |||
| 3812 | 23 | uint16_t mode_candle_multi() | |
| 3813 | { | ||
| 3814 | 23 | return candle(true); | |
| 3815 | } | ||
| 3816 | static const char _data_FX_MODE_CANDLE_MULTI[] PROGMEM = "Candle Multi@!,!;!,!;!;;sx=96,ix=224,pal=0"; | ||
| 3817 | |||
| 3818 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 3819 | /* | ||
| 3820 | / Fireworks in starburst effect | ||
| 3821 | / based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/ | ||
| 3822 | / Speed sets frequency of new starbursts, intensity is the intensity of the burst | ||
| 3823 | */ | ||
| 3824 | #ifdef ESP8266 | ||
| 3825 | #define STARBURST_MAX_FRAG 8 //52 bytes / star | ||
| 3826 | #else | ||
| 3827 | #define STARBURST_MAX_FRAG 10 //60 bytes / star | ||
| 3828 | #endif | ||
| 3829 | //each needs 20+STARBURST_MAX_FRAG*4 bytes | ||
| 3830 | typedef struct particle { | ||
| 3831 | CRGB color; | ||
| 3832 | uint32_t birth =0; | ||
| 3833 | uint32_t last =0; | ||
| 3834 | float vel =0; | ||
| 3835 | uint16_t pos =-1; | ||
| 3836 | float fragment[STARBURST_MAX_FRAG]; | ||
| 3837 | } star; | ||
| 3838 | |||
| 3839 | 23 | uint16_t mode_starburst(void) { | |
| 3840 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 3841 | 23 | unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 | |
| 3842 | 23 | unsigned segs = strip().getActiveSegmentsNum(); | |
| 3843 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (segs <= (strip().getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs |
| 3844 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (segs <= (strip().getMaxSegments() /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs |
| 3845 | 23 | unsigned maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg | |
| 3846 | |||
| 3847 | 23 | unsigned numStars = 1 + (SEGLEN >> 3); | |
| 3848 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (numStars > maxStars) numStars = maxStars; |
| 3849 | 23 | unsigned dataSize = sizeof(star) * numStars; | |
| 3850 | |||
| 3851 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 3852 | |||
| 3853 | 23 | uint32_t it = strip().now; | |
| 3854 | |||
| 3855 | 23 | star* stars = reinterpret_cast<star*>(SEGENV.data); | |
| 3856 | |||
| 3857 | 23 | float maxSpeed = 375.0f; // Max velocity | |
| 3858 | 23 | float particleIgnition = 250.0f; // How long to "flash" | |
| 3859 | 23 | float particleFadeTime = 1500.0f; // Fade out time | |
| 3860 | |||
| 3861 |
2/2✓ Branch 0 taken 955 times.
✓ Branch 1 taken 23 times.
|
978 | for (unsigned j = 0; j < numStars; j++) |
| 3862 | { | ||
| 3863 | // speed to adjust chance of a burst, max is nearly always. | ||
| 3864 |
5/6✓ Branch 0 taken 29 times.
✓ Branch 1 taken 926 times.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 926 times.
|
955 | if (hw_random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) |
| 3865 | { | ||
| 3866 | // Pick a random color and location. | ||
| 3867 | 29 | unsigned startPos = hw_random16(SEGLEN-1); | |
| 3868 | 29 | float multiplier = (float)(hw_random8())/255.0f * 1.0f; | |
| 3869 | |||
| 3870 |
3/6✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
|
29 | stars[j].color = CRGB(SEGMENT.color_wheel(hw_random8())); |
| 3871 | 29 | stars[j].pos = startPos; | |
| 3872 | 29 | stars[j].vel = maxSpeed * (float)(hw_random8())/255.0f * multiplier; | |
| 3873 | 29 | stars[j].birth = it; | |
| 3874 | 29 | stars[j].last = it; | |
| 3875 | // more fragments means larger burst effect | ||
| 3876 | 29 | int num = hw_random8(3,6 + (SEGMENT.intensity >> 5)); | |
| 3877 | |||
| 3878 |
2/2✓ Branch 0 taken 290 times.
✓ Branch 1 taken 29 times.
|
319 | for (int i=0; i < STARBURST_MAX_FRAG; i++) { |
| 3879 |
2/2✓ Branch 0 taken 213 times.
✓ Branch 1 taken 77 times.
|
290 | if (i < num) stars[j].fragment[i] = startPos; |
| 3880 | 77 | else stars[j].fragment[i] = -1; | |
| 3881 | } | ||
| 3882 | } | ||
| 3883 | } | ||
| 3884 | |||
| 3885 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); |
| 3886 | |||
| 3887 |
2/2✓ Branch 0 taken 955 times.
✓ Branch 1 taken 23 times.
|
978 | for (unsigned j=0; j<numStars; j++) |
| 3888 | { | ||
| 3889 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 882 times.
|
955 | if (stars[j].birth != 0) { |
| 3890 | 73 | float dt = (it-stars[j].last)/1000.0; | |
| 3891 | |||
| 3892 |
2/2✓ Branch 0 taken 730 times.
✓ Branch 1 taken 73 times.
|
803 | for (int i=0; i < STARBURST_MAX_FRAG; i++) { |
| 3893 | 730 | int var = i >> 1; | |
| 3894 | |||
| 3895 |
2/2✓ Branch 0 taken 548 times.
✓ Branch 1 taken 182 times.
|
730 | if (stars[j].fragment[i] > 0) { |
| 3896 | //all fragments travel right, will be mirrored on other side | ||
| 3897 | 548 | stars[j].fragment[i] += stars[j].vel * dt * (float)var/3.0; | |
| 3898 | } | ||
| 3899 | } | ||
| 3900 | 73 | stars[j].last = it; | |
| 3901 | 73 | stars[j].vel -= 3*stars[j].vel*dt; | |
| 3902 | } | ||
| 3903 | |||
| 3904 | 955 | CRGB c = stars[j].color; | |
| 3905 | |||
| 3906 | // If the star is brand new, it flashes white briefly. | ||
| 3907 | // Otherwise it just fades over time. | ||
| 3908 | 955 | float fade = 0.0f; | |
| 3909 | 955 | float age = it-stars[j].birth; | |
| 3910 | |||
| 3911 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 882 times.
|
955 | if (age < particleIgnition) { |
| 3912 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
73 | c = CRGB(color_blend(WHITE, RGBW32(c.r,c.g,c.b,0), uint8_t(254.5f*((age / particleIgnition))))); |
| 3913 | } else { | ||
| 3914 | // Figure out how much to fade and shrink the star based on | ||
| 3915 | // its age relative to its lifetime | ||
| 3916 |
1/2✓ Branch 0 taken 882 times.
✗ Branch 1 not taken.
|
882 | if (age > particleIgnition + particleFadeTime) { |
| 3917 | 882 | fade = 1.0f; // Black hole, all faded out | |
| 3918 | 882 | stars[j].birth = 0; | |
| 3919 | 882 | c = CRGB(SEGCOLOR(1)); | |
| 3920 | } else { | ||
| 3921 | ✗ | age -= particleIgnition; | |
| 3922 | ✗ | fade = (age / particleFadeTime); // Fading star | |
| 3923 | ✗ | c = CRGB(color_blend(RGBW32(c.r,c.g,c.b,0), SEGCOLOR(1), uint8_t(254.5f*fade))); | |
| 3924 | } | ||
| 3925 | } | ||
| 3926 | |||
| 3927 | 955 | float particleSize = (1.0f - fade) * 2.0f; | |
| 3928 | |||
| 3929 |
2/2✓ Branch 0 taken 19100 times.
✓ Branch 1 taken 955 times.
|
20055 | for (size_t index=0; index < STARBURST_MAX_FRAG*2; index++) { |
| 3930 | 19100 | bool mirrored = index & 0x1; | |
| 3931 | 19100 | unsigned i = index >> 1; | |
| 3932 |
2/2✓ Branch 0 taken 1096 times.
✓ Branch 1 taken 18004 times.
|
19100 | if (stars[j].fragment[i] > 0) { |
| 3933 | 1096 | float loc = stars[j].fragment[i]; | |
| 3934 |
2/2✓ Branch 0 taken 548 times.
✓ Branch 1 taken 548 times.
|
1096 | if (mirrored) loc -= (loc-stars[j].pos)*2; |
| 3935 | 1096 | unsigned start = loc - particleSize; | |
| 3936 | 1096 | unsigned end = loc + particleSize; | |
| 3937 | if (start < 0) start = 0; | ||
| 3938 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1096 times.
|
1096 | if (start == end) end++; |
| 3939 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1066 times.
|
1096 | if (end > SEGLEN) end = SEGLEN; |
| 3940 |
2/2✓ Branch 0 taken 4284 times.
✓ Branch 1 taken 1096 times.
|
5380 | for (unsigned p = start; p < end; p++) { |
| 3941 |
3/6✓ Branch 0 taken 4284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4284 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4284 times.
✗ Branch 5 not taken.
|
4284 | SEGMENT.setPixelColor(p, c); |
| 3942 | } | ||
| 3943 | } | ||
| 3944 | } | ||
| 3945 | } | ||
| 3946 | 23 | return FRAMETIME; | |
| 3947 | } | ||
| 3948 | #undef STARBURST_MAX_FRAG | ||
| 3949 | static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0"; | ||
| 3950 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 3951 | |||
| 3952 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 3953 | /* | ||
| 3954 | * Exploding fireworks effect | ||
| 3955 | * adapted from: http://www.anirama.com/1000leds/1d-fireworks/ | ||
| 3956 | * adapted for 2D WLED by blazoncek (Blaz Kristan (AKA blazoncek)) | ||
| 3957 | */ | ||
| 3958 | 23 | uint16_t mode_exploding_fireworks(void) | |
| 3959 | { | ||
| 3960 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 3961 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 5 times.
|
23 | const int cols = SEGMENT.is2D() ? SEG_W : 1; |
| 3962 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 5 times.
|
23 | const int rows = SEGMENT.is2D() ? SEG_H : SEGLEN; |
| 3963 | |||
| 3964 | //allocate segment data | ||
| 3965 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 |
| 3966 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | unsigned segs = strip().getActiveSegmentsNum(); |
| 3967 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | if (segs <= (strip().getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs |
| 3968 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | if (segs <= (strip().getMaxSegments() /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs |
| 3969 | 23 | int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg | |
| 3970 | |||
| 3971 | 23 | unsigned numSparks = min(5 + ((rows*cols) >> 1), maxSparks); | |
| 3972 | 23 | unsigned dataSize = sizeof(spark) * numSparks; | |
| 3973 |
4/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
23 | if (!SEGENV.allocateData(dataSize + sizeof(float))) return mode_static(); //allocation failed |
| 3974 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | float *dying_gravity = reinterpret_cast<float*>(SEGENV.data + dataSize); |
| 3975 | |||
| 3976 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated (it may be good idea to reset segment if bounds change) |
| 3977 | 5 | *dying_gravity = 0.0f; | |
| 3978 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = 0; |
| 3979 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux1 = dataSize; |
| 3980 | } | ||
| 3981 | |||
| 3982 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | SEGMENT.fade_out(252); |
| 3983 | |||
| 3984 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data); |
| 3985 | 23 | Spark* flare = sparks; //first spark is flare data | |
| 3986 | |||
| 3987 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | float gravity = -0.0004f - (SEGMENT.speed/800000.0f); // m/s/s |
| 3988 | 23 | gravity *= rows; | |
| 3989 | |||
| 3990 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | if (SEGENV.aux0 < 2) { //FLARE |
| 3991 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGENV.aux0 == 0) { //init flare |
| 3992 | 5 | flare->pos = 0; | |
| 3993 |
7/12✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
|
5 | flare->posX = SEGMENT.is2D() ? hw_random16(2,cols-3) : (SEGMENT.intensity > hw_random8()); // will enable random firing side on 1D |
| 3994 | 5 | unsigned peakHeight = 75 + hw_random8(180); //0-255 | |
| 3995 | 5 | peakHeight = (peakHeight * (rows -1)) >> 8; | |
| 3996 | 5 | flare->vel = sqrtf(-2.0f * gravity * peakHeight); | |
| 3997 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
|
5 | flare->velX = SEGMENT.is2D() ? (hw_random8(9)-4)/64.0f : 0; // no X velocity on 1D |
| 3998 | 5 | flare->col = 255; //brightness | |
| 3999 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = 1; |
| 4000 | } | ||
| 4001 | |||
| 4002 | // launch | ||
| 4003 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (flare->vel > 12 * gravity) { |
| 4004 | // flare | ||
| 4005 |
7/12✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
|
23 | if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(unsigned(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col); |
| 4006 |
4/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | else SEGMENT.setPixelColor((flare->posX > 0.0f) ? rows - int(flare->pos) - 1 : int(flare->pos), flare->col, flare->col, flare->col); |
| 4007 | 23 | flare->pos += flare->vel; | |
| 4008 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
23 | flare->pos = constrain(flare->pos, 0, rows-1); |
| 4009 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 5 times.
|
23 | if (SEGMENT.is2D()) { |
| 4010 | 18 | flare->posX += flare->velX; | |
| 4011 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | flare->posX = constrain(flare->posX, 0, cols-1); |
| 4012 | } | ||
| 4013 | 23 | flare->vel += gravity; | |
| 4014 | 23 | flare->col -= 2; | |
| 4015 | } else { | ||
| 4016 | ✗ | SEGENV.aux0 = 2; // ready to explode | |
| 4017 | } | ||
| 4018 | ✗ | } else if (SEGENV.aux0 < 4) { | |
| 4019 | /* | ||
| 4020 | * Explode! | ||
| 4021 | * | ||
| 4022 | * Explosion happens where the flare ended. | ||
| 4023 | * Size is proportional to the height. | ||
| 4024 | */ | ||
| 4025 | ✗ | unsigned nSparks = flare->pos + hw_random8(4); | |
| 4026 | ✗ | nSparks = std::max(nSparks, 4U); // This is not a standard constrain; numSparks is not guaranteed to be at least 4 | |
| 4027 | ✗ | nSparks = std::min(nSparks, numSparks); | |
| 4028 | |||
| 4029 | // initialize sparks | ||
| 4030 | ✗ | if (SEGENV.aux0 == 2) { | |
| 4031 | ✗ | for (unsigned i = 1; i < nSparks; i++) { | |
| 4032 | ✗ | sparks[i].pos = flare->pos; | |
| 4033 | ✗ | sparks[i].posX = flare->posX; | |
| 4034 | ✗ | sparks[i].vel = (float(hw_random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1 | |
| 4035 | ✗ | sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips | |
| 4036 | ✗ | sparks[i].velX = SEGMENT.is2D() ? (float(hw_random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1 | |
| 4037 | ✗ | sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright | |
| 4038 | //sparks[i].col = constrain(sparks[i].col, 0, 345); | ||
| 4039 | ✗ | sparks[i].colIndex = hw_random8(); | |
| 4040 | ✗ | sparks[i].vel *= flare->pos/rows; // proportional to height | |
| 4041 | ✗ | sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width | |
| 4042 | ✗ | sparks[i].vel *= -gravity *50; | |
| 4043 | } | ||
| 4044 | //sparks[1].col = 345; // this will be our known spark | ||
| 4045 | ✗ | *dying_gravity = gravity/2; | |
| 4046 | ✗ | SEGENV.aux0 = 3; | |
| 4047 | } | ||
| 4048 | |||
| 4049 | ✗ | if (sparks[1].col > 4) {//&& sparks[1].pos > 0) { // as long as our known spark is lit, work with all the sparks | |
| 4050 | ✗ | for (unsigned i = 1; i < nSparks; i++) { | |
| 4051 | ✗ | sparks[i].pos += sparks[i].vel; | |
| 4052 | ✗ | sparks[i].posX += sparks[i].velX; | |
| 4053 | ✗ | sparks[i].vel += *dying_gravity; | |
| 4054 | ✗ | sparks[i].velX += SEGMENT.is2D() ? *dying_gravity : 0; | |
| 4055 | ✗ | if (sparks[i].col > 3) sparks[i].col -= 4; | |
| 4056 | |||
| 4057 | ✗ | if (sparks[i].pos > 0 && sparks[i].pos < rows) { | |
| 4058 | ✗ | if (SEGMENT.is2D() && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue; | |
| 4059 | ✗ | unsigned prog = sparks[i].col; | |
| 4060 | ✗ | uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0); | |
| 4061 | ✗ | CRGBW c = BLACK; //HeatColor(sparks[i].col); | |
| 4062 | ✗ | if (prog > 300) { //fade from white to spark color | |
| 4063 | ✗ | c = color_blend(spColor, WHITE, uint8_t((prog - 300)*5)); | |
| 4064 | ✗ | } else if (prog > 45) { //fade from spark color to black | |
| 4065 | ✗ | c = color_blend(BLACK, spColor, uint8_t(prog - 45)); | |
| 4066 | ✗ | unsigned cooling = (300 - prog) >> 5; | |
| 4067 | ✗ | c.g = qsub8(c.g, cooling); | |
| 4068 | ✗ | c.b = qsub8(c.b, cooling * 2); | |
| 4069 | } | ||
| 4070 | ✗ | if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c); | |
| 4071 | ✗ | else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c); | |
| 4072 | } | ||
| 4073 | } | ||
| 4074 | ✗ | if (SEGMENT.check3) SEGMENT.blur(16); | |
| 4075 | ✗ | *dying_gravity *= .8f; // as sparks burn out they fall slower | |
| 4076 | } else { | ||
| 4077 | ✗ | SEGENV.aux0 = 6 + hw_random8(10); //wait for this many frames | |
| 4078 | } | ||
| 4079 | } else { | ||
| 4080 | ✗ | SEGENV.aux0--; | |
| 4081 | ✗ | if (SEGENV.aux0 < 4) { | |
| 4082 | ✗ | SEGENV.aux0 = 0; //back to flare | |
| 4083 | } | ||
| 4084 | } | ||
| 4085 | |||
| 4086 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 4087 | } | ||
| 4088 | #undef MAX_SPARKS | ||
| 4089 | static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gravity,Firing side;!,!;!;12;pal=11,ix=128"; | ||
| 4090 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 4091 | |||
| 4092 | /* | ||
| 4093 | * Drip Effect | ||
| 4094 | * ported of: https://www.youtube.com/watch?v=sru2fXh4r7k | ||
| 4095 | */ | ||
| 4096 | 23 | uint16_t mode_drip(void) | |
| 4097 | { | ||
| 4098 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 4099 | //allocate segment data | ||
| 4100 | 23 | unsigned strips = SEGMENT.nrOfVStrips(); | |
| 4101 | 23 | const int maxNumDrops = 4; | |
| 4102 | 23 | unsigned dataSize = sizeof(spark) * maxNumDrops; | |
| 4103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed |
| 4104 | 23 | Spark* drops = reinterpret_cast<Spark*>(SEGENV.data); | |
| 4105 | |||
| 4106 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); |
| 4107 | |||
| 4108 | struct virtualStrip { | ||
| 4109 | 456 | static void runStrip(uint16_t stripNr, Spark* drops) { | |
| 4110 | |||
| 4111 | 456 | unsigned numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3 | |
| 4112 | |||
| 4113 | 456 | float gravity = -0.0005f - (SEGMENT.speed/50000.0f); | |
| 4114 | 456 | gravity *= max(1, (int)SEGLEN-1); | |
| 4115 | 456 | int sourcedrop = 12; | |
| 4116 | |||
| 4117 |
2/2✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 456 times.
|
1696 | for (unsigned j=0;j<numDrops;j++) { |
| 4118 |
2/2✓ Branch 0 taken 280 times.
✓ Branch 1 taken 960 times.
|
1240 | if (drops[j].colIndex == 0) { //init |
| 4119 | 280 | drops[j].pos = SEGLEN-1; // start at end | |
| 4120 | 280 | drops[j].vel = 0; // speed | |
| 4121 | 280 | drops[j].col = sourcedrop; // brightness | |
| 4122 | 280 | drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing) | |
| 4123 | } | ||
| 4124 | |||
| 4125 | 1240 | SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,SEGCOLOR(0), uint8_t(sourcedrop)));// water source | |
| 4126 |
2/2✓ Branch 0 taken 1226 times.
✓ Branch 1 taken 14 times.
|
1240 | if (drops[j].colIndex==1) { |
| 4127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1226 times.
|
1226 | if (drops[j].col>255) drops[j].col=255; |
| 4128 | 1226 | SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,SEGCOLOR(0),uint8_t(drops[j].col))); | |
| 4129 | |||
| 4130 | 1226 | drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling | |
| 4131 | |||
| 4132 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1218 times.
|
1226 | if (hw_random8() < drops[j].col/10) { // random drop |
| 4133 | 8 | drops[j].colIndex=2; //fall | |
| 4134 | 8 | drops[j].col=255; | |
| 4135 | } | ||
| 4136 | } | ||
| 4137 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1218 times.
|
1240 | if (drops[j].colIndex > 1) { // falling |
| 4138 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | if (drops[j].pos > 0) { // fall until end of segment |
| 4139 | 22 | drops[j].pos += drops[j].vel; | |
| 4140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if (drops[j].pos < 0) drops[j].pos = 0; |
| 4141 | 22 | drops[j].vel += gravity; // gravity is negative | |
| 4142 | |||
| 4143 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 22 times.
|
110 | for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets |
| 4144 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 14 times.
|
88 | unsigned pos = constrain(unsigned(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally |
| 4145 | 88 | SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),uint8_t(drops[j].col/i))); //spread pixel with fade while falling | |
| 4146 | } | ||
| 4147 | |||
| 4148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if (drops[j].colIndex > 2) { // during bounce, some water is on the floor |
| 4149 | ✗ | SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(SEGCOLOR(0),BLACK,uint8_t(drops[j].col))); | |
| 4150 | } | ||
| 4151 | } else { // we hit bottom | ||
| 4152 | ✗ | if (drops[j].colIndex > 2) { // already hit once, so back to forming | |
| 4153 | ✗ | drops[j].colIndex = 0; | |
| 4154 | ✗ | drops[j].col = sourcedrop; | |
| 4155 | |||
| 4156 | } else { | ||
| 4157 | |||
| 4158 | ✗ | if (drops[j].colIndex==2) { // init bounce | |
| 4159 | ✗ | drops[j].vel = -drops[j].vel/4;// reverse velocity with damping | |
| 4160 | ✗ | drops[j].pos += drops[j].vel; | |
| 4161 | } | ||
| 4162 | ✗ | drops[j].col = sourcedrop*2; | |
| 4163 | ✗ | drops[j].colIndex = 5; // bouncing | |
| 4164 | } | ||
| 4165 | } | ||
| 4166 | } | ||
| 4167 | } | ||
| 4168 | 456 | } | |
| 4169 | }; | ||
| 4170 | |||
| 4171 |
2/2✓ Branch 0 taken 456 times.
✓ Branch 1 taken 23 times.
|
479 | for (unsigned stripNr=0; stripNr<strips; stripNr++) |
| 4172 | 456 | virtualStrip::runStrip(stripNr, &drops[stripNr*maxNumDrops]); | |
| 4173 | |||
| 4174 | 23 | return FRAMETIME; | |
| 4175 | } | ||
| 4176 | static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,,,,,Overlay;!,!;!;;m12=1"; //bar | ||
| 4177 | |||
| 4178 | /* | ||
| 4179 | * Tetris or Stacking (falling bricks) Effect | ||
| 4180 | * by Blaz Kristan (AKA blazoncek) (https://github.com/blazoncek, https://blaz.at/home) | ||
| 4181 | */ | ||
| 4182 | //20 bytes | ||
| 4183 | typedef struct Tetris { | ||
| 4184 | float pos; | ||
| 4185 | float speed; | ||
| 4186 | uint8_t col; // color index | ||
| 4187 | uint16_t brick; // brick size in pixels | ||
| 4188 | uint16_t stack; // stack size in pixels | ||
| 4189 | uint32_t step; // 2D-fication of SEGENV.step (state) | ||
| 4190 | } tetris; | ||
| 4191 | |||
| 4192 | 23 | uint16_t mode_tetrix(void) { | |
| 4193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 4194 | 23 | unsigned strips = SEGMENT.nrOfVStrips(); // allow running on virtual strips (columns in 2D segment) | |
| 4195 | 23 | unsigned dataSize = sizeof(tetris); | |
| 4196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed |
| 4197 | 23 | Tetris* drops = reinterpret_cast<Tetris*>(SEGENV.data); | |
| 4198 | |||
| 4199 | //if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D), then use drop->step = 0 below | ||
| 4200 | |||
| 4201 | // virtualStrip idea by @ewowi (Ewoud Wijma) | ||
| 4202 | // requires virtual strip # to be embedded into upper 16 bits of index in setPixelcolor() | ||
| 4203 | // the following functions will not work on virtual strips: fill(), fade_out(), fadeToBlack(), blur() | ||
| 4204 | struct virtualStrip { | ||
| 4205 | 456 | static void runStrip(size_t stripNr, Tetris *drop) { | |
| 4206 | // initialize dropping on first call or segment full | ||
| 4207 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 352 times.
|
456 | if (SEGENV.call == 0) { |
| 4208 | 104 | drop->stack = 0; // reset brick stack size | |
| 4209 | 104 | drop->step = strip().now + 2000; // start by fading out strip | |
| 4210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
|
104 | if (SEGMENT.check1) drop->col = 0;// use only one color from palette |
| 4211 | } | ||
| 4212 | |||
| 4213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
|
456 | if (drop->step == 0) { // init brick |
| 4214 | // speed calculation: a single brick should reach bottom of strip in X seconds | ||
| 4215 | // if the speed is set to 1 this should take 5s and at 255 it should take 0.25s | ||
| 4216 | // as this is dependant on SEGLEN it should be taken into account and the fact that effect runs every FRAMETIME s | ||
| 4217 | ✗ | int speed = SEGMENT.speed ? SEGMENT.speed : hw_random8(1,255); | |
| 4218 | ✗ | speed = map(speed, 1, 255, 5000, 250); // time taken for full (SEGLEN) drop | |
| 4219 | ✗ | drop->speed = float(SEGLEN * FRAMETIME) / float(speed); // set speed | |
| 4220 | ✗ | drop->pos = SEGLEN; // start at end of segment (no need to subtract 1) | |
| 4221 | ✗ | if (!SEGMENT.check1) drop->col = hw_random8(0,15)<<4; // limit color choices so there is enough HUE gap | |
| 4222 | ✗ | drop->step = 1; // drop state (0 init, 1 forming, 2 falling) | |
| 4223 | ✗ | drop->brick = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : hw_random8(1,5)) * (1+(SEGLEN>>6)); // size of brick | |
| 4224 | } | ||
| 4225 | |||
| 4226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
|
456 | if (drop->step == 1) { // forming |
| 4227 | ✗ | if (hw_random8()>>6) { // random drop | |
| 4228 | ✗ | drop->step = 2; // fall | |
| 4229 | } | ||
| 4230 | } | ||
| 4231 | |||
| 4232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
|
456 | if (drop->step == 2) { // falling |
| 4233 | ✗ | if (drop->pos > drop->stack) { // fall until top of stack | |
| 4234 | ✗ | drop->pos -= drop->speed; // may add gravity as: speed += gravity | |
| 4235 | ✗ | if (int(drop->pos) < int(drop->stack)) drop->pos = drop->stack; | |
| 4236 | ✗ | for (unsigned i = unsigned(drop->pos); i < SEGLEN; i++) { | |
| 4237 | ✗ | uint32_t col = i < unsigned(drop->pos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1); | |
| 4238 | ✗ | SEGMENT.setPixelColor(indexToVStrip(i, stripNr), col); | |
| 4239 | } | ||
| 4240 | } else { // we hit bottom | ||
| 4241 | ✗ | drop->step = 0; // proceed with next brick, go back to init | |
| 4242 | ✗ | drop->stack += drop->brick; // increase the stack size | |
| 4243 | ✗ | if (drop->stack >= SEGLEN) drop->step = strip().now + 2000; // fade out stack | |
| 4244 | } | ||
| 4245 | } | ||
| 4246 | |||
| 4247 |
1/2✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
|
456 | if (drop->step > 2) { // fade strip |
| 4248 | 456 | drop->brick = 0; // reset brick size (no more growing) | |
| 4249 |
1/2✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
|
456 | if (drop->step > strip().now) { |
| 4250 | // allow fading of virtual strip | ||
| 4251 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 456 times.
|
7967 | for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend |
| 4252 | } else { | ||
| 4253 | ✗ | drop->stack = 0; // reset brick stack size | |
| 4254 | ✗ | drop->step = 0; // proceed with next brick | |
| 4255 | ✗ | if (SEGMENT.check1) drop->col += 8; // gradually increase palette index | |
| 4256 | } | ||
| 4257 | } | ||
| 4258 | 456 | } | |
| 4259 | }; | ||
| 4260 | |||
| 4261 |
2/2✓ Branch 0 taken 456 times.
✓ Branch 1 taken 23 times.
|
479 | for (unsigned stripNr=0; stripNr<strips; stripNr++) |
| 4262 | 456 | virtualStrip::runStrip(stripNr, &drops[stripNr]); | |
| 4263 | |||
| 4264 | 23 | return FRAMETIME; | |
| 4265 | } | ||
| 4266 | static const char _data_FX_MODE_TETRIX[] PROGMEM = "Tetrix@!,Width,,,,One color;!,!;!;;sx=0,ix=0,pal=11,m12=1"; | ||
| 4267 | |||
| 4268 | |||
| 4269 | /* | ||
| 4270 | / Plasma Effect | ||
| 4271 | / adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino | ||
| 4272 | */ | ||
| 4273 | 23 | uint16_t mode_plasma(void) { | |
| 4274 | // initialize phases on start | ||
| 4275 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 4276 | 5 | SEGENV.aux0 = hw_random8(0,2); // add a bit of randomness | |
| 4277 | } | ||
| 4278 | 23 | unsigned thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64); | |
| 4279 | 23 | unsigned thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64); | |
| 4280 | |||
| 4281 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: |
| 4282 | 7511 | unsigned 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. | |
| 4283 | 7511 | + cos8_t((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. | |
| 4284 |
2/2✓ Branch 0 taken 932 times.
✓ Branch 1 taken 6579 times.
|
7511 | unsigned thisBright = qsub8(colorIndex, beatsin8_t(7,0, (128 - (SEGMENT.intensity>>1)))); |
| 4285 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0, thisBright)); |
| 4286 | } | ||
| 4287 | |||
| 4288 | 23 | return FRAMETIME; | |
| 4289 | } | ||
| 4290 | static const char _data_FX_MODE_PLASMA[] PROGMEM = "Plasma@Phase,!;!;!"; | ||
| 4291 | |||
| 4292 | |||
| 4293 | /* | ||
| 4294 | * Percentage display | ||
| 4295 | * Intensity values from 0-100 turn on the leds. | ||
| 4296 | */ | ||
| 4297 | 861 | uint16_t mode_percent(void) { | |
| 4298 | |||
| 4299 | 861 | unsigned percent = SEGMENT.intensity; | |
| 4300 | 861 | percent = constrain(percent, 0, 200); | |
| 4301 | 842 | unsigned active_leds = (percent < 100) ? roundf(SEGLEN * percent / 100.0f) | |
| 4302 |
2/2✓ Branch 0 taken 842 times.
✓ Branch 1 taken 19 times.
|
1703 | : roundf(SEGLEN * (200 - percent) / 100.0f); |
| 4303 | |||
| 4304 | 861 | unsigned size = (1 + ((SEGMENT.speed * SEGLEN) >> 11)); | |
| 4305 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 861 times.
|
861 | if (SEGMENT.speed == 255) size = 255; |
| 4306 | |||
| 4307 |
2/2✓ Branch 0 taken 842 times.
✓ Branch 1 taken 19 times.
|
861 | if (percent <= 100) { |
| 4308 |
2/2✓ Branch 0 taken 22160 times.
✓ Branch 1 taken 842 times.
|
23002 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4309 |
2/2✓ Branch 0 taken 5778 times.
✓ Branch 1 taken 16382 times.
|
22160 | if (i < SEGENV.aux1) { |
| 4310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5778 times.
|
5778 | if (SEGMENT.check1) |
| 4311 | ✗ | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(map(percent,0,100,0,255), false, false, 0)); | |
| 4312 | else | ||
| 4313 |
2/4✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5778 times.
|
5778 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 4314 | } | ||
| 4315 | else { | ||
| 4316 | 16382 | SEGMENT.setPixelColor(i, SEGCOLOR(1)); | |
| 4317 | } | ||
| 4318 | } | ||
| 4319 | } else { | ||
| 4320 |
2/2✓ Branch 0 taken 5463 times.
✓ Branch 1 taken 19 times.
|
5482 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4321 |
2/2✓ Branch 0 taken 5013 times.
✓ Branch 1 taken 450 times.
|
5463 | if (i < (SEGLEN - SEGENV.aux1)) { |
| 4322 | 5013 | SEGMENT.setPixelColor(i, SEGCOLOR(1)); | |
| 4323 | } | ||
| 4324 | else { | ||
| 4325 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 450 times.
|
450 | if (SEGMENT.check1) |
| 4326 | ✗ | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(map(percent,100,200,255,0), false, false, 0)); | |
| 4327 | else | ||
| 4328 |
2/4✓ Branch 0 taken 450 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 450 times.
|
450 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); |
| 4329 | } | ||
| 4330 | } | ||
| 4331 | } | ||
| 4332 | |||
| 4333 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 745 times.
|
861 | if(active_leds > SEGENV.aux1) { // smooth transition to the target value |
| 4334 | 116 | SEGENV.aux1 += size; | |
| 4335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
|
116 | if (SEGENV.aux1 > active_leds) SEGENV.aux1 = active_leds; |
| 4336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 745 times.
|
745 | } else if (active_leds < SEGENV.aux1) { |
| 4337 | ✗ | if (SEGENV.aux1 > size) SEGENV.aux1 -= size; else SEGENV.aux1 = 0; | |
| 4338 | ✗ | if (SEGENV.aux1 < active_leds) SEGENV.aux1 = active_leds; | |
| 4339 | } | ||
| 4340 | |||
| 4341 | 861 | return FRAMETIME; | |
| 4342 | } | ||
| 4343 | static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,One color;!,!;!"; | ||
| 4344 | |||
| 4345 | |||
| 4346 | /* | ||
| 4347 | * Modulates the brightness similar to a heartbeat | ||
| 4348 | * (unimplemented?) tries to draw an ECG approximation on a 2D matrix | ||
| 4349 | */ | ||
| 4350 | 23 | uint16_t mode_heartbeat(void) { | |
| 4351 | 23 | unsigned bpm = 40 + (SEGMENT.speed >> 3); | |
| 4352 | 23 | uint32_t msPerBeat = (60000L / bpm); | |
| 4353 | 23 | uint32_t secondBeat = (msPerBeat / 3); | |
| 4354 | 23 | uint32_t bri_lower = SEGENV.aux1; | |
| 4355 | 23 | unsigned long beatTimer = strip().now - SEGENV.step; | |
| 4356 | |||
| 4357 | 23 | bri_lower = bri_lower * 2042 / (2048 + SEGMENT.intensity); | |
| 4358 | 23 | SEGENV.aux1 = bri_lower; | |
| 4359 | |||
| 4360 |
5/6✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if ((beatTimer > secondBeat) && !SEGENV.aux0) { // time for the second beat? |
| 4361 | 5 | SEGENV.aux1 = UINT16_MAX; //3/4 bri | |
| 4362 | 5 | SEGENV.aux0 = 1; | |
| 4363 | } | ||
| 4364 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (beatTimer > msPerBeat) { // time to reset the beat timer? |
| 4365 | 5 | SEGENV.aux1 = UINT16_MAX; //full bri | |
| 4366 | 5 | SEGENV.aux0 = 0; | |
| 4367 | 5 | SEGENV.step = strip().now; | |
| 4368 | } | ||
| 4369 | |||
| 4370 |
2/2✓ Branch 0 taken 973 times.
✓ Branch 1 taken 23 times.
|
996 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4371 |
2/4✓ Branch 0 taken 973 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 973 times.
|
973 | SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255 - (SEGENV.aux1 >> 8)))); |
| 4372 | } | ||
| 4373 | |||
| 4374 | 23 | return FRAMETIME; | |
| 4375 | } | ||
| 4376 | static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;01;m12=1"; | ||
| 4377 | |||
| 4378 | |||
| 4379 | // "Pacifica" | ||
| 4380 | // Gentle, blue-green ocean waves. | ||
| 4381 | // December 2019, Mark Kriegsman and Mary Corey March. | ||
| 4382 | // For Dan. | ||
| 4383 | // | ||
| 4384 | // | ||
| 4385 | // In this animation, there are four "layers" of waves of light. | ||
| 4386 | // | ||
| 4387 | // Each layer moves independently, and each is scaled separately. | ||
| 4388 | // | ||
| 4389 | // All four wave layers are added together on top of each other, and then | ||
| 4390 | // another filter is applied that adds "whitecaps" of brightness where the | ||
| 4391 | // waves line up with each other more. Finally, another pass is taken | ||
| 4392 | // over the led array to 'deepen' (dim) the blues and greens. | ||
| 4393 | // | ||
| 4394 | // The speed and scale and motion each layer varies slowly within independent | ||
| 4395 | // hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions | ||
| 4396 | // with a lot of oddly specific numeric ranges. | ||
| 4397 | // | ||
| 4398 | // These three custom blue-green color palettes were inspired by the colors found in | ||
| 4399 | // the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7 | ||
| 4400 | // | ||
| 4401 | // Modified for WLED, based on https://github.com/FastLED/FastLED/blob/master/examples/Pacifica/Pacifica.ino | ||
| 4402 | // | ||
| 4403 | // Add one layer of waves into the led array | ||
| 4404 | 30044 | static CRGB pacifica_one_layer(uint16_t i, const CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) | |
| 4405 | { | ||
| 4406 | 30044 | unsigned ci = cistart; | |
| 4407 | 30044 | unsigned waveangle = ioff; | |
| 4408 | 30044 | unsigned wavescale_half = (wavescale >> 1) + 20; | |
| 4409 | |||
| 4410 | 30044 | waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i | |
| 4411 | 30044 | unsigned s16 = sin16_t(waveangle) + 32768; | |
| 4412 | 30044 | unsigned cs = scale16(s16, wavescale_half) + wavescale_half; | |
| 4413 | 30044 | ci += (cs * i); | |
| 4414 | 30044 | unsigned sindex16 = sin16_t(ci) + 32768; | |
| 4415 | 30044 | unsigned sindex8 = scale16(sindex16, 240); | |
| 4416 |
1/2✓ Branch 0 taken 30044 times.
✗ Branch 1 not taken.
|
30044 | return CRGB(ColorFromPalette(p, sindex8, bri, LINEARBLEND)); |
| 4417 | } | ||
| 4418 | |||
| 4419 | 23 | uint16_t mode_pacifica() | |
| 4420 | { | ||
| 4421 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | uint32_t nowOld = strip().now; |
| 4422 | |||
| 4423 | CRGBPalette16 pacifica_palette_1 = | ||
| 4424 | { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, | ||
| 4425 | 23 | 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 }; | |
| 4426 | CRGBPalette16 pacifica_palette_2 = | ||
| 4427 | { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, | ||
| 4428 | 23 | 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F }; | |
| 4429 | CRGBPalette16 pacifica_palette_3 = | ||
| 4430 | { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33, | ||
| 4431 | 23 | 0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF }; | |
| 4432 | |||
| 4433 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | if (SEGMENT.palette) { |
| 4434 | 23 | pacifica_palette_1 = SEGPALETTE; | |
| 4435 | 23 | pacifica_palette_2 = SEGPALETTE; | |
| 4436 | 23 | pacifica_palette_3 = SEGPALETTE; | |
| 4437 | } | ||
| 4438 | |||
| 4439 | // Increment the four "color index start" counters, one for each wave layer. | ||
| 4440 | // Each is incremented at a different speed, and the speeds vary over time. | ||
| 4441 |
8/16✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 23 times.
✗ Branch 15 not taken.
|
23 | unsigned sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step & 0xFFFF, sCIStart4 = (SEGENV.step >> 16); |
| 4442 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | uint32_t deltams = (FRAMETIME >> 2) + ((FRAMETIME * SEGMENT.speed) >> 7); |
| 4443 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | uint64_t deltat = (strip().now >> 2) + ((strip().now * SEGMENT.speed) >> 7); |
| 4444 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | strip().now = deltat; |
| 4445 | |||
| 4446 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | unsigned speedfactor1 = beatsin16_t(3, 179, 269); |
| 4447 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | unsigned speedfactor2 = beatsin16_t(4, 179, 269); |
| 4448 | 23 | uint32_t deltams1 = (deltams * speedfactor1) / 256; | |
| 4449 | 23 | uint32_t deltams2 = (deltams * speedfactor2) / 256; | |
| 4450 | 23 | uint32_t deltams21 = (deltams1 + deltams2) / 2; | |
| 4451 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | sCIStart1 += (deltams1 * beatsin88_t(1011,10,13)); |
| 4452 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | sCIStart2 -= (deltams21 * beatsin88_t(777,8,11)); |
| 4453 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | sCIStart3 -= (deltams1 * beatsin88_t(501,5,7)); |
| 4454 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | sCIStart4 -= (deltams2 * beatsin88_t(257,4,6)); |
| 4455 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2; |
| 4456 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | SEGENV.step = (sCIStart4 << 16) | (sCIStart3 & 0xFFFF); |
| 4457 | |||
| 4458 | // Clear out the LED array to a dim background blue-green | ||
| 4459 | //SEGMENT.fill(132618); | ||
| 4460 | |||
| 4461 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | unsigned basethreshold = beatsin8_t( 9, 55, 65); |
| 4462 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | unsigned wave = beat8( 7 ); |
| 4463 | |||
| 4464 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4465 | 7511 | CRGB c = CRGB(2, 6, 10); | |
| 4466 | // Render each of four layers, with different scales and speeds, that vary over time | ||
| 4467 |
5/10✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7511 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7511 times.
✗ Branch 9 not taken.
|
7511 | c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16_t(3, 11 * 256, 14 * 256), beatsin8_t(10, 70, 130), 0-beat16(301)); |
| 4468 |
5/10✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7511 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7511 times.
✗ Branch 9 not taken.
|
7511 | c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16_t(4, 6 * 256, 9 * 256), beatsin8_t(17, 40, 80), beat16(401)); |
| 4469 |
4/8✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7511 times.
✗ Branch 7 not taken.
|
7511 | c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8_t(9, 10,38) , 0-beat16(503)); |
| 4470 |
4/8✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7511 times.
✗ Branch 7 not taken.
|
7511 | c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8_t(8, 10,28) , beat16(601)); |
| 4471 | |||
| 4472 | // Add extra 'white' to areas where the four layers of light have lined up brightly | ||
| 4473 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
7511 | unsigned threshold = scale8( sin8_t( wave), 20) + basethreshold; |
| 4474 | 7511 | wave += 7; | |
| 4475 | 7511 | unsigned l = c.getAverageLight(); | |
| 4476 |
2/2✓ Branch 0 taken 4214 times.
✓ Branch 1 taken 3297 times.
|
7511 | if (l > threshold) { |
| 4477 | 4214 | unsigned overage = l - threshold; | |
| 4478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4214 times.
|
4214 | unsigned overage2 = qadd8(overage, overage); |
| 4479 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 4214 times.
✓ Branch 2 taken 4214 times.
✗ Branch 3 not taken.
|
8428 | c += CRGB(overage, overage2, qadd8(overage2, overage2)); |
| 4480 | } | ||
| 4481 | |||
| 4482 | //deepen the blues and greens | ||
| 4483 | 7511 | c.blue = scale8(c.blue, 145); | |
| 4484 | 7511 | c.green = scale8(c.green, 200); | |
| 4485 | 7511 | c |= CRGB( 2, 5, 7); | |
| 4486 | |||
| 4487 |
3/6✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7511 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7511 times.
✗ Branch 5 not taken.
|
7511 | SEGMENT.setPixelColor(i, c); |
| 4488 | } | ||
| 4489 | |||
| 4490 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | strip().now = nowOld; |
| 4491 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
46 | return FRAMETIME; |
| 4492 | } | ||
| 4493 | static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=51"; | ||
| 4494 | |||
| 4495 | |||
| 4496 | /* | ||
| 4497 | * Mode simulates a gradual sunrise | ||
| 4498 | */ | ||
| 4499 | 23 | uint16_t mode_sunrise() { | |
| 4500 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 4501 | //speed 0 - static sun | ||
| 4502 | //speed 1 - 60: sunrise time in minutes | ||
| 4503 | //speed 60 - 120 : sunset time in minutes - 60; | ||
| 4504 | //speed above: "breathing" rise and set | ||
| 4505 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) { |
| 4506 | 5 | SEGENV.step = millis(); //save starting time, millis() because strip().now can change from sync | |
| 4507 | 5 | SEGENV.aux0 = SEGMENT.speed; | |
| 4508 | } | ||
| 4509 | |||
| 4510 | 23 | SEGMENT.fill(BLACK); | |
| 4511 | 23 | unsigned stage = 0xFFFF; | |
| 4512 | |||
| 4513 | 23 | uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds | |
| 4514 | |||
| 4515 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
|
23 | if (SEGMENT.speed > 120) { //quick sunrise and sunset |
| 4516 | 4 | unsigned counter = (strip().now >> 1) * (((SEGMENT.speed -120) >> 1) +1); | |
| 4517 | 4 | stage = triwave16(counter); | |
| 4518 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 4 times.
|
19 | } else if (SEGMENT.speed) { //sunrise |
| 4519 | 15 | unsigned durMins = SEGMENT.speed; | |
| 4520 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (durMins > 60) durMins -= 60; |
| 4521 | 15 | uint32_t s10Target = durMins * 600; | |
| 4522 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (s10SinceStart > s10Target) s10SinceStart = s10Target; |
| 4523 | 15 | stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF); | |
| 4524 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset |
| 4525 | } | ||
| 4526 | |||
| 4527 |
2/2✓ Branch 0 taken 3776 times.
✓ Branch 1 taken 23 times.
|
3799 | for (unsigned i = 0; i <= SEGLEN/2; i++) |
| 4528 | { | ||
| 4529 | //default palette is Fire | ||
| 4530 | 3776 | unsigned wave = triwave16((i * stage) / SEGLEN); | |
| 4531 | 3776 | wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15); | |
| 4532 | uint32_t c; | ||
| 4533 |
2/2✓ Branch 0 taken 698 times.
✓ Branch 1 taken 3078 times.
|
3776 | if (wave > 240) { //clipped, full white sun |
| 4534 | 698 | c = SEGMENT.color_from_palette( 240, false, true, 255); | |
| 4535 | } else { //transition | ||
| 4536 | 3078 | c = SEGMENT.color_from_palette(wave, false, true, 255); | |
| 4537 | } | ||
| 4538 | 3776 | SEGMENT.setPixelColor(i, c); | |
| 4539 | 3776 | SEGMENT.setPixelColor(SEGLEN - i - 1, c); | |
| 4540 | } | ||
| 4541 | |||
| 4542 | 23 | return FRAMETIME; | |
| 4543 | } | ||
| 4544 | static const char _data_FX_MODE_SUNRISE[] PROGMEM = "Sunrise@Time [min],Width;;!;;pal=35,sx=60"; | ||
| 4545 | |||
| 4546 | |||
| 4547 | /* | ||
| 4548 | * Effects by Andrew Tuline | ||
| 4549 | */ | ||
| 4550 | 46 | static uint16_t phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline. | |
| 4551 | |||
| 4552 | 46 | unsigned allfreq = 16; // Base frequency. | |
| 4553 | 46 | float *phase = reinterpret_cast<float*>(&SEGENV.step); // Phase change value gets calculated (float fits into unsigned long). | |
| 4554 | 46 | unsigned cutOff = (255-SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192). | |
| 4555 | 46 | unsigned modVal = 5;//SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5). | |
| 4556 | |||
| 4557 | 46 | unsigned index = strip().now/64; // Set color rotation speed | |
| 4558 | 46 | *phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4) | |
| 4559 | |||
| 4560 |
2/2✓ Branch 0 taken 15022 times.
✓ Branch 1 taken 46 times.
|
15068 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4561 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 7511 times.
|
15022 | if (moder == 1) modVal = (perlin8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. |
| 4562 | 15022 | unsigned val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that led 0 is used. | |
| 4563 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 14983 times.
|
15022 | if (modVal == 0) modVal = 1; |
| 4564 | 15022 | val += *phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline. | |
| 4565 | 15022 | unsigned b = cubicwave8(val); // Now we make an 8 bit sinewave. | |
| 4566 |
2/2✓ Branch 0 taken 7284 times.
✓ Branch 1 taken 7738 times.
|
15022 | b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light. |
| 4567 | 15022 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, false, 0), uint8_t(b))); | |
| 4568 | 15022 | index += 256 / SEGLEN; | |
| 4569 |
2/2✓ Branch 0 taken 13312 times.
✓ Branch 1 taken 1710 times.
|
15022 | if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs |
| 4570 | } | ||
| 4571 | |||
| 4572 | 46 | return FRAMETIME; | |
| 4573 | } | ||
| 4574 | |||
| 4575 | |||
| 4576 | 23 | uint16_t mode_phased(void) { | |
| 4577 | 23 | return phased_base(0); | |
| 4578 | } | ||
| 4579 | static const char _data_FX_MODE_PHASED[] PROGMEM = "Phased@!,!;!,!;!"; | ||
| 4580 | |||
| 4581 | |||
| 4582 | 23 | uint16_t mode_phased_noise(void) { | |
| 4583 | 23 | return phased_base(1); | |
| 4584 | } | ||
| 4585 | static const char _data_FX_MODE_PHASEDNOISE[] PROGMEM = "Phased Noise@!,!;!,!;!"; | ||
| 4586 | |||
| 4587 | |||
| 4588 | 23 | uint16_t mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline. | |
| 4589 | 23 | unsigned prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function | |
| 4590 | 23 | 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. | |
| 4591 | |||
| 4592 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4593 | 7511 | unsigned ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. | |
| 4594 | 7511 | unsigned pixBri = sin8_t(ranstart + 16 * strip().now/(256-SEGMENT.speed)); | |
| 4595 |
2/2✓ Branch 0 taken 3739 times.
✓ Branch 1 taken 3772 times.
|
7511 | if (random8() > SEGMENT.intensity) pixBri = 0; |
| 4596 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip().now/100, false, PALETTE_SOLID_WRAP, 0), pixBri)); |
| 4597 | } | ||
| 4598 | |||
| 4599 | 23 | random16_set_seed(prevSeed); // restore original seed so other effects can use "random" PRNG | |
| 4600 | 23 | return FRAMETIME; | |
| 4601 | } | ||
| 4602 | static const char _data_FX_MODE_TWINKLEUP[] PROGMEM = "Twinkleup@!,Intensity;!,!;!;;m12=0"; | ||
| 4603 | |||
| 4604 | |||
| 4605 | // Peaceful noise that's slow and with gradually changing palettes. Does not support WLED palettes or default colours or controls. | ||
| 4606 | 23 | uint16_t mode_noisepal(void) { // Slow noise palette by Andrew Tuline. | |
| 4607 | 23 | unsigned scale = 15 + (SEGMENT.intensity >> 2); //default was 30 | |
| 4608 | //#define scale 30 | ||
| 4609 | |||
| 4610 | 23 | unsigned dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes (2 * 16 * 3 = 96 bytes) | |
| 4611 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 4612 | |||
| 4613 | 23 | CRGBPalette16* palettes = reinterpret_cast<CRGBPalette16*>(SEGENV.data); | |
| 4614 | |||
| 4615 | 23 | unsigned changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec | |
| 4616 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (strip().now - SEGENV.step > changePaletteMs) |
| 4617 | { | ||
| 4618 | 5 | SEGENV.step = strip().now; | |
| 4619 | |||
| 4620 | 5 | unsigned baseI = hw_random8(); | |
| 4621 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | palettes[1] = CRGBPalette16(CHSV(baseI+hw_random8(64), 255, hw_random8(128,255)), CHSV(baseI+128, 255, hw_random8(128,255)), CHSV(baseI+hw_random8(92), 192, hw_random8(128,255)), CHSV(baseI+hw_random8(92), 255, hw_random8(128,255))); |
| 4622 | } | ||
| 4623 | |||
| 4624 | //EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms) | ||
| 4625 | 23 | nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations. | |
| 4626 | |||
| 4627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGMENT.palette > 0) palettes[0] = SEGPALETTE; |
| 4628 | |||
| 4629 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4630 | 7511 | unsigned index = perlin8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. | |
| 4631 | 7511 | SEGMENT.setPixelColor(i, ColorFromPalette(palettes[0], index, 255, LINEARBLEND)); // Use my own palette. | |
| 4632 | } | ||
| 4633 | |||
| 4634 | 23 | SEGENV.aux0 += beatsin8_t(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. | |
| 4635 | |||
| 4636 | 23 | return FRAMETIME; | |
| 4637 | } | ||
| 4638 | static const char _data_FX_MODE_NOISEPAL[] PROGMEM = "Noise Pal@!,Scale;;!"; | ||
| 4639 | |||
| 4640 | |||
| 4641 | // Sine waves that have controllable phase change speed, frequency and cutoff. By Andrew Tuline. | ||
| 4642 | // SEGMENT.speed ->Speed, SEGMENT.intensity -> Frequency (SEGMENT.fft1 -> Color change, SEGMENT.fft2 -> PWM cutoff) | ||
| 4643 | // | ||
| 4644 | 23 | uint16_t mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline | |
| 4645 | //#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0 | ||
| 4646 | |||
| 4647 | 23 | unsigned colorIndex = strip().now /32;//(256 - SEGMENT.fft1); // Amount of colour change. | |
| 4648 | |||
| 4649 | 23 | SEGENV.step += SEGMENT.speed/16; // Speed of animation. | |
| 4650 | 23 | unsigned freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal. | |
| 4651 | |||
| 4652 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows: |
| 4653 | 7511 | uint8_t 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).. | |
| 4654 | //setPixCol(i, i*colorIndex/255, pixBri); | ||
| 4655 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri)); |
| 4656 | } | ||
| 4657 | |||
| 4658 | 23 | return FRAMETIME; | |
| 4659 | } | ||
| 4660 | static const char _data_FX_MODE_SINEWAVE[] PROGMEM = "Sine@!,Scale;;!"; | ||
| 4661 | |||
| 4662 | |||
| 4663 | /* | ||
| 4664 | * Best of both worlds from Palette and Spot effects. By Aircoookie | ||
| 4665 | */ | ||
| 4666 | 23 | uint16_t mode_flow(void) | |
| 4667 | { | ||
| 4668 | 23 | unsigned counter = 0; | |
| 4669 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (SEGMENT.speed != 0) |
| 4670 | { | ||
| 4671 | 19 | counter = strip().now * ((SEGMENT.speed >> 2) +1); | |
| 4672 | 19 | counter = counter >> 8; | |
| 4673 | } | ||
| 4674 | |||
| 4675 | 23 | unsigned maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs | |
| 4676 | 23 | unsigned zones = (SEGMENT.intensity * maxZones) >> 8; | |
| 4677 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 14 times.
|
23 | if (zones & 0x01) zones++; //zones must be even |
| 4678 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 14 times.
|
23 | if (zones < 2) zones = 2; |
| 4679 | 23 | unsigned zoneLen = SEGLEN / zones; | |
| 4680 | 23 | unsigned offset = (SEGLEN - zones * zoneLen) >> 1; | |
| 4681 | |||
| 4682 | 23 | SEGMENT.fill(SEGMENT.color_from_palette(-counter, false, true, 255)); | |
| 4683 | |||
| 4684 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 23 times.
|
119 | for (unsigned z = 0; z < zones; z++) |
| 4685 | { | ||
| 4686 | 96 | unsigned pos = offset + z * zoneLen; | |
| 4687 |
2/2✓ Branch 0 taken 938 times.
✓ Branch 1 taken 96 times.
|
1034 | for (unsigned i = 0; i < zoneLen; i++) |
| 4688 | { | ||
| 4689 | 938 | unsigned colorIndex = (i * 255 / zoneLen) - counter; | |
| 4690 |
2/2✓ Branch 0 taken 469 times.
✓ Branch 1 taken 469 times.
|
938 | unsigned led = (z & 0x01) ? i : (zoneLen -1) -i; |
| 4691 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 938 times.
|
938 | if (SEGMENT.reverse) led = (zoneLen -1) -led; |
| 4692 | 938 | SEGMENT.setPixelColor(pos + led, SEGMENT.color_from_palette(colorIndex, false, true, 255)); | |
| 4693 | } | ||
| 4694 | } | ||
| 4695 | |||
| 4696 | 23 | return FRAMETIME; | |
| 4697 | } | ||
| 4698 | static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //vertical | ||
| 4699 | |||
| 4700 | |||
| 4701 | /* | ||
| 4702 | * Dots waving around in a sine/pendulum motion. | ||
| 4703 | * Little pixel birds flying in a circle. By Aircoookie | ||
| 4704 | */ | ||
| 4705 | 23 | uint16_t mode_chunchun(void) | |
| 4706 | { | ||
| 4707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 4708 | 23 | SEGMENT.fade_out(254); // add a bit of trail | |
| 4709 | 23 | unsigned counter = strip().now * (6 + (SEGMENT.speed >> 4)); | |
| 4710 | 23 | unsigned numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment | |
| 4711 | 23 | unsigned span = (SEGMENT.intensity << 8) / numBirds; | |
| 4712 | |||
| 4713 |
2/2✓ Branch 0 taken 978 times.
✓ Branch 1 taken 23 times.
|
1001 | for (unsigned i = 0; i < numBirds; i++) |
| 4714 | { | ||
| 4715 | 978 | counter -= span; | |
| 4716 | 978 | unsigned megumin = sin16_t(counter) + 0x8000; | |
| 4717 | 978 | unsigned bird = uint32_t(megumin * SEGLEN) >> 16; | |
| 4718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 978 times.
|
978 | bird = constrain(bird, 0U, SEGLEN-1U); |
| 4719 | 978 | SEGMENT.setPixelColor(bird, SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0)); // no palette wrapping | |
| 4720 | } | ||
| 4721 | 23 | return FRAMETIME; | |
| 4722 | } | ||
| 4723 | static const char _data_FX_MODE_CHUNCHUN[] PROGMEM = "Chunchun@!,Gap size;!,!;!"; | ||
| 4724 | |||
| 4725 | #define SPOT_TYPE_SOLID 0 | ||
| 4726 | #define SPOT_TYPE_GRADIENT 1 | ||
| 4727 | #define SPOT_TYPE_2X_GRADIENT 2 | ||
| 4728 | #define SPOT_TYPE_2X_DOT 3 | ||
| 4729 | #define SPOT_TYPE_3X_DOT 4 | ||
| 4730 | #define SPOT_TYPE_4X_DOT 5 | ||
| 4731 | #define SPOT_TYPES_COUNT 6 | ||
| 4732 | #ifdef ESP8266 | ||
| 4733 | #define SPOT_MAX_COUNT 17 //Number of simultaneous waves | ||
| 4734 | #else | ||
| 4735 | #define SPOT_MAX_COUNT 49 //Number of simultaneous waves | ||
| 4736 | #endif | ||
| 4737 | |||
| 4738 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 4739 | //13 bytes | ||
| 4740 | typedef struct Spotlight { | ||
| 4741 | float speed; | ||
| 4742 | uint8_t colorIdx; | ||
| 4743 | int16_t position; | ||
| 4744 | unsigned long lastUpdateTime; | ||
| 4745 | uint8_t width; | ||
| 4746 | uint8_t type; | ||
| 4747 | } spotlight; | ||
| 4748 | |||
| 4749 | /* | ||
| 4750 | * Spotlights moving back and forth that cast dancing shadows. | ||
| 4751 | * Shine this through tree branches/leaves or other close-up objects that cast | ||
| 4752 | * interesting shadows onto a ceiling or tarp. | ||
| 4753 | * | ||
| 4754 | * By Steve Pomeroy @xxv | ||
| 4755 | */ | ||
| 4756 | 23 | uint16_t mode_dancing_shadows(void) | |
| 4757 | { | ||
| 4758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 4759 | 23 | unsigned numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266 | |
| 4760 | 23 | bool initialize = SEGENV.aux0 != numSpotlights; | |
| 4761 | 23 | SEGENV.aux0 = numSpotlights; | |
| 4762 | |||
| 4763 | 23 | unsigned dataSize = sizeof(spotlight) * numSpotlights; | |
| 4764 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 4765 | 23 | Spotlight* spotlights = reinterpret_cast<Spotlight*>(SEGENV.data); | |
| 4766 | |||
| 4767 | 23 | SEGMENT.fill(BLACK); | |
| 4768 | |||
| 4769 | 23 | unsigned long time = strip().now; | |
| 4770 | 23 | bool respawn = false; | |
| 4771 | |||
| 4772 |
2/2✓ Branch 0 taken 579 times.
✓ Branch 1 taken 23 times.
|
602 | for (size_t i = 0; i < numSpotlights; i++) { |
| 4773 |
2/2✓ Branch 0 taken 453 times.
✓ Branch 1 taken 126 times.
|
579 | if (!initialize) { |
| 4774 | // advance the position of the spotlight | ||
| 4775 | 906 | int delta = (float)(time - spotlights[i].lastUpdateTime) * | |
| 4776 | 453 | (spotlights[i].speed * ((1.0 + SEGMENT.speed)/100.0)); | |
| 4777 | |||
| 4778 |
2/2✓ Branch 0 taken 447 times.
✓ Branch 1 taken 6 times.
|
453 | if (abs(delta) >= 1) { |
| 4779 | 447 | spotlights[i].position += delta; | |
| 4780 | 447 | spotlights[i].lastUpdateTime = time; | |
| 4781 | } | ||
| 4782 | |||
| 4783 |
2/2✓ Branch 0 taken 213 times.
✓ Branch 1 taken 7 times.
|
673 | respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (int)(SEGLEN + 2)) |
| 4784 |
6/6✓ Branch 0 taken 220 times.
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 233 times.
✓ Branch 3 taken 213 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 230 times.
|
673 | || (spotlights[i].speed < 0.0 && spotlights[i].position < -(spotlights[i].width + 2)); |
| 4785 | } | ||
| 4786 | |||
| 4787 |
4/4✓ Branch 0 taken 453 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 443 times.
|
579 | if (initialize || respawn) { |
| 4788 | 136 | spotlights[i].colorIdx = hw_random8(); | |
| 4789 | 136 | spotlights[i].width = hw_random8(1, 10); | |
| 4790 | |||
| 4791 | 136 | spotlights[i].speed = 1.0/hw_random8(4, 50); | |
| 4792 | |||
| 4793 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 10 times.
|
136 | if (initialize) { |
| 4794 | 126 | spotlights[i].position = hw_random16(SEGLEN); | |
| 4795 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 64 times.
|
126 | spotlights[i].speed *= hw_random8(2) ? 1.0 : -1.0; |
| 4796 | } else { | ||
| 4797 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
|
10 | if (hw_random8(2)) { |
| 4798 | 4 | spotlights[i].position = SEGLEN + spotlights[i].width; | |
| 4799 | 4 | spotlights[i].speed *= -1.0; | |
| 4800 | }else { | ||
| 4801 | 6 | spotlights[i].position = -spotlights[i].width; | |
| 4802 | } | ||
| 4803 | } | ||
| 4804 | |||
| 4805 | 136 | spotlights[i].lastUpdateTime = time; | |
| 4806 | 136 | spotlights[i].type = hw_random8(SPOT_TYPES_COUNT); | |
| 4807 | } | ||
| 4808 | |||
| 4809 | 579 | uint32_t color = SEGMENT.color_from_palette(spotlights[i].colorIdx, false, false, 255); | |
| 4810 | 579 | int start = spotlights[i].position; | |
| 4811 | |||
| 4812 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 514 times.
|
579 | if (spotlights[i].width <= 1) { |
| 4813 |
5/6✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 61 times.
✓ Branch 5 taken 4 times.
|
65 | if (start >= 0 && start < (int)SEGLEN) { |
| 4814 | 61 | SEGMENT.blendPixelColor(start, color, 128); | |
| 4815 | } | ||
| 4816 | } else { | ||
| 4817 |
6/7✓ Branch 0 taken 77 times.
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 91 times.
✗ Branch 6 not taken.
|
514 | switch (spotlights[i].type) { |
| 4818 | 77 | case SPOT_TYPE_SOLID: | |
| 4819 |
2/2✓ Branch 0 taken 418 times.
✓ Branch 1 taken 77 times.
|
495 | for (size_t j = 0; j < spotlights[i].width; j++) { |
| 4820 |
2/2✓ Branch 0 taken 398 times.
✓ Branch 1 taken 20 times.
|
418 | if ((start + j) >= 0 && (start + j) < SEGLEN) { |
| 4821 | 398 | SEGMENT.blendPixelColor(start + j, color, 128); | |
| 4822 | } | ||
| 4823 | } | ||
| 4824 | 77 | break; | |
| 4825 | |||
| 4826 | 131 | case SPOT_TYPE_GRADIENT: | |
| 4827 |
2/2✓ Branch 0 taken 647 times.
✓ Branch 1 taken 131 times.
|
778 | for (size_t j = 0; j < spotlights[i].width; j++) { |
| 4828 |
2/2✓ Branch 0 taken 614 times.
✓ Branch 1 taken 33 times.
|
647 | if ((start + j) >= 0 && (start + j) < SEGLEN) { |
| 4829 | 614 | SEGMENT.blendPixelColor(start + j, color, cubicwave8(map(j, 0, spotlights[i].width - 1, 0, 255))); | |
| 4830 | } | ||
| 4831 | } | ||
| 4832 | 131 | break; | |
| 4833 | |||
| 4834 | 87 | case SPOT_TYPE_2X_GRADIENT: | |
| 4835 |
2/2✓ Branch 0 taken 401 times.
✓ Branch 1 taken 87 times.
|
488 | for (size_t j = 0; j < spotlights[i].width; j++) { |
| 4836 |
2/2✓ Branch 0 taken 388 times.
✓ Branch 1 taken 13 times.
|
401 | if ((start + j) >= 0 && (start + j) < SEGLEN) { |
| 4837 | 388 | SEGMENT.blendPixelColor(start + j, color, cubicwave8(2 * map(j, 0, spotlights[i].width - 1, 0, 255))); | |
| 4838 | } | ||
| 4839 | } | ||
| 4840 | 87 | break; | |
| 4841 | |||
| 4842 | 89 | case SPOT_TYPE_2X_DOT: | |
| 4843 |
2/2✓ Branch 0 taken 280 times.
✓ Branch 1 taken 89 times.
|
369 | for (size_t j = 0; j < spotlights[i].width; j += 2) { |
| 4844 |
2/2✓ Branch 0 taken 245 times.
✓ Branch 1 taken 35 times.
|
280 | if ((start + j) >= 0 && (start + j) < SEGLEN) { |
| 4845 | 245 | SEGMENT.blendPixelColor(start + j, color, 128); | |
| 4846 | } | ||
| 4847 | } | ||
| 4848 | 89 | break; | |
| 4849 | |||
| 4850 | 39 | case SPOT_TYPE_3X_DOT: | |
| 4851 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 39 times.
|
105 | for (size_t j = 0; j < spotlights[i].width; j += 3) { |
| 4852 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 1 times.
|
66 | if ((start + j) >= 0 && (start + j) < SEGLEN) { |
| 4853 | 65 | SEGMENT.blendPixelColor(start + j, color, 128); | |
| 4854 | } | ||
| 4855 | } | ||
| 4856 | 39 | break; | |
| 4857 | |||
| 4858 | 91 | case SPOT_TYPE_4X_DOT: | |
| 4859 |
2/2✓ Branch 0 taken 166 times.
✓ Branch 1 taken 91 times.
|
257 | for (size_t j = 0; j < spotlights[i].width; j += 4) { |
| 4860 |
2/2✓ Branch 0 taken 153 times.
✓ Branch 1 taken 13 times.
|
166 | if ((start + j) >= 0 && (start + j) < SEGLEN) { |
| 4861 | 153 | SEGMENT.blendPixelColor(start + j, color, 128); | |
| 4862 | } | ||
| 4863 | } | ||
| 4864 | 91 | break; | |
| 4865 | } | ||
| 4866 | } | ||
| 4867 | } | ||
| 4868 | |||
| 4869 | 23 | return FRAMETIME; | |
| 4870 | } | ||
| 4871 | static const char _data_FX_MODE_DANCING_SHADOWS[] PROGMEM = "Dancing Shadows@!,# of shadows;!;!"; | ||
| 4872 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 4873 | |||
| 4874 | /* | ||
| 4875 | Imitates a washing machine, rotating same waves forward, then pause, then backward. | ||
| 4876 | By Stefan Seegel | ||
| 4877 | */ | ||
| 4878 | 23 | uint16_t mode_washing_machine(void) { | |
| 4879 | 23 | int speed = tristate_square8(strip().now >> 7, 90, 15); | |
| 4880 | |||
| 4881 | 23 | SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); | |
| 4882 | |||
| 4883 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4884 | 7511 | uint8_t col = sin8_t(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); | |
| 4885 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); |
| 4886 | } | ||
| 4887 | |||
| 4888 | 23 | return FRAMETIME; | |
| 4889 | } | ||
| 4890 | static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,!;;!"; | ||
| 4891 | |||
| 4892 | |||
| 4893 | /* | ||
| 4894 | Image effect | ||
| 4895 | Draws a .gif image from filesystem on the matrix/strip | ||
| 4896 | */ | ||
| 4897 | ✗ | uint16_t mode_image(void) { | |
| 4898 | #ifndef WLED_ENABLE_GIF | ||
| 4899 | ✗ | return mode_static(); | |
| 4900 | #else | ||
| 4901 | renderImageToSegment(SEGMENT); | ||
| 4902 | return FRAMETIME; | ||
| 4903 | #endif | ||
| 4904 | // if (status != 0 && status != 254 && status != 255) { | ||
| 4905 | // Serial.print("GIF renderer return: "); | ||
| 4906 | // Serial.println(status); | ||
| 4907 | // } | ||
| 4908 | } | ||
| 4909 | static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; | ||
| 4910 | |||
| 4911 | /* | ||
| 4912 | Blends random colors across palette | ||
| 4913 | Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e | ||
| 4914 | */ | ||
| 4915 | 23 | uint16_t mode_blends(void) { | |
| 4916 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 13 times.
|
23 | unsigned pixelLen = SEGLEN > UINT8_MAX ? UINT8_MAX : SEGLEN; |
| 4917 | 23 | unsigned dataSize = sizeof(uint32_t) * (pixelLen + 1); // max segment length of 56 pixels on 16 segment ESP8266 | |
| 4918 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 4919 | 23 | uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | |
| 4920 | 23 | uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128); | |
| 4921 | 23 | unsigned shift = (strip().now * ((SEGMENT.speed >> 3) +1)) >> 8; | |
| 4922 | |||
| 4923 |
2/2✓ Branch 0 taken 4170 times.
✓ Branch 1 taken 23 times.
|
4193 | for (unsigned i = 0; i < pixelLen; i++) { |
| 4924 |
2/4✓ Branch 0 taken 4170 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4170 times.
|
4170 | pixels[i] = color_blend(pixels[i], SEGMENT.color_from_palette(shift + quadwave8((i + 1) * 16), false, PALETTE_SOLID_WRAP, 255), blendSpeed); |
| 4925 | 4170 | shift += 3; | |
| 4926 | } | ||
| 4927 | |||
| 4928 | 23 | unsigned offset = 0; | |
| 4929 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 4930 | 7511 | SEGMENT.setPixelColor(i, pixels[offset++]); | |
| 4931 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 7475 times.
|
7511 | if (offset >= pixelLen) offset = 0; |
| 4932 | } | ||
| 4933 | |||
| 4934 | 23 | return FRAMETIME; | |
| 4935 | } | ||
| 4936 | static const char _data_FX_MODE_BLENDS[] PROGMEM = "Blends@Shift speed,Blend speed;;!"; | ||
| 4937 | |||
| 4938 | |||
| 4939 | /* | ||
| 4940 | TV Simulator | ||
| 4941 | Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch | ||
| 4942 | */ | ||
| 4943 | //43 bytes | ||
| 4944 | typedef struct TvSim { | ||
| 4945 | uint32_t totalTime = 0; | ||
| 4946 | uint32_t fadeTime = 0; | ||
| 4947 | uint32_t startTime = 0; | ||
| 4948 | uint32_t elapsed = 0; | ||
| 4949 | uint32_t pixelNum = 0; | ||
| 4950 | uint16_t sliderValues = 0; | ||
| 4951 | uint32_t sceeneStart = 0; | ||
| 4952 | uint32_t sceeneDuration = 0; | ||
| 4953 | uint16_t sceeneColorHue = 0; | ||
| 4954 | uint8_t sceeneColorSat = 0; | ||
| 4955 | uint8_t sceeneColorBri = 0; | ||
| 4956 | uint8_t actualColorR = 0; | ||
| 4957 | uint8_t actualColorG = 0; | ||
| 4958 | uint8_t actualColorB = 0; | ||
| 4959 | uint16_t pr = 0; // Prev R, G, B | ||
| 4960 | uint16_t pg = 0; | ||
| 4961 | uint16_t pb = 0; | ||
| 4962 | } tvSim; | ||
| 4963 | |||
| 4964 | 23 | uint16_t mode_tv_simulator(void) { | |
| 4965 | int nr, ng, nb, r, g, b, i, hue; | ||
| 4966 | uint8_t sat, bri, j; | ||
| 4967 | |||
| 4968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(sizeof(tvSim))) return mode_static(); //allocation failed |
| 4969 | 23 | TvSim* tvSimulator = reinterpret_cast<TvSim*>(SEGENV.data); | |
| 4970 | |||
| 4971 | 23 | uint8_t colorSpeed = map(SEGMENT.speed, 0, UINT8_MAX, 1, 20); | |
| 4972 | 23 | uint8_t colorIntensity = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 30); | |
| 4973 | |||
| 4974 | 23 | i = SEGMENT.speed << 8 | SEGMENT.intensity; | |
| 4975 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
|
23 | if (i != tvSimulator->sliderValues) { |
| 4976 | 4 | tvSimulator->sliderValues = i; | |
| 4977 | 4 | SEGENV.aux1 = 0; | |
| 4978 | } | ||
| 4979 | |||
| 4980 | // create a new sceene | ||
| 4981 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (((strip().now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { |
| 4982 | 5 | tvSimulator->sceeneStart = strip().now; // remember the start of the new sceene | |
| 4983 | 5 | tvSimulator->sceeneDuration = hw_random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider) | |
| 4984 | 5 | tvSimulator->sceeneColorHue = hw_random16( 0, 768); // random start color-tone for the sceene | |
| 4985 | 5 | tvSimulator->sceeneColorSat = hw_random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene | |
| 4986 | 5 | tvSimulator->sceeneColorBri = hw_random8 ( 200, 240); // random start color-brightness for the sceene | |
| 4987 | 5 | SEGENV.aux1 = 1; | |
| 4988 | 5 | SEGENV.aux0 = 0; | |
| 4989 | } | ||
| 4990 | |||
| 4991 | // slightly change the color-tone in this sceene | ||
| 4992 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.aux0 == 0) { |
| 4993 | // hue change in both directions | ||
| 4994 | 5 | j = hw_random8(4 * colorIntensity); | |
| 4995 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
7 | hue = (hw_random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative |
| 4996 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767) ; // positive |
| 4997 | |||
| 4998 | // saturation | ||
| 4999 | 5 | j = hw_random8(2 * colorIntensity); | |
| 5000 | 5 | sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j; | |
| 5001 | |||
| 5002 | // brightness | ||
| 5003 | 5 | j = hw_random8(100); | |
| 5004 | 5 | bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j; | |
| 5005 | |||
| 5006 | // calculate R,G,B from HSV | ||
| 5007 | // Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/ | ||
| 5008 | { // just to create a local scope for the variables | ||
| 5009 | 5 | uint8_t temp[5], n = (hue >> 8) % 3; | |
| 5010 | 5 | uint8_t x = ((((hue & 255) * sat) >> 8) * bri) >> 8; | |
| 5011 | 5 | uint8_t s = ( (256 - sat) * bri) >> 8; | |
| 5012 | 5 | temp[0] = temp[3] = s; | |
| 5013 | 5 | temp[1] = temp[4] = x + s; | |
| 5014 | 5 | temp[2] = bri - x; | |
| 5015 | 5 | tvSimulator->actualColorR = temp[n + 2]; | |
| 5016 | 5 | tvSimulator->actualColorG = temp[n + 1]; | |
| 5017 | 5 | tvSimulator->actualColorB = temp[n ]; | |
| 5018 | } | ||
| 5019 | } | ||
| 5020 | // Apply gamma correction, further expand to 16/16/16 | ||
| 5021 | 23 | nr = (uint8_t)gamma8(tvSimulator->actualColorR) * 257; // New R/G/B | |
| 5022 | 23 | ng = (uint8_t)gamma8(tvSimulator->actualColorG) * 257; | |
| 5023 | 23 | nb = (uint8_t)gamma8(tvSimulator->actualColorB) * 257; | |
| 5024 | |||
| 5025 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.aux0 == 0) { // initialize next iteration |
| 5026 | 5 | SEGENV.aux0 = 1; | |
| 5027 | |||
| 5028 | // randomize total duration and fade duration for the actual color | ||
| 5029 | 5 | tvSimulator->totalTime = hw_random16(250, 2500); // Semi-random pixel-to-pixel time | |
| 5030 | 5 | tvSimulator->fadeTime = hw_random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time | |
| 5031 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if (hw_random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time |
| 5032 | |||
| 5033 | 5 | tvSimulator->startTime = strip().now; | |
| 5034 | } // end of initialization | ||
| 5035 | |||
| 5036 | // how much time is elapsed ? | ||
| 5037 | 23 | tvSimulator->elapsed = strip().now - tvSimulator->startTime; | |
| 5038 | |||
| 5039 | // fade from prev color to next color | ||
| 5040 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 8 times.
|
23 | if (tvSimulator->elapsed < tvSimulator->fadeTime) { |
| 5041 | 15 | r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr); | |
| 5042 | 15 | g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng); | |
| 5043 | 15 | b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb); | |
| 5044 | } else { // Avoid divide-by-zero in map() | ||
| 5045 | 8 | r = nr; | |
| 5046 | 8 | g = ng; | |
| 5047 | 8 | b = nb; | |
| 5048 | } | ||
| 5049 | |||
| 5050 | // set strip color | ||
| 5051 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (i = 0; i < (int)SEGLEN; i++) { |
| 5052 | 7511 | SEGMENT.setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit | |
| 5053 | } | ||
| 5054 | |||
| 5055 | // if total duration has passed, remember last color and restart the loop | ||
| 5056 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if ( tvSimulator->elapsed >= tvSimulator->totalTime) { |
| 5057 | ✗ | tvSimulator->pr = nr; // Prev RGB = new RGB | |
| 5058 | ✗ | tvSimulator->pg = ng; | |
| 5059 | ✗ | tvSimulator->pb = nb; | |
| 5060 | ✗ | SEGENV.aux0 = 0; | |
| 5061 | } | ||
| 5062 | |||
| 5063 | 23 | return FRAMETIME; | |
| 5064 | } | ||
| 5065 | static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;!;01"; | ||
| 5066 | |||
| 5067 | |||
| 5068 | /* | ||
| 5069 | Aurora effect | ||
| 5070 | */ | ||
| 5071 | |||
| 5072 | //CONFIG | ||
| 5073 | #ifdef ESP8266 | ||
| 5074 | #define W_MAX_COUNT 9 //Number of simultaneous waves | ||
| 5075 | #else | ||
| 5076 | #define W_MAX_COUNT 20 //Number of simultaneous waves | ||
| 5077 | #endif | ||
| 5078 | #define W_MAX_SPEED 6 //Higher number, higher speed | ||
| 5079 | #define W_WIDTH_FACTOR 6 //Higher number, smaller waves | ||
| 5080 | |||
| 5081 | //24 bytes | ||
| 5082 | class AuroraWave { | ||
| 5083 | private: | ||
| 5084 | uint16_t ttl; | ||
| 5085 | CRGB basecolor; | ||
| 5086 | float basealpha; | ||
| 5087 | uint16_t age; | ||
| 5088 | uint16_t width; | ||
| 5089 | float center; | ||
| 5090 | bool goingleft; | ||
| 5091 | float speed_factor; | ||
| 5092 | bool alive = true; | ||
| 5093 | |||
| 5094 | public: | ||
| 5095 | 60 | void init(uint32_t segment_length, CRGB color) { | |
| 5096 | 60 | ttl = hw_random16(500, 1501); | |
| 5097 | 60 | basecolor = color; | |
| 5098 | 60 | basealpha = hw_random8(60, 101) / (float)100; | |
| 5099 | 60 | age = 0; | |
| 5100 | 60 | width = hw_random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier | |
| 5101 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (!width) width = 1; |
| 5102 | 60 | center = hw_random8(101) / (float)100 * segment_length; | |
| 5103 | 60 | goingleft = hw_random8(0, 2) == 0; | |
| 5104 | 60 | speed_factor = (hw_random8(10, 31) / (float)100 * W_MAX_SPEED / 255); | |
| 5105 | 60 | alive = true; | |
| 5106 | 60 | } | |
| 5107 | |||
| 5108 | 83621 | CRGB getColorForLED(int ledIndex) { | |
| 5109 |
4/4✓ Branch 0 taken 53203 times.
✓ Branch 1 taken 30418 times.
✓ Branch 2 taken 36524 times.
✓ Branch 3 taken 16679 times.
|
83621 | if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave |
| 5110 | |||
| 5111 | CRGB rgb; | ||
| 5112 | |||
| 5113 | //Offset of this led from center of wave | ||
| 5114 | //The further away from the center, the dimmer the LED | ||
| 5115 | 16679 | float offset = ledIndex - center; | |
| 5116 |
2/2✓ Branch 0 taken 8859 times.
✓ Branch 1 taken 7820 times.
|
16679 | if (offset < 0) offset = -offset; |
| 5117 | 16679 | float offsetFactor = offset / width; | |
| 5118 | |||
| 5119 | //The age of the wave determines it brightness. | ||
| 5120 | //At half its maximum age it will be the brightest. | ||
| 5121 | 16679 | float ageFactor = 0.1; | |
| 5122 |
1/2✓ Branch 0 taken 16679 times.
✗ Branch 1 not taken.
|
16679 | if((float)age / ttl < 0.5) { |
| 5123 | 16679 | ageFactor = (float)age / (ttl / 2); | |
| 5124 | } else { | ||
| 5125 | ✗ | ageFactor = (float)(ttl - age) / ((float)ttl * 0.5); | |
| 5126 | } | ||
| 5127 | |||
| 5128 | //Calculate color based on above factors and basealpha value | ||
| 5129 | 16679 | float factor = (1 - offsetFactor) * ageFactor * basealpha; | |
| 5130 | 16679 | rgb.r = basecolor.r * factor; | |
| 5131 | 16679 | rgb.g = basecolor.g * factor; | |
| 5132 | 16679 | rgb.b = basecolor.b * factor; | |
| 5133 | |||
| 5134 | 16679 | return rgb; | |
| 5135 | }; | ||
| 5136 | |||
| 5137 | //Change position and age of wave | ||
| 5138 | //Determine if its sill "alive" | ||
| 5139 | 273 | void update(uint32_t segment_length, uint32_t speed) { | |
| 5140 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 116 times.
|
273 | if(goingleft) { |
| 5141 | 157 | center -= speed_factor * speed; | |
| 5142 | } else { | ||
| 5143 | 116 | center += speed_factor * speed; | |
| 5144 | } | ||
| 5145 | |||
| 5146 | 273 | age++; | |
| 5147 | |||
| 5148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
|
273 | if(age > ttl) { |
| 5149 | ✗ | alive = false; | |
| 5150 | } else { | ||
| 5151 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 116 times.
|
273 | if(goingleft) { |
| 5152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
|
157 | if(center + width < 0) { |
| 5153 | ✗ | alive = false; | |
| 5154 | } | ||
| 5155 | } else { | ||
| 5156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
|
116 | if(center - width > segment_length) { |
| 5157 | ✗ | alive = false; | |
| 5158 | } | ||
| 5159 | } | ||
| 5160 | } | ||
| 5161 | 273 | }; | |
| 5162 | |||
| 5163 | 273 | bool stillAlive() { | |
| 5164 | 273 | return alive; | |
| 5165 | }; | ||
| 5166 | }; | ||
| 5167 | |||
| 5168 | 27 | uint16_t mode_aurora(void) { | |
| 5169 | //aux1 = Wavecount | ||
| 5170 | //aux2 = Intensity in last loop | ||
| 5171 | |||
| 5172 | AuroraWave* waves; | ||
| 5173 | |||
| 5174 | //TODO: I am not sure this is a correct way of handling memory allocation since if it fails on 1st run | ||
| 5175 | // it will display static effect but on second run it may crash ESP since data will be nullptr | ||
| 5176 | |||
| 5177 |
6/6✓ Branch 0 taken 22 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 21 times.
|
27 | if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) { |
| 5178 | //Intensity slider changed or first call | ||
| 5179 | 6 | SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT); | |
| 5180 | 6 | SEGENV.aux0 = SEGMENT.intensity; | |
| 5181 | |||
| 5182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 16 segment ESP8266 |
| 5183 | ✗ | return mode_static(); //allocation failed | |
| 5184 | } | ||
| 5185 | |||
| 5186 | 6 | waves = reinterpret_cast<AuroraWave*>(SEGENV.data); | |
| 5187 | |||
| 5188 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 6 times.
|
66 | for (int i = 0; i < SEGENV.aux1; i++) { |
| 5189 |
3/6✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
|
60 | waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3)))); |
| 5190 | } | ||
| 5191 | } else { | ||
| 5192 | 21 | waves = reinterpret_cast<AuroraWave*>(SEGENV.data); | |
| 5193 | } | ||
| 5194 | |||
| 5195 |
2/2✓ Branch 0 taken 273 times.
✓ Branch 1 taken 27 times.
|
300 | for (int i = 0; i < SEGENV.aux1; i++) { |
| 5196 | //Update values of wave | ||
| 5197 | 273 | waves[i].update(SEGLEN, SEGMENT.speed); | |
| 5198 | |||
| 5199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
|
273 | if(!(waves[i].stillAlive())) { |
| 5200 | //If a wave dies, reinitialize it starts over. | ||
| 5201 | ✗ | waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3)))); | |
| 5202 | } | ||
| 5203 | } | ||
| 5204 | |||
| 5205 | 27 | uint8_t backlight = 1; //dimmer backlight if less active colors | |
| 5206 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (SEGCOLOR(0)) backlight++; |
| 5207 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (SEGCOLOR(1)) backlight++; |
| 5208 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 23 times.
|
27 | if (SEGCOLOR(2)) backlight++; |
| 5209 | //Loop through LEDs to determine color | ||
| 5210 |
2/2✓ Branch 0 taken 7711 times.
✓ Branch 1 taken 27 times.
|
7738 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 5211 | 7711 | CRGB mixedRgb = CRGB(backlight, backlight, backlight); | |
| 5212 | |||
| 5213 | //For each LED we must check each wave if it is "active" at this position. | ||
| 5214 | //If there are multiple waves active on a LED we multiply their values. | ||
| 5215 |
4/6✓ Branch 0 taken 91332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91332 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 83621 times.
✓ Branch 5 taken 7711 times.
|
91332 | for (int j = 0; j < SEGENV.aux1; j++) { |
| 5216 | 83621 | CRGB rgb = waves[j].getColorForLED(i); | |
| 5217 | |||
| 5218 |
2/2✓ Branch 0 taken 1479 times.
✓ Branch 1 taken 82142 times.
|
167242 | if(rgb != CRGB(0)) { |
| 5219 |
1/2✓ Branch 0 taken 1479 times.
✗ Branch 1 not taken.
|
1479 | mixedRgb += rgb; |
| 5220 | } | ||
| 5221 | } | ||
| 5222 | |||
| 5223 |
3/6✓ Branch 0 taken 7711 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7711 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7711 times.
✗ Branch 5 not taken.
|
30844 | SEGMENT.setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2]); |
| 5224 | } | ||
| 5225 | |||
| 5226 | 27 | return FRAMETIME; | |
| 5227 | } | ||
| 5228 | static const char _data_FX_MODE_AURORA[] PROGMEM = "Aurora@!,!;1,2,3;!;;sx=24,pal=50"; | ||
| 5229 | |||
| 5230 | // WLED-SR effects | ||
| 5231 | |||
| 5232 | ///////////////////////// | ||
| 5233 | // Perlin Move // | ||
| 5234 | ///////////////////////// | ||
| 5235 | // 16 bit perlinmove. Use Perlin Noise instead of sinewaves for movement. By Andrew Tuline. | ||
| 5236 | // Controls are speed, # of pixels, faderate. | ||
| 5237 | 23 | uint16_t mode_perlinmove(void) { | |
| 5238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 5239 | 23 | SEGMENT.fade_out(255-SEGMENT.custom1); | |
| 5240 |
2/2✓ Branch 0 taken 203 times.
✓ Branch 1 taken 23 times.
|
226 | for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) { |
| 5241 | 203 | unsigned locn = perlin16(strip().now*128/(260-SEGMENT.speed)+i*15000, strip().now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. | |
| 5242 | 203 | unsigned pixloc = map(locn, 50*256, 192*256, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. | |
| 5243 |
2/4✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
|
203 | SEGMENT.setPixelColor(pixloc, SEGMENT.color_from_palette(pixloc%255, false, PALETTE_SOLID_WRAP, 0)); |
| 5244 | } | ||
| 5245 | |||
| 5246 | 23 | return FRAMETIME; | |
| 5247 | } // mode_perlinmove() | ||
| 5248 | static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixels,Fade rate;!,!;!"; | ||
| 5249 | |||
| 5250 | |||
| 5251 | ///////////////////////// | ||
| 5252 | // Waveins // | ||
| 5253 | ///////////////////////// | ||
| 5254 | // Uses beatsin8() + phase shifting. By: Andrew Tuline | ||
| 5255 | 23 | uint16_t mode_wavesins(void) { | |
| 5256 | |||
| 5257 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 5258 | 7511 | uint8_t bri = sin8_t(strip().now/4 + i * SEGMENT.intensity); | |
| 5259 | 7511 | uint8_t index = beatsin8_t(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider | |
| 5260 | //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); | ||
| 5261 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); |
| 5262 | } | ||
| 5263 | |||
| 5264 | 23 | return FRAMETIME; | |
| 5265 | } // mode_waveins() | ||
| 5266 | static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness variation,Starting color,Range of colors,Color variation;!;!"; | ||
| 5267 | |||
| 5268 | |||
| 5269 | ////////////////////////////// | ||
| 5270 | // Flow Stripe // | ||
| 5271 | ////////////////////////////// | ||
| 5272 | // By: ldirko https://editor.soulmatelights.com/gallery/392-flow-led-stripe , modifed by: Andrew Tuline | ||
| 5273 | 23 | uint16_t mode_FlowStripe(void) { | |
| 5274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 5275 | 23 | const int hl = SEGLEN * 10 / 13; | |
| 5276 | 23 | uint8_t hue = strip().now / (SEGMENT.speed+1); | |
| 5277 | 23 | uint32_t t = strip().now / (SEGMENT.intensity/8+1); | |
| 5278 | |||
| 5279 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 5280 | 7511 | int c = (abs((int)i - hl) / hl) * 127; | |
| 5281 | 7511 | c = sin8_t(c); | |
| 5282 | 7511 | c = sin8_t(c / 2 + t); | |
| 5283 | 7511 | byte b = sin8_t(c + t/8); | |
| 5284 |
1/2✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
|
15022 | SEGMENT.setPixelColor(i, CHSV(b + hue, 255, 255)); |
| 5285 | } | ||
| 5286 | |||
| 5287 | 23 | return FRAMETIME; | |
| 5288 | } // mode_FlowStripe() | ||
| 5289 | static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Effect speed;;"; | ||
| 5290 | |||
| 5291 | |||
| 5292 | #ifndef WLED_DISABLE_2D | ||
| 5293 | /////////////////////////////////////////////////////////////////////////////// | ||
| 5294 | //*************************** 2D routines *********************************** | ||
| 5295 | |||
| 5296 | |||
| 5297 | // Black hole | ||
| 5298 | 34 | uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline | |
| 5299 |
5/6✓ Branch 0 taken 29 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 29 times.
|
34 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5300 | |||
| 5301 | 29 | const int cols = SEG_W; | |
| 5302 | 29 | const int rows = SEG_H; | |
| 5303 | int x, y; | ||
| 5304 | |||
| 5305 | 29 | SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails | |
| 5306 | 29 | unsigned long t = strip().now/128; // timebase | |
| 5307 | // outer stars | ||
| 5308 |
2/2✓ Branch 0 taken 232 times.
✓ Branch 1 taken 29 times.
|
261 | for (size_t i = 0; i < 8; i++) { |
| 5309 | 232 | x = beatsin8_t(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); | |
| 5310 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 116 times.
|
232 | y = beatsin8_t(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); |
| 5311 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
✓ Branch 2 taken 232 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 232 times.
|
232 | SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(i*32, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); |
| 5312 | } | ||
| 5313 | // inner stars | ||
| 5314 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 29 times.
|
145 | for (size_t i = 0; i < 4; i++) { |
| 5315 | 116 | x = beatsin8_t(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); | |
| 5316 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 58 times.
|
116 | y = beatsin8_t(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); |
| 5317 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 116 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 116 times.
|
116 | SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(255-i*64, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); |
| 5318 | } | ||
| 5319 | // central white dot | ||
| 5320 | 29 | SEGMENT.setPixelColorXY(cols/2, rows/2, WHITE); | |
| 5321 | // blur everything a bit | ||
| 5322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (SEGMENT.check3) SEGMENT.blur(16, cols*rows < 100); |
| 5323 | |||
| 5324 | 29 | return FRAMETIME; | |
| 5325 | } // mode_2DBlackHole() | ||
| 5326 | static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid,,Blur;!;!;2;pal=11"; | ||
| 5327 | |||
| 5328 | |||
| 5329 | //////////////////////////// | ||
| 5330 | // 2D Colored Bursts // | ||
| 5331 | //////////////////////////// | ||
| 5332 | 23 | uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.soulmatelights.com/gallery/819-colored-bursts , modified by: Andrew Tuline | |
| 5333 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5334 | |||
| 5335 | 18 | const int cols = SEG_W; | |
| 5336 | 18 | const int rows = SEG_H; | |
| 5337 | |||
| 5338 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 5339 | 4 | SEGENV.aux0 = 0; // start with red hue | |
| 5340 | } | ||
| 5341 | |||
| 5342 | 18 | bool dot = SEGMENT.check3; | |
| 5343 | 18 | bool grad = SEGMENT.check1; | |
| 5344 | |||
| 5345 | 18 | byte numLines = SEGMENT.intensity/16 + 1; | |
| 5346 | |||
| 5347 | 18 | SEGENV.aux0++; // hue | |
| 5348 | 18 | SEGMENT.fadeToBlackBy(40 - SEGMENT.check2 * 8); | |
| 5349 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 18 times.
|
176 | for (size_t i = 0; i < numLines; i++) { |
| 5350 | 158 | byte x1 = beatsin8_t(2 + SEGMENT.speed/16, 0, (cols - 1)); | |
| 5351 | 158 | byte x2 = beatsin8_t(1 + SEGMENT.speed/16, 0, (rows - 1)); | |
| 5352 | 158 | byte y1 = beatsin8_t(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); | |
| 5353 | 158 | byte y2 = beatsin8_t(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); | |
| 5354 | 158 | uint32_t color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); | |
| 5355 | |||
| 5356 |
2/2✓ Branch 0 taken 107 times.
✓ Branch 1 taken 51 times.
|
158 | byte xsteps = abs8(x1 - y1) + 1; |
| 5357 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 84 times.
|
158 | byte ysteps = abs8(x2 - y2) + 1; |
| 5358 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 43 times.
|
158 | byte steps = xsteps >= ysteps ? xsteps : ysteps; |
| 5359 | //Draw gradient line | ||
| 5360 |
2/2✓ Branch 0 taken 1828 times.
✓ Branch 1 taken 158 times.
|
1986 | for (size_t j = 1; j <= steps; j++) { |
| 5361 | 1828 | uint8_t rate = j * 255 / steps; | |
| 5362 | 1828 | byte dx = lerp8by8(x1, y1, rate); | |
| 5363 | 1828 | byte dy = lerp8by8(x2, y2, rate); | |
| 5364 | //SEGMENT.setPixelColorXY(dx, dy, grad ? color.nscale8_video(255-rate) : color); // use addPixelColorXY for different look | ||
| 5365 | 1828 | SEGMENT.addPixelColorXY(dx, dy, color); // use setPixelColorXY for different look | |
| 5366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1828 times.
|
1828 | if (grad) SEGMENT.fadePixelColorXY(dx, dy, rate); |
| 5367 | } | ||
| 5368 | |||
| 5369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
|
158 | if (dot) { //add white point at the ends of line |
| 5370 | ✗ | SEGMENT.setPixelColorXY(x1, x2, WHITE); | |
| 5371 | ✗ | SEGMENT.setPixelColorXY(y1, y2, DARKSLATEGRAY); | |
| 5372 | } | ||
| 5373 | } | ||
| 5374 | 18 | SEGMENT.blur(SEGMENT.custom3>>1, SEGMENT.check2); | |
| 5375 | |||
| 5376 | 18 | return FRAMETIME; | |
| 5377 | } // mode_2DColoredBursts() | ||
| 5378 | static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines,,,Blur,Gradient,Smear,Dots;;!;2;c3=16"; | ||
| 5379 | |||
| 5380 | |||
| 5381 | ///////////////////// | ||
| 5382 | // 2D DNA // | ||
| 5383 | ///////////////////// | ||
| 5384 | 23 | uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pastebin.com/pCkkkzcs. Updated by Preyy. WLED conversion by Andrew Tuline. | |
| 5385 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5386 | |||
| 5387 | 18 | const int cols = SEG_W; | |
| 5388 | 18 | const int rows = SEG_H; | |
| 5389 | |||
| 5390 | 18 | SEGMENT.fadeToBlackBy(64); | |
| 5391 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int i = 0; i < cols; i++) { |
| 5392 | 451 | SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip().now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); | |
| 5393 | 451 | SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip().now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); | |
| 5394 | } | ||
| 5395 | 18 | SEGMENT.blur(SEGMENT.intensity / (8 - (SEGMENT.check1 * 2)), SEGMENT.check1); | |
| 5396 | |||
| 5397 | 18 | return FRAMETIME; | |
| 5398 | } // mode_2Ddna() | ||
| 5399 | static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur,,,,Smear;;!;2;ix=0"; | ||
| 5400 | |||
| 5401 | ///////////////////////// | ||
| 5402 | // 2D DNA Spiral // | ||
| 5403 | ///////////////////////// | ||
| 5404 | 23 | uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/512-dna-spiral-variation , modified by: Andrew Tuline | |
| 5405 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5406 | |||
| 5407 | 18 | const int cols = SEG_W; | |
| 5408 | 18 | const int rows = SEG_H; | |
| 5409 | |||
| 5410 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 5411 | 4 | SEGMENT.fill(BLACK); | |
| 5412 | } | ||
| 5413 | |||
| 5414 | 18 | unsigned speeds = SEGMENT.speed/2 + 7; | |
| 5415 | 18 | unsigned freq = SEGMENT.intensity/8; | |
| 5416 | |||
| 5417 | 18 | uint32_t ms = strip().now / 20; | |
| 5418 | 18 | SEGMENT.fadeToBlackBy(135); | |
| 5419 | |||
| 5420 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 18 times.
|
241 | for (int i = 0; i < rows; i++) { |
| 5421 | 223 | int x = beatsin8_t(speeds, 0, cols - 1, 0, i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, i * freq + 128); | |
| 5422 | 223 | int x1 = beatsin8_t(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); | |
| 5423 | 223 | unsigned hue = (i * 128 / rows) + ms; | |
| 5424 | // skip every 4th row every now and then (fade it more) | ||
| 5425 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 55 times.
|
223 | if ((i + ms / 8) & 3) { |
| 5426 | // draw a gradient line between x and x1 | ||
| 5427 | 168 | x = x / 2; x1 = x1 / 2; | |
| 5428 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 104 times.
|
168 | unsigned steps = abs8(x - x1) + 1; |
| 5429 | 168 | bool positive = (x1 >= x); // direction of drawing | |
| 5430 |
2/2✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 168 times.
|
3000 | for (size_t k = 1; k <= steps; k++) { |
| 5431 | 2832 | unsigned rate = k * 255 / steps; | |
| 5432 | //unsigned dx = lerp8by8(x, x1, rate); | ||
| 5433 |
2/2✓ Branch 0 taken 866 times.
✓ Branch 1 taken 1966 times.
|
2832 | unsigned dx = positive? (x + k-1) : (x - k+1); // behaves the same as "lerp8by8" but does not create holes |
| 5434 | //SEGMENT.setPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND).nscale8_video(rate)); | ||
| 5435 | 2832 | SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND)); // use setPixelColorXY for different look | |
| 5436 | 2832 | SEGMENT.fadePixelColorXY(dx, i, rate); | |
| 5437 | } | ||
| 5438 | 168 | SEGMENT.setPixelColorXY(x, i, DARKSLATEGRAY); | |
| 5439 | 168 | SEGMENT.setPixelColorXY(x1, i, WHITE); | |
| 5440 | } | ||
| 5441 | } | ||
| 5442 | 18 | SEGMENT.blur(((uint16_t)SEGMENT.custom1 * 3) / (6 + SEGMENT.check1), SEGMENT.check1); | |
| 5443 | |||
| 5444 | 18 | return FRAMETIME; | |
| 5445 | } // mode_2DDNASpiral() | ||
| 5446 | static const char _data_FX_MODE_2DDNASPIRAL[] PROGMEM = "DNA Spiral@Scroll speed,Y frequency,Blur,,,Smear;;!;2;c1=0"; | ||
| 5447 | |||
| 5448 | |||
| 5449 | ///////////////////////// | ||
| 5450 | // 2D Drift // | ||
| 5451 | ///////////////////////// | ||
| 5452 | 23 | uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmatelights.com/gallery/884-drift , Modified by: Andrew Tuline | |
| 5453 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5454 | |||
| 5455 | 18 | const int cols = SEG_W; | |
| 5456 | 18 | const int rows = SEG_H; | |
| 5457 | |||
| 5458 | 18 | const int colsCenter = (cols>>1) + (cols%2); | |
| 5459 | 18 | const int rowsCenter = (rows>>1) + (rows%2); | |
| 5460 | |||
| 5461 | 18 | SEGMENT.fadeToBlackBy(128); | |
| 5462 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | const float maxDim = MAX(cols, rows)/2; |
| 5463 | 18 | unsigned long t = strip().now / (32 - (SEGMENT.speed>>3)); | |
| 5464 | 18 | unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup | |
| 5465 |
2/2✓ Branch 0 taken 820 times.
✓ Branch 1 taken 18 times.
|
838 | for (float i = 1.0f; i < maxDim; i += 0.25f) { |
| 5466 | 820 | float angle = radians(t * (maxDim - i)); | |
| 5467 | 820 | int mySin = sin_t(angle) * i; | |
| 5468 | 820 | int myCos = cos_t(angle) * i; | |
| 5469 | 820 | SEGMENT.setPixelColorXY(colsCenter + mySin, rowsCenter + myCos, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND)); | |
| 5470 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 820 times.
|
820 | if (SEGMENT.check1) SEGMENT.setPixelColorXY(colsCenter + myCos, rowsCenter + mySin, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND)); |
| 5471 | } | ||
| 5472 | 18 | SEGMENT.blur(SEGMENT.intensity>>(3 - SEGMENT.check2), SEGMENT.check2); | |
| 5473 | |||
| 5474 | 18 | return FRAMETIME; | |
| 5475 | } // mode_2DDrift() | ||
| 5476 | static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur,,,,Twin,Smear;;!;2;ix=0"; | ||
| 5477 | |||
| 5478 | |||
| 5479 | ////////////////////////// | ||
| 5480 | // 2D Firenoise // | ||
| 5481 | ////////////////////////// | ||
| 5482 | 23 | uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline. Yet another short routine. | |
| 5483 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5484 | |||
| 5485 | 18 | const int cols = SEG_W; | |
| 5486 | 18 | const int rows = SEG_H; | |
| 5487 | |||
| 5488 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 5489 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | SEGMENT.fill(BLACK); |
| 5490 | } | ||
| 5491 | |||
| 5492 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | unsigned xscale = SEGMENT.intensity*4; |
| 5493 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | unsigned yscale = SEGMENT.speed*8; |
| 5494 | 18 | unsigned indexx = 0; | |
| 5495 | |||
| 5496 |
6/12✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
|
18 | CRGBPalette16 pal = SEGMENT.check1 ? SEGPALETTE : SEGMENT.loadPalette(pal, 35); |
| 5497 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int j=0; j < cols; j++) { |
| 5498 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int i=0; i < rows; i++) { |
| 5499 |
2/4✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
|
6761 | indexx = perlin8(j*yscale*rows/255, i*xscale+strip().now/4); // We're moving along our Perlin map. |
| 5500 |
4/8✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6761 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6761 times.
✗ Branch 7 not taken.
|
6761 | SEGMENT.setPixelColorXY(j, i, ColorFromPalette(pal, min(i*indexx/11, 225U), i*255/rows, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. |
| 5501 | } // for i | ||
| 5502 | } // for j | ||
| 5503 | |||
| 5504 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 5505 | } // mode_2Dfirenoise() | ||
| 5506 | static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y scale,,,,Palette;;!;2;pal=66"; | ||
| 5507 | |||
| 5508 | |||
| 5509 | ////////////////////////////// | ||
| 5510 | // 2D Frizzles // | ||
| 5511 | ////////////////////////////// | ||
| 5512 | 23 | uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.soulmatelights.com/gallery/640-color-frizzles , Modified by: Andrew Tuline | |
| 5513 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5514 | |||
| 5515 | 18 | const int cols = SEG_W; | |
| 5516 | 18 | const int rows = SEG_H; | |
| 5517 | |||
| 5518 | 18 | SEGMENT.fadeToBlackBy(16 + SEGMENT.check1 * 10); | |
| 5519 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 18 times.
|
162 | for (size_t i = 8; i > 0; i--) { |
| 5520 | 432 | SEGMENT.addPixelColorXY(beatsin8_t(SEGMENT.speed/8 + i, 0, cols - 1), | |
| 5521 | 144 | beatsin8_t(SEGMENT.intensity/8 - i, 0, rows - 1), | |
| 5522 | 144 | ColorFromPalette(SEGPALETTE, beatsin8_t(12, 0, 255), 255, LINEARBLEND)); | |
| 5523 | } | ||
| 5524 | 18 | SEGMENT.blur(SEGMENT.custom1 >> (3 + SEGMENT.check1), SEGMENT.check1); | |
| 5525 | 18 | return FRAMETIME; | |
| 5526 | } // mode_2DFrizzles() | ||
| 5527 | static const char _data_FX_MODE_2DFRIZZLES[] PROGMEM = "Frizzles@X frequency,Y frequency,Blur,,,Smear;;!;2"; | ||
| 5528 | |||
| 5529 | |||
| 5530 | /////////////////////////////////////////// | ||
| 5531 | // 2D Cellular Automata Game of life // | ||
| 5532 | /////////////////////////////////////////// | ||
| 5533 | typedef struct ColorCount { | ||
| 5534 | CRGB color; | ||
| 5535 | int8_t count; | ||
| 5536 | } colorCount; | ||
| 5537 | |||
| 5538 | 23 | uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color | |
| 5539 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5540 | |||
| 5541 | 18 | const int cols = SEG_W; | |
| 5542 | 18 | const int rows = SEG_H; | |
| 5543 | 22247 | const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; | |
| 5544 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | const unsigned dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled |
| 5545 | 18 | const int crcBufferLen = 2; //(SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi) | |
| 5546 | |||
| 5547 |
4/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
18 | if (!SEGENV.allocateData(dataSize + sizeof(uint16_t)*crcBufferLen)) return mode_static(); //allocation failed |
| 5548 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | CRGB *prevLeds = reinterpret_cast<CRGB*>(SEGENV.data); |
| 5549 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint16_t *crcBuffer = reinterpret_cast<uint16_t*>(SEGENV.data + dataSize); |
| 5550 | |||
| 5551 | 18 | CRGB backgroundColor = SEGCOLOR(1); | |
| 5552 | |||
| 5553 |
10/16✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 14 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 14 times.
✓ Branch 14 taken 4 times.
✓ Branch 15 taken 14 times.
|
18 | if (SEGENV.call == 0 || strip().now - SEGMENT.step > 3000) { |
| 5554 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | SEGENV.step = strip().now; |
| 5555 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux0 = 0; |
| 5556 | |||
| 5557 | //give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen) | ||
| 5558 |
4/4✓ Branch 0 taken 1557 times.
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 103 times.
✓ Branch 3 taken 4 times.
|
1664 | for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) { |
| 5559 | 1557 | unsigned state = hw_random8()%2; | |
| 5560 |
2/2✓ Branch 0 taken 719 times.
✓ Branch 1 taken 838 times.
|
1557 | if (state == 0) |
| 5561 |
3/6✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 719 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 719 times.
✗ Branch 5 not taken.
|
719 | SEGMENT.setPixelColorXY(x,y, backgroundColor); |
| 5562 | else | ||
| 5563 |
10/20✓ Branch 0 taken 838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 838 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 838 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 838 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 838 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 838 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 838 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 838 times.
✓ Branch 16 taken 838 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 838 times.
✗ Branch 19 not taken.
|
838 | SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 255)); |
| 5564 | } | ||
| 5565 | |||
| 5566 |
4/4✓ Branch 0 taken 1557 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 4 times.
|
1612 | for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black; |
| 5567 | 4 | memset(crcBuffer, 0, sizeof(uint16_t)*crcBufferLen); | |
| 5568 |
7/12✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✓ Branch 11 taken 1 times.
|
14 | } else if (strip().now - SEGENV.step < FRAMETIME_FIXED * (uint32_t)map(SEGMENT.speed,0,255,64,4)) { |
| 5569 | // update only when appropriate time passes (in 42 FPS slots) | ||
| 5570 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | return FRAMETIME; |
| 5571 | } | ||
| 5572 | |||
| 5573 | //copy previous leds (save previous generation) | ||
| 5574 | //NOTE: using lossy getPixelColor() is a benefit as endlessly repeating patterns will eventually fade out causing a reset | ||
| 5575 |
7/10✓ Branch 0 taken 2069 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2069 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2069 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2069 times.
✓ Branch 7 taken 135 times.
✓ Branch 8 taken 135 times.
✓ Branch 9 taken 5 times.
|
2209 | for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) prevLeds[XY(x,y)] = SEGMENT.getPixelColorXY(x,y); |
| 5576 | |||
| 5577 | //calculate new leds | ||
| 5578 |
4/4✓ Branch 0 taken 2069 times.
✓ Branch 1 taken 135 times.
✓ Branch 2 taken 135 times.
✓ Branch 3 taken 5 times.
|
2209 | for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) { |
| 5579 | |||
| 5580 |
2/2✓ Branch 0 taken 18621 times.
✓ Branch 1 taken 2069 times.
|
20690 | colorCount colorsCount[9]; // count the different colors in the 3*3 matrix |
| 5581 |
2/2✓ Branch 0 taken 18621 times.
✓ Branch 1 taken 2069 times.
|
20690 | for (int i=0; i<9; i++) colorsCount[i] = {backgroundColor, 0}; // init colorsCount |
| 5582 | |||
| 5583 | // iterate through neighbors and count them and their different colors | ||
| 5584 | 2069 | int neighbors = 0; | |
| 5585 |
4/4✓ Branch 0 taken 18621 times.
✓ Branch 1 taken 6207 times.
✓ Branch 2 taken 6207 times.
✓ Branch 3 taken 2069 times.
|
26897 | for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) { // iterate through 3*3 matrix |
| 5586 |
4/4✓ Branch 0 taken 6207 times.
✓ Branch 1 taken 12414 times.
✓ Branch 2 taken 2069 times.
✓ Branch 3 taken 4138 times.
|
18621 | if (i==0 && j==0) continue; // ignore itself |
| 5587 | // wrap around segment | ||
| 5588 | 16552 | int xx = x+i, yy = y+j; | |
| 5589 |
4/4✓ Branch 0 taken 201 times.
✓ Branch 1 taken 16351 times.
✓ Branch 2 taken 201 times.
✓ Branch 3 taken 16150 times.
|
16552 | if (x+i < 0) xx = cols-1; else if (x+i >= cols) xx = 0; |
| 5590 |
4/4✓ Branch 0 taken 405 times.
✓ Branch 1 taken 16147 times.
✓ Branch 2 taken 405 times.
✓ Branch 3 taken 15742 times.
|
16552 | if (y+j < 0) yy = rows-1; else if (y+j >= rows) yy = 0; |
| 5591 | |||
| 5592 | 16552 | unsigned xy = XY(xx, yy); // previous cell xy to check | |
| 5593 | // count different neighbours and colors | ||
| 5594 |
4/4✓ Branch 0 taken 11048 times.
✓ Branch 1 taken 5504 times.
✓ Branch 2 taken 12712 times.
✓ Branch 3 taken 3840 times.
|
33104 | if (prevLeds[xy] != backgroundColor) { |
| 5595 | 12712 | neighbors++; | |
| 5596 | 12712 | bool colorFound = false; | |
| 5597 | int k; | ||
| 5598 |
3/4✓ Branch 0 taken 31368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18656 times.
✓ Branch 3 taken 12712 times.
|
31368 | for (k=0; k<9 && colorsCount[k].count != 0; k++) |
| 5599 |
4/4✓ Branch 0 taken 8982 times.
✓ Branch 1 taken 9674 times.
✓ Branch 2 taken 6328 times.
✓ Branch 3 taken 12328 times.
|
37312 | if (colorsCount[k].color == prevLeds[xy]) { |
| 5600 | 6328 | colorsCount[k].count++; | |
| 5601 | 6328 | colorFound = true; | |
| 5602 | } | ||
| 5603 |
2/2✓ Branch 0 taken 6384 times.
✓ Branch 1 taken 6328 times.
|
12712 | if (!colorFound) colorsCount[k] = {prevLeds[xy], 1}; //add new color found in the array |
| 5604 | } | ||
| 5605 | } // i,j | ||
| 5606 | |||
| 5607 | // Rules of Life | ||
| 5608 | 2069 | uint32_t col = uint32_t(prevLeds[XY(x,y)]) & 0x00FFFFFF; // uint32_t operator returns RGBA, we want RGBW -> cut off "alpha" byte | |
| 5609 | 2069 | uint32_t bgc = RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0); | |
| 5610 |
7/10✓ Branch 0 taken 1589 times.
✓ Branch 1 taken 480 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1578 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
|
2069 | if ((col != bgc) && (neighbors < 2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness |
| 5611 |
7/10✓ Branch 0 taken 1578 times.
✓ Branch 1 taken 480 times.
✓ Branch 2 taken 1410 times.
✓ Branch 3 taken 168 times.
✓ Branch 4 taken 1410 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1410 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1410 times.
✗ Branch 9 not taken.
|
2058 | else if ((col != bgc) && (neighbors > 3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation |
| 5612 |
4/4✓ Branch 0 taken 480 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 415 times.
|
648 | else if ((col == bgc) && (neighbors == 3)) { // Reproduction |
| 5613 | // find dominant color and assign it to a cell | ||
| 5614 | 65 | colorCount dominantColorCount = {backgroundColor, 0}; | |
| 5615 |
3/4✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 65 times.
|
259 | for (int i=0; i<9 && colorsCount[i].count != 0; i++) |
| 5616 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 128 times.
|
194 | if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i]; |
| 5617 | // assign the dominant color w/ a bit of randomness to avoid "gliders" | ||
| 5618 |
6/12✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 65 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 65 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 65 times.
✗ Branch 11 not taken.
|
65 | if (dominantColorCount.count > 0 && hw_random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color); |
| 5619 |
8/8✓ Branch 0 taken 415 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 385 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 582 times.
|
648 | } else if ((col == bgc) && (neighbors == 2) && !hw_random8(128)) { // Mutation |
| 5620 |
10/20✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
|
1 | SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 255)); |
| 5621 | } | ||
| 5622 | // else do nothing! | ||
| 5623 | } //x,y | ||
| 5624 | |||
| 5625 | // calculate CRC16 of leds | ||
| 5626 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | uint16_t crc = crc16((const unsigned char*)prevLeds, dataSize); |
| 5627 | // check if we had same CRC and reset if needed | ||
| 5628 | 5 | bool repetition = false; | |
| 5629 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
15 | for (int i=0; i<crcBufferLen && !repetition; i++) repetition = (crc == crcBuffer[i]); // (Ewowi) |
| 5630 | // same CRC would mean image did not change or was repeating itself | ||
| 5631 |
4/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | if (!repetition) SEGENV.step = strip().now; //if no repetition avoid reset |
| 5632 | // remember CRCs across frames | ||
| 5633 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | crcBuffer[SEGENV.aux0] = crc; |
| 5634 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | ++SEGENV.aux0 %= crcBufferLen; |
| 5635 | |||
| 5636 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | return FRAMETIME; |
| 5637 | } // mode_2Dgameoflife() | ||
| 5638 | static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!;!,!;!;2"; | ||
| 5639 | |||
| 5640 | |||
| 5641 | ///////////////////////// | ||
| 5642 | // 2D Hiphotic // | ||
| 5643 | ///////////////////////// | ||
| 5644 | 23 | uint16_t mode_2DHiphotic() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , Modified by: Andrew Tuline | |
| 5645 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5646 | |||
| 5647 | 18 | const int cols = SEG_W; | |
| 5648 | 18 | const int rows = SEG_H; | |
| 5649 | 18 | const uint32_t a = strip().now / ((SEGMENT.custom3>>1)+1); | |
| 5650 | |||
| 5651 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int x = 0; x < cols; x++) { |
| 5652 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int y = 0; y < rows; y++) { |
| 5653 |
2/4✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6761 times.
|
6761 | SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8_t(cos8_t(x * SEGMENT.speed/16 + a / 3) + sin8_t(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); |
| 5654 | } | ||
| 5655 | } | ||
| 5656 | |||
| 5657 | 18 | return FRAMETIME; | |
| 5658 | } // mode_2DHiphotic() | ||
| 5659 | static const char _data_FX_MODE_2DHIPHOTIC[] PROGMEM = "Hiphotic@X scale,Y scale,,,Speed;!;!;2"; | ||
| 5660 | |||
| 5661 | |||
| 5662 | ///////////////////////// | ||
| 5663 | // 2D Julia // | ||
| 5664 | ///////////////////////// | ||
| 5665 | // Sliders are: | ||
| 5666 | // intensity = Maximum number of iterations per pixel. | ||
| 5667 | // Custom1 = Location of X centerpoint | ||
| 5668 | // Custom2 = Location of Y centerpoint | ||
| 5669 | // Custom3 = Size of the area (small value = smaller area) | ||
| 5670 | typedef struct Julia { | ||
| 5671 | float xcen; | ||
| 5672 | float ycen; | ||
| 5673 | float xymag; | ||
| 5674 | } julia; | ||
| 5675 | |||
| 5676 | 23 | uint16_t mode_2DJulia(void) { // An animated Julia set by Andrew Tuline. | |
| 5677 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5678 | |||
| 5679 | 18 | const int cols = SEG_W; | |
| 5680 | 18 | const int rows = SEG_H; | |
| 5681 | |||
| 5682 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!SEGENV.allocateData(sizeof(julia))) return mode_static(); |
| 5683 | 18 | Julia* julias = reinterpret_cast<Julia*>(SEGENV.data); | |
| 5684 | |||
| 5685 | float reAl; | ||
| 5686 | float imAg; | ||
| 5687 | |||
| 5688 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { // Reset the center if we've just re-started this animation. |
| 5689 | 4 | julias->xcen = 0.; | |
| 5690 | 4 | julias->ycen = 0.; | |
| 5691 | 4 | julias->xymag = 1.0; | |
| 5692 | |||
| 5693 | 4 | SEGMENT.custom1 = 128; // Make sure the location widgets are centered to start. | |
| 5694 | 4 | SEGMENT.custom2 = 128; | |
| 5695 | 4 | SEGMENT.custom3 = 16; | |
| 5696 | 4 | SEGMENT.intensity = 24; | |
| 5697 | } | ||
| 5698 | |||
| 5699 | 18 | julias->xcen = julias->xcen + (float)(SEGMENT.custom1 - 128)/100000.f; | |
| 5700 | 18 | julias->ycen = julias->ycen + (float)(SEGMENT.custom2 - 128)/100000.f; | |
| 5701 | 18 | julias->xymag = julias->xymag + (float)((SEGMENT.custom3 - 16)<<3)/100000.f; // reduced resolution slider | |
| 5702 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (julias->xymag < 0.01f) julias->xymag = 0.01f; |
| 5703 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (julias->xymag > 1.0f) julias->xymag = 1.0f; |
| 5704 | |||
| 5705 | 18 | float xmin = julias->xcen - julias->xymag; | |
| 5706 | 18 | float xmax = julias->xcen + julias->xymag; | |
| 5707 | 18 | float ymin = julias->ycen - julias->xymag; | |
| 5708 | 18 | float ymax = julias->ycen + julias->xymag; | |
| 5709 | |||
| 5710 | // Whole set should be within -1.2,1.2 to -.8 to 1. | ||
| 5711 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | xmin = constrain(xmin, -1.2f, 1.2f); |
| 5712 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | xmax = constrain(xmax, -1.2f, 1.2f); |
| 5713 |
1/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
18 | ymin = constrain(ymin, -0.8f, 1.0f); |
| 5714 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | ymax = constrain(ymax, -0.8f, 1.0f); |
| 5715 | |||
| 5716 | float dx; // Delta x is mapped to the matrix size. | ||
| 5717 | float dy; // Delta y is mapped to the matrix size. | ||
| 5718 | |||
| 5719 | 18 | int maxIterations = 15; // How many iterations per pixel before we give up. Make it 8 bits to match our range of colours. | |
| 5720 | 18 | float maxCalc = 16.0; // How big is each calculation allowed to be before we give up. | |
| 5721 | |||
| 5722 | 18 | maxIterations = SEGMENT.intensity/2; | |
| 5723 | |||
| 5724 | |||
| 5725 | // Resize section on the fly for some animaton. | ||
| 5726 | 18 | reAl = -0.94299f; // PixelBlaze example | |
| 5727 | 18 | imAg = 0.3162f; | |
| 5728 | |||
| 5729 | 18 | reAl += (float)sin16_t(strip().now * 34) / 655340.f; | |
| 5730 | 18 | imAg += (float)sin16_t(strip().now * 26) / 655340.f; | |
| 5731 | |||
| 5732 | 18 | dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. | |
| 5733 | 18 | dy = (ymax - ymin) / (rows); | |
| 5734 | |||
| 5735 | // Start y | ||
| 5736 | 18 | float y = ymin; | |
| 5737 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 18 times.
|
241 | for (int j = 0; j < rows; j++) { |
| 5738 | |||
| 5739 | // Start x | ||
| 5740 | 223 | float x = xmin; | |
| 5741 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 223 times.
|
6984 | for (int i = 0; i < cols; i++) { |
| 5742 | |||
| 5743 | // Now we test, as we iterate z = z^2 + c does z tend towards infinity? | ||
| 5744 | 6761 | float a = x; | |
| 5745 | 6761 | float b = y; | |
| 5746 | 6761 | int iter = 0; | |
| 5747 | |||
| 5748 |
2/2✓ Branch 0 taken 52261 times.
✓ Branch 1 taken 1781 times.
|
54042 | while (iter < maxIterations) { // Here we determine whether or not we're out of bounds. |
| 5749 | 52261 | float aa = a * a; | |
| 5750 | 52261 | float bb = b * b; | |
| 5751 | 52261 | float len = aa + bb; | |
| 5752 |
2/2✓ Branch 0 taken 4980 times.
✓ Branch 1 taken 47281 times.
|
52261 | if (len > maxCalc) { // |z| = sqrt(a^2+b^2) OR z^2 = a^2+b^2 to save on having to perform a square root. |
| 5753 | 4980 | break; // Bail | |
| 5754 | } | ||
| 5755 | |||
| 5756 | // This operation corresponds to z -> z^2+c where z=a+ib c=(x,y). Remember to use 'foil'. | ||
| 5757 | 47281 | b = 2*a*b + imAg; | |
| 5758 | 47281 | a = aa - bb + reAl; | |
| 5759 | 47281 | iter++; | |
| 5760 | } // while | ||
| 5761 | |||
| 5762 | // We color each pixel based on how long it takes to get to infinity, or black if it never gets there. | ||
| 5763 |
2/2✓ Branch 0 taken 1781 times.
✓ Branch 1 taken 4980 times.
|
6761 | if (iter == maxIterations) { |
| 5764 | 1781 | SEGMENT.setPixelColorXY(i, j, 0); | |
| 5765 | } else { | ||
| 5766 |
2/4✓ Branch 0 taken 4980 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4980 times.
|
4980 | SEGMENT.setPixelColorXY(i, j, SEGMENT.color_from_palette(iter*255/maxIterations, false, PALETTE_SOLID_WRAP, 0)); |
| 5767 | } | ||
| 5768 | 6761 | x += dx; | |
| 5769 | } | ||
| 5770 | 223 | y += dy; | |
| 5771 | } | ||
| 5772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if(SEGMENT.check1) |
| 5773 | ✗ | SEGMENT.blur(100, true); | |
| 5774 | |||
| 5775 | 18 | return FRAMETIME; | |
| 5776 | } // mode_2DJulia() | ||
| 5777 | static const char _data_FX_MODE_2DJULIA[] PROGMEM = "Julia@,Max iterations per pixel,X center,Y center,Area size, Blur;!;!;2;ix=24,c1=128,c2=128,c3=16"; | ||
| 5778 | |||
| 5779 | |||
| 5780 | ////////////////////////////// | ||
| 5781 | // 2D Lissajous // | ||
| 5782 | ////////////////////////////// | ||
| 5783 | 23 | uint16_t mode_2DLissajous(void) { // By: Andrew Tuline | |
| 5784 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5785 | |||
| 5786 | 18 | const int cols = SEG_W; | |
| 5787 | 18 | const int rows = SEG_H; | |
| 5788 | |||
| 5789 | 18 | SEGMENT.fadeToBlackBy(SEGMENT.intensity); | |
| 5790 | 18 | uint_fast16_t phase = (strip().now * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed | |
| 5791 | |||
| 5792 | //for (int i=0; i < 4*(cols+rows); i ++) { | ||
| 5793 |
2/2✓ Branch 0 taken 4608 times.
✓ Branch 1 taken 18 times.
|
4626 | for (int i=0; i < 256; i ++) { |
| 5794 | //float xlocn = float(sin8_t(now/4+i*(SEGMENT.speed>>5))) / 255.0f; | ||
| 5795 | //float ylocn = float(cos8_t(now/4+i*2)) / 255.0f; | ||
| 5796 | 4608 | uint_fast8_t xlocn = sin8_t(phase/2 + (i*SEGMENT.speed)/32); | |
| 5797 | 4608 | uint_fast8_t ylocn = cos8_t(phase/2 + i*2); | |
| 5798 |
1/2✓ Branch 0 taken 4608 times.
✗ Branch 1 not taken.
|
4608 | xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding |
| 5799 |
1/2✓ Branch 0 taken 4608 times.
✗ Branch 1 not taken.
|
4608 | ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() |
| 5800 |
2/4✓ Branch 0 taken 4608 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4608 times.
|
4608 | SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip().now/100+i, false, PALETTE_SOLID_WRAP, 0)); |
| 5801 | } | ||
| 5802 | 18 | SEGMENT.blur(SEGMENT.custom1 >> (1 + SEGMENT.check1 * 3), SEGMENT.check1); | |
| 5803 | |||
| 5804 | 18 | return FRAMETIME; | |
| 5805 | } // mode_2DLissajous() | ||
| 5806 | static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,Blur,,Speed,Smear;!;!;2;c1=0"; | ||
| 5807 | |||
| 5808 | |||
| 5809 | /////////////////////// | ||
| 5810 | // 2D Matrix // | ||
| 5811 | /////////////////////// | ||
| 5812 | 23 | uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams. Adapted by Andrew Tuline & improved by merkisoft and ewowi, and softhack007. | |
| 5813 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5814 | |||
| 5815 | 18 | const int cols = SEG_W; | |
| 5816 | 18 | const int rows = SEG_H; | |
| 5817 | 10362 | const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; | |
| 5818 | |||
| 5819 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | unsigned dataSize = (SEGMENT.length()+7) >> 3; //1 bit per LED for trails |
| 5820 |
4/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
18 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 5821 | |||
| 5822 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 5823 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | SEGMENT.fill(BLACK); |
| 5824 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.step = 0; |
| 5825 | } | ||
| 5826 | |||
| 5827 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t fade = map(SEGMENT.custom1, 0, 255, 50, 250); // equals trail size |
| 5828 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t speed = (256-SEGMENT.speed) >> map(min(rows, 150), 0, 150, 0, 3); // slower speeds for small displays |
| 5829 | |||
| 5830 | uint32_t spawnColor; | ||
| 5831 | uint32_t trailColor; | ||
| 5832 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check1) { |
| 5833 | ✗ | spawnColor = SEGCOLOR(0); | |
| 5834 | ✗ | trailColor = SEGCOLOR(1); | |
| 5835 | } else { | ||
| 5836 | 18 | spawnColor = RGBW32(175,255,175,0); | |
| 5837 | 18 | trailColor = RGBW32(27,130,39,0); | |
| 5838 | } | ||
| 5839 | |||
| 5840 | 18 | bool emptyScreen = true; | |
| 5841 |
5/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 6 times.
|
18 | if (strip().now - SEGENV.step >= speed) { |
| 5842 |
3/6✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
|
12 | SEGENV.step = strip().now; |
| 5843 | // move pixels one row down. Falling codes keep color and add trail pixels; all others pixels are faded | ||
| 5844 | // TODO: it would be better to paint trails idividually instead of relying on fadeToBlackBy() | ||
| 5845 |
3/6✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
|
12 | SEGMENT.fadeToBlackBy(fade); |
| 5846 |
2/2✓ Branch 0 taken 166 times.
✓ Branch 1 taken 12 times.
|
178 | for (int row = rows-1; row >= 0; row--) { |
| 5847 |
2/2✓ Branch 0 taken 5162 times.
✓ Branch 1 taken 166 times.
|
5328 | for (int col = 0; col < cols; col++) { |
| 5848 | 5162 | unsigned index = XY(col, row) >> 3; | |
| 5849 | 5162 | unsigned bitNum = XY(col, row) & 0x07; | |
| 5850 |
4/6✓ Branch 0 taken 5162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5162 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 5151 times.
|
5162 | if (bitRead(SEGENV.data[index], bitNum)) { |
| 5851 |
3/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
|
11 | SEGMENT.setPixelColorXY(col, row, trailColor); // create trail |
| 5852 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | bitClear(SEGENV.data[index], bitNum); |
| 5853 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (row < rows-1) { |
| 5854 |
3/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
|
11 | SEGMENT.setPixelColorXY(col, row+1, spawnColor); |
| 5855 | 11 | index = XY(col, row+1) >> 3; | |
| 5856 | 11 | bitNum = XY(col, row+1) & 0x07; | |
| 5857 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | bitSet(SEGENV.data[index], bitNum); |
| 5858 | 11 | emptyScreen = false; | |
| 5859 | } | ||
| 5860 | } | ||
| 5861 | } | ||
| 5862 | } | ||
| 5863 | |||
| 5864 | // spawn new falling code | ||
| 5865 |
8/10✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 4 times.
|
12 | if (hw_random8() <= SEGMENT.intensity || emptyScreen) { |
| 5866 | 8 | uint8_t spawnX = hw_random8(cols); | |
| 5867 |
3/6✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | SEGMENT.setPixelColorXY(spawnX, 0, spawnColor); |
| 5868 | // update hint for next run | ||
| 5869 | 8 | unsigned index = XY(spawnX, 0) >> 3; | |
| 5870 | 8 | unsigned bitNum = XY(spawnX, 0) & 0x07; | |
| 5871 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | bitSet(SEGENV.data[index], bitNum); |
| 5872 | } | ||
| 5873 | } | ||
| 5874 | |||
| 5875 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 5876 | } // mode_2Dmatrix() | ||
| 5877 | static const char _data_FX_MODE_2DMATRIX[] PROGMEM = "Matrix@!,Spawning rate,Trail,,,Custom color;Spawn,Trail;;2"; | ||
| 5878 | |||
| 5879 | |||
| 5880 | ///////////////////////// | ||
| 5881 | // 2D Metaballs // | ||
| 5882 | ///////////////////////// | ||
| 5883 | 23 | uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have one of the dimensions be 2 or less. Adapted by Andrew Tuline. | |
| 5884 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5885 | |||
| 5886 | 18 | const int cols = SEG_W; | |
| 5887 | 18 | const int rows = SEG_H; | |
| 5888 | |||
| 5889 | 18 | float speed = 0.25f * (1+(SEGMENT.speed>>6)); | |
| 5890 | |||
| 5891 | // get some 2 random moving points | ||
| 5892 | 18 | int x2 = map(perlin8(strip().now * speed, 25355, 685), 0, 255, 0, cols-1); | |
| 5893 | 18 | int y2 = map(perlin8(strip().now * speed, 355, 11685), 0, 255, 0, rows-1); | |
| 5894 | |||
| 5895 | 18 | int x3 = map(perlin8(strip().now * speed, 55355, 6685), 0, 255, 0, cols-1); | |
| 5896 | 18 | int y3 = map(perlin8(strip().now * speed, 25355, 22685), 0, 255, 0, rows-1); | |
| 5897 | |||
| 5898 | // and one Lissajou function | ||
| 5899 | 18 | int x1 = beatsin8_t(23 * speed, 0, cols-1); | |
| 5900 | 18 | int y1 = beatsin8_t(28 * speed, 0, rows-1); | |
| 5901 | |||
| 5902 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 18 times.
|
241 | for (int y = 0; y < rows; y++) { |
| 5903 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 223 times.
|
6984 | for (int x = 0; x < cols; x++) { |
| 5904 | // calculate distances of the 3 points from actual pixel | ||
| 5905 | // and add them together with weightening | ||
| 5906 | 6761 | unsigned dx = abs(x - x1); | |
| 5907 | 6761 | unsigned dy = abs(y - y1); | |
| 5908 | 6761 | unsigned dist = 2 * sqrt32_bw((dx * dx) + (dy * dy)); | |
| 5909 | |||
| 5910 | 6761 | dx = abs(x - x2); | |
| 5911 | 6761 | dy = abs(y - y2); | |
| 5912 | 6761 | dist += sqrt32_bw((dx * dx) + (dy * dy)); | |
| 5913 | |||
| 5914 | 6761 | dx = abs(x - x3); | |
| 5915 | 6761 | dy = abs(y - y3); | |
| 5916 | 6761 | dist += sqrt32_bw((dx * dx) + (dy * dy)); | |
| 5917 | |||
| 5918 | // inverse result | ||
| 5919 |
1/2✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
|
6761 | int color = dist ? 1000 / dist : 255; |
| 5920 | |||
| 5921 | // map color between thresholds | ||
| 5922 |
3/4✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6656 times.
✓ Branch 3 taken 105 times.
|
6761 | if (color > 0 and color < 60) { |
| 5923 |
2/4✓ Branch 0 taken 6656 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6656 times.
|
6656 | SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(map(color * 9, 9, 531, 0, 255), false, PALETTE_SOLID_WRAP, 0)); |
| 5924 | } else { | ||
| 5925 |
2/4✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 105 times.
|
105 | SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(0, false, PALETTE_SOLID_WRAP, 0)); |
| 5926 | } | ||
| 5927 | // show the 3 points, too | ||
| 5928 | 6761 | SEGMENT.setPixelColorXY(x1, y1, WHITE); | |
| 5929 | 6761 | SEGMENT.setPixelColorXY(x2, y2, WHITE); | |
| 5930 | 6761 | SEGMENT.setPixelColorXY(x3, y3, WHITE); | |
| 5931 | } | ||
| 5932 | } | ||
| 5933 | |||
| 5934 | 18 | return FRAMETIME; | |
| 5935 | } // mode_2Dmetaballs() | ||
| 5936 | static const char _data_FX_MODE_2DMETABALLS[] PROGMEM = "Metaballs@!;;!;2"; | ||
| 5937 | |||
| 5938 | |||
| 5939 | ////////////////////// | ||
| 5940 | // 2D Noise // | ||
| 5941 | ////////////////////// | ||
| 5942 | 23 | uint16_t mode_2Dnoise(void) { // By Andrew Tuline | |
| 5943 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5944 | |||
| 5945 | 18 | const int cols = SEG_W; | |
| 5946 | 18 | const int rows = SEG_H; | |
| 5947 | |||
| 5948 | 18 | const unsigned scale = SEGMENT.intensity+2; | |
| 5949 | |||
| 5950 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 18 times.
|
241 | for (int y = 0; y < rows; y++) { |
| 5951 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 223 times.
|
6984 | for (int x = 0; x < cols; x++) { |
| 5952 | 6761 | uint8_t pixelHue8 = perlin8(x * scale, y * scale, strip().now / (16 - SEGMENT.speed/16)); | |
| 5953 | 6761 | SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, pixelHue8)); | |
| 5954 | } | ||
| 5955 | } | ||
| 5956 | |||
| 5957 | 18 | return FRAMETIME; | |
| 5958 | } // mode_2Dnoise() | ||
| 5959 | static const char _data_FX_MODE_2DNOISE[] PROGMEM = "Noise2D@!,Scale;;!;2"; | ||
| 5960 | |||
| 5961 | |||
| 5962 | ////////////////////////////// | ||
| 5963 | // 2D Plasma Ball // | ||
| 5964 | ////////////////////////////// | ||
| 5965 | 23 | uint16_t mode_2DPlasmaball(void) { // By: Stepko https://editor.soulmatelights.com/gallery/659-plasm-ball , Modified by: Andrew Tuline | |
| 5966 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 5967 | |||
| 5968 | 18 | const int cols = SEG_W; | |
| 5969 | 18 | const int rows = SEG_H; | |
| 5970 | |||
| 5971 | 18 | SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); | |
| 5972 | 18 | uint_fast32_t t = (strip().now * 8) / (256 - SEGMENT.speed); // optimized to avoid float | |
| 5973 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int i = 0; i < cols; i++) { |
| 5974 | 451 | unsigned thisVal = perlin8(i * 30, t, t); | |
| 5975 | 451 | unsigned thisMax = map(thisVal, 0, 255, 0, cols-1); | |
| 5976 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int j = 0; j < rows; j++) { |
| 5977 | 6761 | unsigned thisVal_ = perlin8(t, j * 30, t); | |
| 5978 | 6761 | unsigned thisMax_ = map(thisVal_, 0, 255, 0, rows-1); | |
| 5979 | 6761 | int x = (i + thisMax_ - cols / 2); | |
| 5980 | 6761 | int y = (j + thisMax - cols / 2); | |
| 5981 | 6761 | int cx = (i + thisMax_); | |
| 5982 | 6761 | int cy = (j + thisMax); | |
| 5983 | |||
| 5984 |
4/4✓ Branch 0 taken 3336 times.
✓ Branch 1 taken 3425 times.
✓ Branch 2 taken 2667 times.
✓ Branch 3 taken 669 times.
|
13522 | SEGMENT.addPixelColorXY(i, j, ((x - y > -2) && (x - y < 2)) || |
| 5985 |
6/6✓ Branch 0 taken 5899 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 5667 times.
✓ Branch 3 taken 232 times.
✓ Branch 4 taken 5667 times.
✓ Branch 5 taken 193 times.
|
6092 | ((cols - 1 - x - y) > -2 && (cols - 1 - x - y < 2)) || |
| 5986 | 5667 | (cols - cx == 0) || | |
| 5987 |
4/4✓ Branch 0 taken 5466 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 5264 times.
✓ Branch 3 taken 202 times.
|
5667 | (cols - 1 - cx == 0) || |
| 5988 | 5264 | ((rows - cy == 0) || | |
| 5989 |
2/2✓ Branch 0 taken 139 times.
✓ Branch 1 taken 5125 times.
|
6761 | (rows - 1 - cy == 0)) ? ColorFromPalette(SEGPALETTE, beat8(5), thisVal, LINEARBLEND) : CRGB::Black); |
| 5990 | } | ||
| 5991 | } | ||
| 5992 | 18 | SEGMENT.blur(SEGMENT.custom2>>5); | |
| 5993 | |||
| 5994 | 18 | return FRAMETIME; | |
| 5995 | } // mode_2DPlasmaball() | ||
| 5996 | static const char _data_FX_MODE_2DPLASMABALL[] PROGMEM = "Plasma Ball@Speed,,Fade,Blur;;!;2"; | ||
| 5997 | |||
| 5998 | |||
| 5999 | //////////////////////////////// | ||
| 6000 | // 2D Polar Lights // | ||
| 6001 | //////////////////////////////// | ||
| 6002 | |||
| 6003 | 23 | uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https://editor.soulmatelights.com/gallery/762-polar-lights , Modified by: Andrew Tuline & @dedehai (palette support) | |
| 6004 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6005 | |||
| 6006 | 18 | const int cols = SEG_W; | |
| 6007 | 18 | const int rows = SEG_H; | |
| 6008 | |||
| 6009 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 6010 | 4 | SEGMENT.fill(BLACK); | |
| 6011 | 4 | SEGENV.step = 0; | |
| 6012 | } | ||
| 6013 | |||
| 6014 | 18 | float adjustHeight = (float)map(rows, 8, 32, 28, 12); // maybe use mapf() ??? | |
| 6015 | 18 | unsigned adjScale = map(cols, 8, 64, 310, 63); | |
| 6016 | 18 | unsigned _scale = map(SEGMENT.intensity, 0, 255, 30, adjScale); | |
| 6017 | 18 | int _speed = map(SEGMENT.speed, 0, 255, 128, 16); | |
| 6018 | |||
| 6019 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int x = 0; x < cols; x++) { |
| 6020 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int y = 0; y < rows; y++) { |
| 6021 | 6761 | SEGENV.step++; | |
| 6022 |
2/2✓ Branch 0 taken 2347 times.
✓ Branch 1 taken 4414 times.
|
6761 | uint8_t palindex = qsub8(perlin8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), fabsf((float)rows / 2.0f - (float)y) * adjustHeight); |
| 6023 | 6761 | uint8_t palbrightness = palindex; | |
| 6024 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6761 times.
|
6761 | if(SEGMENT.check1) palindex = 255 - palindex; //flip palette |
| 6025 | 6761 | SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(palindex, false, false, 255, palbrightness)); | |
| 6026 | } | ||
| 6027 | } | ||
| 6028 | |||
| 6029 | 18 | return FRAMETIME; | |
| 6030 | } // mode_2DPolarLights() | ||
| 6031 | static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale,,,,Flip Palette;;!;2;pal=71"; | ||
| 6032 | |||
| 6033 | |||
| 6034 | ///////////////////////// | ||
| 6035 | // 2D Pulser // | ||
| 6036 | ///////////////////////// | ||
| 6037 | 23 | uint16_t mode_2DPulser(void) { // By: ldirko https://editor.soulmatelights.com/gallery/878-pulse-test , modifed by: Andrew Tuline | |
| 6038 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6039 | |||
| 6040 | 18 | const int cols = SEG_W; | |
| 6041 | 18 | const int rows = SEG_H; | |
| 6042 | |||
| 6043 | 18 | SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); | |
| 6044 | 18 | uint32_t a = strip().now / (18 - SEGMENT.speed / 16); | |
| 6045 | 18 | int x = (a / 14) % cols; | |
| 6046 | 18 | int y = map((sin8_t(a * 5) + sin8_t(a * 4) + sin8_t(a * 2)), 0, 765, rows-1, 0); | |
| 6047 | 18 | SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND)); | |
| 6048 | |||
| 6049 | 18 | SEGMENT.blur(SEGMENT.intensity>>4); | |
| 6050 | |||
| 6051 | 18 | return FRAMETIME; | |
| 6052 | } // mode_2DPulser() | ||
| 6053 | static const char _data_FX_MODE_2DPULSER[] PROGMEM = "Pulser@!,Blur;;!;2"; | ||
| 6054 | |||
| 6055 | |||
| 6056 | ///////////////////////// | ||
| 6057 | // 2D Sindots // | ||
| 6058 | ///////////////////////// | ||
| 6059 | 23 | uint16_t mode_2DSindots(void) { // By: ldirko https://editor.soulmatelights.com/gallery/597-sin-dots , modified by: Andrew Tuline | |
| 6060 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6061 | |||
| 6062 | 18 | const int cols = SEG_W; | |
| 6063 | 18 | const int rows = SEG_H; | |
| 6064 | |||
| 6065 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 6066 | 4 | SEGMENT.fill(BLACK); | |
| 6067 | } | ||
| 6068 | |||
| 6069 | 18 | SEGMENT.fadeToBlackBy((SEGMENT.custom1>>3) + (SEGMENT.check1 * 24)); | |
| 6070 | |||
| 6071 | 18 | byte t1 = strip().now / (257 - SEGMENT.speed); // 20; | |
| 6072 | 18 | byte t2 = sin8_t(t1) / 4 * 2; | |
| 6073 |
2/2✓ Branch 0 taken 234 times.
✓ Branch 1 taken 18 times.
|
252 | for (int i = 0; i < 13; i++) { |
| 6074 | 234 | int x = sin8_t(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! | |
| 6075 | 234 | int y = sin8_t(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! | |
| 6076 | 234 | SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, i * 255 / 13, 255, LINEARBLEND)); | |
| 6077 | } | ||
| 6078 | 18 | SEGMENT.blur(SEGMENT.custom2 >> (3 + SEGMENT.check1), SEGMENT.check1); | |
| 6079 | |||
| 6080 | 18 | return FRAMETIME; | |
| 6081 | } // mode_2DSindots() | ||
| 6082 | static const char _data_FX_MODE_2DSINDOTS[] PROGMEM = "Sindots@!,Dot distance,Fade rate,Blur,,Smear;;!;2;"; | ||
| 6083 | |||
| 6084 | |||
| 6085 | ////////////////////////////// | ||
| 6086 | // 2D Squared Swirl // | ||
| 6087 | ////////////////////////////// | ||
| 6088 | // custom3 affects the blur amount. | ||
| 6089 | 23 | uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://gist.github.com/kriegsman/368b316c55221134b160 | |
| 6090 | // Modifed by: Andrew Tuline | ||
| 6091 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6092 | |||
| 6093 | 18 | const int cols = SEG_W; | |
| 6094 | 18 | const int rows = SEG_H; | |
| 6095 | |||
| 6096 | 18 | const uint8_t kBorderWidth = 2; | |
| 6097 | |||
| 6098 | 18 | SEGMENT.fadeToBlackBy(1 + SEGMENT.intensity / 5); | |
| 6099 | 18 | SEGMENT.blur(SEGMENT.custom3>>1); | |
| 6100 | |||
| 6101 | // Use two out-of-sync sine waves | ||
| 6102 | 18 | int i = beatsin8_t(19, kBorderWidth, cols-kBorderWidth); | |
| 6103 | 18 | int j = beatsin8_t(22, kBorderWidth, cols-kBorderWidth); | |
| 6104 | 18 | int k = beatsin8_t(17, kBorderWidth, cols-kBorderWidth); | |
| 6105 | 18 | int m = beatsin8_t(18, kBorderWidth, rows-kBorderWidth); | |
| 6106 | 18 | int n = beatsin8_t(15, kBorderWidth, rows-kBorderWidth); | |
| 6107 | 18 | int p = beatsin8_t(20, kBorderWidth, rows-kBorderWidth); | |
| 6108 | |||
| 6109 | 18 | SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, strip().now/29, 255, LINEARBLEND)); | |
| 6110 | 18 | SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, strip().now/41, 255, LINEARBLEND)); | |
| 6111 | 18 | SEGMENT.addPixelColorXY(k, p, ColorFromPalette(SEGPALETTE, strip().now/73, 255, LINEARBLEND)); | |
| 6112 | |||
| 6113 | 18 | return FRAMETIME; | |
| 6114 | } // mode_2Dsquaredswirl() | ||
| 6115 | static const char _data_FX_MODE_2DSQUAREDSWIRL[] PROGMEM = "Squared Swirl@,Fade,,,Blur;;!;2"; | ||
| 6116 | |||
| 6117 | |||
| 6118 | ////////////////////////////// | ||
| 6119 | // 2D Sun Radiation // | ||
| 6120 | ////////////////////////////// | ||
| 6121 | 23 | uint16_t mode_2DSunradiation(void) { // By: ldirko https://editor.soulmatelights.com/gallery/599-sun-radiation , modified by: Andrew Tuline | |
| 6122 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6123 | |||
| 6124 | 18 | const int cols = SEG_W; | |
| 6125 | 18 | const int rows = SEG_H; | |
| 6126 | |||
| 6127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!SEGENV.allocateData(sizeof(byte)*(cols+2)*(rows+2))) return mode_static(); //allocation failed |
| 6128 | 18 | byte *bump = reinterpret_cast<byte*>(SEGENV.data); | |
| 6129 | |||
| 6130 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 6131 | 4 | SEGMENT.fill(BLACK); | |
| 6132 | } | ||
| 6133 | |||
| 6134 | 18 | unsigned long t = strip().now / 4; | |
| 6135 | 18 | unsigned index = 0; | |
| 6136 | 18 | uint8_t someVal = SEGMENT.speed/4; // Was 25. | |
| 6137 |
2/2✓ Branch 0 taken 259 times.
✓ Branch 1 taken 18 times.
|
277 | for (int j = 0; j < (rows + 2); j++) { |
| 6138 |
2/2✓ Branch 0 taken 8181 times.
✓ Branch 1 taken 259 times.
|
8440 | for (int i = 0; i < (cols + 2); i++) { |
| 6139 | //byte col = (inoise8_raw(i * someVal, j * someVal, t)) / 2; | ||
| 6140 | 8181 | byte col = ((int16_t)perlin8(i * someVal, j * someVal, t) - 0x7F) / 3; | |
| 6141 | 8181 | bump[index++] = col; | |
| 6142 | } | ||
| 6143 | } | ||
| 6144 | |||
| 6145 | 18 | int yindex = cols + 3; | |
| 6146 | 18 | int vly = -(rows / 2 + 1); | |
| 6147 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 18 times.
|
241 | for (int y = 0; y < rows; y++) { |
| 6148 | 223 | ++vly; | |
| 6149 | 223 | int vlx = -(cols / 2 + 1); | |
| 6150 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 223 times.
|
6984 | for (int x = 0; x < cols; x++) { |
| 6151 | 6761 | ++vlx; | |
| 6152 | 6761 | int nx = bump[x + yindex + 1] - bump[x + yindex - 1]; | |
| 6153 | 6761 | int ny = bump[x + yindex + (cols + 2)] - bump[x + yindex - (cols + 2)]; | |
| 6154 |
2/2✓ Branch 0 taken 3426 times.
✓ Branch 1 taken 3335 times.
|
6761 | unsigned difx = abs8(vlx * 7 - nx); |
| 6155 |
2/2✓ Branch 0 taken 3533 times.
✓ Branch 1 taken 3228 times.
|
6761 | unsigned dify = abs8(vly * 7 - ny); |
| 6156 | 6761 | int temp = difx * difx + dify * dify; | |
| 6157 | 6761 | int col = 255 - temp / 8; //8 its a size of effect | |
| 6158 |
2/2✓ Branch 0 taken 4970 times.
✓ Branch 1 taken 1791 times.
|
6761 | if (col < 0) col = 0; |
| 6159 | 6761 | SEGMENT.setPixelColorXY(x, y, HeatColor(col / (3.0f-(float)(SEGMENT.intensity)/128.f))); | |
| 6160 | } | ||
| 6161 | 223 | yindex += (cols + 2); | |
| 6162 | } | ||
| 6163 | |||
| 6164 | 18 | return FRAMETIME; | |
| 6165 | } // mode_2DSunradiation() | ||
| 6166 | static const char _data_FX_MODE_2DSUNRADIATION[] PROGMEM = "Sun Radiation@Variance,Brightness;;;2"; | ||
| 6167 | |||
| 6168 | |||
| 6169 | ///////////////////////// | ||
| 6170 | // 2D Tartan // | ||
| 6171 | ///////////////////////// | ||
| 6172 | 23 | uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.soulmatelights.com/gallery/3-tartan , Modified by: Andrew Tuline | |
| 6173 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6174 | |||
| 6175 | 18 | const int cols = SEG_W; | |
| 6176 | 18 | const int rows = SEG_H; | |
| 6177 | |||
| 6178 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 6179 | 4 | SEGMENT.fill(BLACK); | |
| 6180 | } | ||
| 6181 | |||
| 6182 | uint8_t hue, bri; | ||
| 6183 | size_t intensity; | ||
| 6184 | 18 | int offsetX = beatsin16_t(3, -360, 360); | |
| 6185 | 18 | int offsetY = beatsin16_t(2, -360, 360); | |
| 6186 | 18 | int sharpness = SEGMENT.custom3 / 8; // 0-3 | |
| 6187 | |||
| 6188 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int x = 0; x < cols; x++) { |
| 6189 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int y = 0; y < rows; y++) { |
| 6190 | 6761 | hue = x * beatsin16_t(10, 1, 10) + offsetY; | |
| 6191 | 6761 | intensity = bri = sin8_t(x * SEGMENT.speed/2 + offsetX); | |
| 6192 |
2/2✓ Branch 0 taken 11474 times.
✓ Branch 1 taken 6761 times.
|
18235 | for (int i=0; i<sharpness; i++) intensity *= bri; |
| 6193 | 6761 | intensity >>= 8*sharpness; | |
| 6194 | 6761 | SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); | |
| 6195 | 6761 | hue = y * 3 + offsetX; | |
| 6196 | 6761 | intensity = bri = sin8_t(y * SEGMENT.intensity/2 + offsetY); | |
| 6197 |
2/2✓ Branch 0 taken 11474 times.
✓ Branch 1 taken 6761 times.
|
18235 | for (int i=0; i<sharpness; i++) intensity *= bri; |
| 6198 | 6761 | intensity >>= 8*sharpness; | |
| 6199 | 6761 | SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); | |
| 6200 | } | ||
| 6201 | } | ||
| 6202 | |||
| 6203 | 18 | return FRAMETIME; | |
| 6204 | } // mode_2DTartan() | ||
| 6205 | static const char _data_FX_MODE_2DTARTAN[] PROGMEM = "Tartan@X scale,Y scale,,,Sharpness;;!;2"; | ||
| 6206 | |||
| 6207 | |||
| 6208 | ///////////////////////// | ||
| 6209 | // 2D spaceships // | ||
| 6210 | ///////////////////////// | ||
| 6211 | 23 | uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [https://editor.soulmatelights.com/gallery/639-space-ships], adapted by Blaz Kristan (AKA blazoncek) | |
| 6212 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6213 | |||
| 6214 | 18 | const int cols = SEG_W; | |
| 6215 | 18 | const int rows = SEG_H; | |
| 6216 | |||
| 6217 | 18 | uint32_t tb = strip().now >> 12; // every ~4s | |
| 6218 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
|
18 | if (tb > SEGENV.step) { |
| 6219 | 5 | int dir = ++SEGENV.aux0; | |
| 6220 | 5 | dir += (int)hw_random8(3)-1; | |
| 6221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (dir > 7) SEGENV.aux0 = 0; |
| 6222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | else if (dir < 0) SEGENV.aux0 = 7; |
| 6223 | 5 | else SEGENV.aux0 = dir; | |
| 6224 | 5 | SEGENV.step = tb + hw_random8(4); | |
| 6225 | } | ||
| 6226 | |||
| 6227 | 18 | SEGMENT.fadeToBlackBy(map(SEGMENT.speed, 0, 255, 248, 16)); | |
| 6228 | 18 | SEGMENT.move(SEGENV.aux0, 1); | |
| 6229 | |||
| 6230 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 18 times.
|
162 | for (size_t i = 0; i < 8; i++) { |
| 6231 | 144 | int x = beatsin8_t(12 + i, 2, cols - 3); | |
| 6232 | 144 | int y = beatsin8_t(15 + i, 2, rows - 3); | |
| 6233 | 144 | uint32_t color = ColorFromPalette(SEGPALETTE, beatsin8_t(12 + i, 0, 255), 255); | |
| 6234 | 144 | SEGMENT.addPixelColorXY(x, y, color); | |
| 6235 |
3/4✓ Branch 0 taken 40 times.
✓ Branch 1 taken 104 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
|
144 | if (cols > 24 || rows > 24) { |
| 6236 | 104 | SEGMENT.addPixelColorXY(x+1, y, color); | |
| 6237 | 104 | SEGMENT.addPixelColorXY(x-1, y, color); | |
| 6238 | 104 | SEGMENT.addPixelColorXY(x, y+1, color); | |
| 6239 | 104 | SEGMENT.addPixelColorXY(x, y-1, color); | |
| 6240 | } | ||
| 6241 | } | ||
| 6242 | 18 | SEGMENT.blur(SEGMENT.intensity >> 3, SEGMENT.check1); | |
| 6243 | |||
| 6244 | 18 | return FRAMETIME; | |
| 6245 | } | ||
| 6246 | static const char _data_FX_MODE_2DSPACESHIPS[] PROGMEM = "Spaceships@!,Blur,,,,Smear;;!;2"; | ||
| 6247 | |||
| 6248 | |||
| 6249 | ///////////////////////// | ||
| 6250 | // 2D Crazy Bees // | ||
| 6251 | ///////////////////////// | ||
| 6252 | //// Crazy bees by stepko (c)12.02.21 [https://editor.soulmatelights.com/gallery/651-crazy-bees], adapted by Blaz Kristan (AKA blazoncek), improved by @dedehai | ||
| 6253 | #define MAX_BEES 5 | ||
| 6254 | 23 | uint16_t mode_2Dcrazybees(void) { | |
| 6255 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6256 | |||
| 6257 | 18 | const int cols = SEG_W; | |
| 6258 | 18 | const int rows = SEG_H; | |
| 6259 | |||
| 6260 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | byte n = MIN(MAX_BEES, (rows * cols) / 256 + 1); |
| 6261 | |||
| 6262 | typedef struct Bee { | ||
| 6263 | uint8_t posX, posY, aimX, aimY, hue; | ||
| 6264 | int8_t deltaX, deltaY, signX, signY, error; | ||
| 6265 | 14 | void aimed(uint16_t w, uint16_t h) { | |
| 6266 | //random16_set_seed(millis()); | ||
| 6267 | 14 | aimX = random8(0, w); | |
| 6268 | 14 | aimY = random8(0, h); | |
| 6269 | 14 | hue = random8(); | |
| 6270 | 14 | deltaX = abs(aimX - posX); | |
| 6271 | 14 | deltaY = abs(aimY - posY); | |
| 6272 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
|
14 | signX = posX < aimX ? 1 : -1; |
| 6273 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
14 | signY = posY < aimY ? 1 : -1; |
| 6274 | 14 | error = deltaX - deltaY; | |
| 6275 | 14 | }; | |
| 6276 | } bee_t; | ||
| 6277 | |||
| 6278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!SEGENV.allocateData(sizeof(bee_t)*MAX_BEES)) return mode_static(); //allocation failed |
| 6279 | 18 | bee_t *bee = reinterpret_cast<bee_t*>(SEGENV.data); | |
| 6280 | |||
| 6281 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 6282 | 4 | random16_set_seed(strip().now); | |
| 6283 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
|
14 | for (size_t i = 0; i < n; i++) { |
| 6284 | 10 | bee[i].posX = random8(0, cols); | |
| 6285 | 10 | bee[i].posY = random8(0, rows); | |
| 6286 | 10 | bee[i].aimed(cols, rows); | |
| 6287 | } | ||
| 6288 | } | ||
| 6289 | |||
| 6290 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | if (strip().now > SEGENV.step) { |
| 6291 | 15 | SEGENV.step = strip().now + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1)); | |
| 6292 | 15 | SEGMENT.fadeToBlackBy(32 + ((SEGMENT.check1*SEGMENT.intensity) / 25)); | |
| 6293 | 15 | SEGMENT.blur(SEGMENT.intensity / (2 + SEGMENT.check1 * 9), SEGMENT.check1); | |
| 6294 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 15 times.
|
50 | for (size_t i = 0; i < n; i++) { |
| 6295 | 35 | uint32_t flowerCcolor = SEGMENT.color_from_palette(bee[i].hue, false, true, 255); | |
| 6296 | 35 | SEGMENT.addPixelColorXY(bee[i].aimX + 1, bee[i].aimY, flowerCcolor); | |
| 6297 | 35 | SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY + 1, flowerCcolor); | |
| 6298 | 35 | SEGMENT.addPixelColorXY(bee[i].aimX - 1, bee[i].aimY, flowerCcolor); | |
| 6299 | 35 | SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY - 1, flowerCcolor); | |
| 6300 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4 times.
|
35 | if (bee[i].posX != bee[i].aimX || bee[i].posY != bee[i].aimY) { |
| 6301 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
62 | SEGMENT.setPixelColorXY(bee[i].posX, bee[i].posY, CRGB(CHSV(bee[i].hue, 60, 255))); |
| 6302 | 31 | int error2 = bee[i].error * 2; | |
| 6303 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 4 times.
|
31 | if (error2 > -bee[i].deltaY) { |
| 6304 | 27 | bee[i].error -= bee[i].deltaY; | |
| 6305 | 27 | bee[i].posX += bee[i].signX; | |
| 6306 | } | ||
| 6307 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16 times.
|
31 | if (error2 < bee[i].deltaX) { |
| 6308 | 15 | bee[i].error += bee[i].deltaX; | |
| 6309 | 15 | bee[i].posY += bee[i].signY; | |
| 6310 | } | ||
| 6311 | 31 | } else { | |
| 6312 | 4 | bee[i].aimed(cols, rows); | |
| 6313 | } | ||
| 6314 | } | ||
| 6315 | } | ||
| 6316 | 18 | return FRAMETIME; | |
| 6317 | } | ||
| 6318 | static const char _data_FX_MODE_2DCRAZYBEES[] PROGMEM = "Crazy Bees@!,Blur,,,,Smear;;!;2;pal=11,ix=0"; | ||
| 6319 | #undef MAX_BEES | ||
| 6320 | |||
| 6321 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 6322 | ///////////////////////// | ||
| 6323 | // 2D Ghost Rider // | ||
| 6324 | ///////////////////////// | ||
| 6325 | //// Ghost Rider by stepko (c)2021 [https://editor.soulmatelights.com/gallery/716-ghost-rider], adapted by Blaz Kristan (AKA blazoncek) | ||
| 6326 | #define LIGHTERS_AM 64 // max lighters (adequate for 32x32 matrix) | ||
| 6327 | 23 | uint16_t mode_2Dghostrider(void) { | |
| 6328 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6329 | |||
| 6330 | 18 | const int cols = SEG_W; | |
| 6331 | 18 | const int rows = SEG_H; | |
| 6332 | |||
| 6333 | typedef struct Lighter { | ||
| 6334 | int16_t gPosX; | ||
| 6335 | int16_t gPosY; | ||
| 6336 | uint16_t gAngle; | ||
| 6337 | int8_t angleSpeed; | ||
| 6338 | uint16_t lightersPosX[LIGHTERS_AM]; | ||
| 6339 | uint16_t lightersPosY[LIGHTERS_AM]; | ||
| 6340 | uint16_t Angle[LIGHTERS_AM]; | ||
| 6341 | uint16_t time[LIGHTERS_AM]; | ||
| 6342 | bool reg[LIGHTERS_AM]; | ||
| 6343 | int8_t Vspeed; | ||
| 6344 | } lighter_t; | ||
| 6345 | |||
| 6346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!SEGENV.allocateData(sizeof(lighter_t))) return mode_static(); //allocation failed |
| 6347 | 18 | lighter_t *lighter = reinterpret_cast<lighter_t*>(SEGENV.data); | |
| 6348 | |||
| 6349 | 18 | const size_t maxLighters = min(cols + rows, LIGHTERS_AM); | |
| 6350 | |||
| 6351 |
5/6✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { |
| 6352 | 4 | SEGENV.aux0 = cols; | |
| 6353 | 4 | SEGENV.aux1 = rows; | |
| 6354 | 4 | lighter->angleSpeed = hw_random8(0,20) - 10; | |
| 6355 | 4 | lighter->gAngle = hw_random16(); | |
| 6356 | 4 | lighter->Vspeed = 5; | |
| 6357 | 4 | lighter->gPosX = (cols/2) * 10; | |
| 6358 | 4 | lighter->gPosY = (rows/2) * 10; | |
| 6359 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 4 times.
|
158 | for (size_t i = 0; i < maxLighters; i++) { |
| 6360 | 154 | lighter->lightersPosX[i] = lighter->gPosX; | |
| 6361 | 154 | lighter->lightersPosY[i] = lighter->gPosY + i; | |
| 6362 | 154 | lighter->time[i] = i * 2; | |
| 6363 | 154 | lighter->reg[i] = false; | |
| 6364 | } | ||
| 6365 | } | ||
| 6366 | |||
| 6367 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | if (strip().now > SEGENV.step) { |
| 6368 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | SEGENV.step = strip().now + 1024 / (cols+rows); |
| 6369 | |||
| 6370 |
5/10✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
|
15 | SEGMENT.fadeToBlackBy((SEGMENT.speed>>2)+64); |
| 6371 | |||
| 6372 | 15 | CRGB color = CRGB::White; | |
| 6373 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | SEGMENT.wu_pixel(lighter->gPosX * 256 / 10, lighter->gPosY * 256 / 10, color); |
| 6374 | |||
| 6375 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | lighter->gPosX += lighter->Vspeed * sin_t(radians(lighter->gAngle)); |
| 6376 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | lighter->gPosY += lighter->Vspeed * cos_t(radians(lighter->gAngle)); |
| 6377 | 15 | lighter->gAngle += lighter->angleSpeed; | |
| 6378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (lighter->gPosX < 0) lighter->gPosX = (cols - 1) * 10; |
| 6379 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (lighter->gPosX > (cols - 1) * 10) lighter->gPosX = 0; |
| 6380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (lighter->gPosY < 0) lighter->gPosY = (rows - 1) * 10; |
| 6381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (lighter->gPosY > (rows - 1) * 10) lighter->gPosY = 0; |
| 6382 |
2/2✓ Branch 0 taken 644 times.
✓ Branch 1 taken 15 times.
|
659 | for (size_t i = 0; i < maxLighters; i++) { |
| 6383 | 644 | lighter->time[i] += hw_random8(5, 20); | |
| 6384 |
1/2✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
|
644 | if (lighter->time[i] >= 255 || |
| 6385 |
1/2✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
|
644 | (lighter->lightersPosX[i] <= 0) || |
| 6386 |
1/2✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
|
644 | (lighter->lightersPosX[i] >= (cols - 1) * 10) || |
| 6387 |
1/2✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
|
644 | (lighter->lightersPosY[i] <= 0) || |
| 6388 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
|
644 | (lighter->lightersPosY[i] >= (rows - 1) * 10)) { |
| 6389 | ✗ | lighter->reg[i] = true; | |
| 6390 | } | ||
| 6391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 644 times.
|
644 | if (lighter->reg[i]) { |
| 6392 | ✗ | lighter->lightersPosY[i] = lighter->gPosY; | |
| 6393 | ✗ | lighter->lightersPosX[i] = lighter->gPosX; | |
| 6394 | ✗ | lighter->Angle[i] = lighter->gAngle + ((int)hw_random8(20) - 10); | |
| 6395 | ✗ | lighter->time[i] = 0; | |
| 6396 | ✗ | lighter->reg[i] = false; | |
| 6397 | } else { | ||
| 6398 |
1/2✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
|
644 | lighter->lightersPosX[i] += -7 * sin_t(radians(lighter->Angle[i])); |
| 6399 |
1/2✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
|
644 | lighter->lightersPosY[i] += -7 * cos_t(radians(lighter->Angle[i])); |
| 6400 | } | ||
| 6401 |
4/8✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 644 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 644 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 644 times.
✗ Branch 7 not taken.
|
644 | SEGMENT.wu_pixel(lighter->lightersPosX[i] * 256 / 10, lighter->lightersPosY[i] * 256 / 10, ColorFromPalette(SEGPALETTE, (256 - lighter->time[i]))); |
| 6402 | } | ||
| 6403 |
5/10✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
|
15 | SEGMENT.blur(SEGMENT.intensity>>3); |
| 6404 | } | ||
| 6405 | |||
| 6406 | 18 | return FRAMETIME; | |
| 6407 | } | ||
| 6408 | static const char _data_FX_MODE_2DGHOSTRIDER[] PROGMEM = "Ghost Rider@Fade rate,Blur;;!;2"; | ||
| 6409 | #undef LIGHTERS_AM | ||
| 6410 | |||
| 6411 | //////////////////////////// | ||
| 6412 | // 2D Floating Blobs // | ||
| 6413 | //////////////////////////// | ||
| 6414 | //// Floating Blobs by stepko (c)2021 [https://editor.soulmatelights.com/gallery/573-blobs], adapted by Blaz Kristan (AKA blazoncek) | ||
| 6415 | #define MAX_BLOBS 8 | ||
| 6416 | 23 | uint16_t mode_2Dfloatingblobs(void) { | |
| 6417 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6418 | |||
| 6419 | 18 | const int cols = SEG_W; | |
| 6420 | 18 | const int rows = SEG_H; | |
| 6421 | |||
| 6422 | typedef struct Blob { | ||
| 6423 | float x[MAX_BLOBS], y[MAX_BLOBS]; | ||
| 6424 | float sX[MAX_BLOBS], sY[MAX_BLOBS]; // speed | ||
| 6425 | float r[MAX_BLOBS]; | ||
| 6426 | bool grow[MAX_BLOBS]; | ||
| 6427 | byte color[MAX_BLOBS]; | ||
| 6428 | } blob_t; | ||
| 6429 | |||
| 6430 | 18 | size_t Amount = (SEGMENT.intensity>>5) + 1; // NOTE: be sure to update MAX_BLOBS if you change this | |
| 6431 | |||
| 6432 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!SEGENV.allocateData(sizeof(blob_t))) return mode_static(); //allocation failed |
| 6433 | 18 | blob_t *blob = reinterpret_cast<blob_t*>(SEGENV.data); | |
| 6434 | |||
| 6435 |
5/6✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { |
| 6436 | 4 | SEGENV.aux0 = cols; // re-initialise if virtual size changes | |
| 6437 | 4 | SEGENV.aux1 = rows; | |
| 6438 | //SEGMENT.fill(BLACK); | ||
| 6439 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
|
36 | for (size_t i = 0; i < MAX_BLOBS; i++) { |
| 6440 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
|
32 | blob->r[i] = hw_random8(1, cols>8 ? (cols/4) : 2); |
| 6441 | 32 | blob->sX[i] = (float) hw_random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x | |
| 6442 | 32 | blob->sY[i] = (float) hw_random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y | |
| 6443 | 32 | blob->x[i] = hw_random8(0, cols-1); | |
| 6444 | 32 | blob->y[i] = hw_random8(0, rows-1); | |
| 6445 | 32 | blob->color[i] = hw_random8(); | |
| 6446 | 32 | blob->grow[i] = (blob->r[i] < 1.f); | |
| 6447 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (blob->sX[i] == 0) blob->sX[i] = 1; |
| 6448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (blob->sY[i] == 0) blob->sY[i] = 1; |
| 6449 | } | ||
| 6450 | } | ||
| 6451 | |||
| 6452 | 18 | SEGMENT.fadeToBlackBy((SEGMENT.custom2>>3)+1); | |
| 6453 | |||
| 6454 | // Bounce balls around | ||
| 6455 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 18 times.
|
104 | for (size_t i = 0; i < Amount; i++) { |
| 6456 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 67 times.
|
105 | if (SEGENV.step < strip().now) blob->color[i] = add8(blob->color[i], 4); // slowly change color |
| 6457 | // change radius if needed | ||
| 6458 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 54 times.
|
86 | if (blob->grow[i]) { |
| 6459 | // enlarge radius until it is >= 4 | ||
| 6460 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 3 times.
|
32 | blob->r[i] += (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f; |
| 6461 |
4/4✓ Branch 0 taken 20 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 28 times.
|
32 | if (blob->r[i] >= MIN(cols/4.f,2.f)) { |
| 6462 | 4 | blob->grow[i] = false; | |
| 6463 | } | ||
| 6464 | } else { | ||
| 6465 | // reduce radius until it is < 1 | ||
| 6466 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6 times.
|
54 | blob->r[i] -= (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f; |
| 6467 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 43 times.
|
54 | if (blob->r[i] < 1.f) { |
| 6468 | 11 | blob->grow[i] = true; | |
| 6469 | } | ||
| 6470 | } | ||
| 6471 | 86 | uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0); | |
| 6472 |
2/2✓ Branch 0 taken 67 times.
✓ Branch 1 taken 19 times.
|
86 | if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c); |
| 6473 | 19 | else SEGMENT.setPixelColorXY((int)roundf(blob->x[i]), (int)roundf(blob->y[i]), c); | |
| 6474 | // move x | ||
| 6475 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 48 times.
|
86 | if (blob->x[i] + blob->r[i] >= cols - 1) blob->x[i] += (blob->sX[i] * ((cols - 1 - blob->x[i]) / blob->r[i] + 0.005f)); |
| 6476 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 38 times.
|
48 | else if (blob->x[i] - blob->r[i] <= 0) blob->x[i] += (blob->sX[i] * (blob->x[i] / blob->r[i] + 0.005f)); |
| 6477 | 38 | else blob->x[i] += blob->sX[i]; | |
| 6478 | // move y | ||
| 6479 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 42 times.
|
86 | if (blob->y[i] + blob->r[i] >= rows - 1) blob->y[i] += (blob->sY[i] * ((rows - 1 - blob->y[i]) / blob->r[i] + 0.005f)); |
| 6480 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 22 times.
|
42 | else if (blob->y[i] - blob->r[i] <= 0) blob->y[i] += (blob->sY[i] * (blob->y[i] / blob->r[i] + 0.005f)); |
| 6481 | 22 | else blob->y[i] += blob->sY[i]; | |
| 6482 | // bounce x | ||
| 6483 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 84 times.
|
86 | if (blob->x[i] < 0.01f) { |
| 6484 | 2 | blob->sX[i] = (float)hw_random8(3, cols) / (256 - SEGMENT.speed); | |
| 6485 | 2 | blob->x[i] = 0.01f; | |
| 6486 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 76 times.
|
84 | } else if (blob->x[i] > (float)cols - 1.01f) { |
| 6487 | 8 | blob->sX[i] = (float)hw_random8(3, cols) / (256 - SEGMENT.speed); | |
| 6488 | 8 | blob->sX[i] = -blob->sX[i]; | |
| 6489 | 8 | blob->x[i] = (float)cols - 1.01f; | |
| 6490 | } | ||
| 6491 | // bounce y | ||
| 6492 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 82 times.
|
86 | if (blob->y[i] < 0.01f) { |
| 6493 | 4 | blob->sY[i] = (float)hw_random8(3, rows) / (256 - SEGMENT.speed); | |
| 6494 | 4 | blob->y[i] = 0.01f; | |
| 6495 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 75 times.
|
82 | } else if (blob->y[i] > (float)rows - 1.01f) { |
| 6496 | 7 | blob->sY[i] = (float)hw_random8(3, rows) / (256 - SEGMENT.speed); | |
| 6497 | 7 | blob->sY[i] = -blob->sY[i]; | |
| 6498 | 7 | blob->y[i] = (float)rows - 1.01f; | |
| 6499 | } | ||
| 6500 | } | ||
| 6501 | 18 | SEGMENT.blur(SEGMENT.custom1>>2); | |
| 6502 | |||
| 6503 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.step < strip().now) SEGENV.step = strip().now + 2000; // change colors every 2 seconds |
| 6504 | |||
| 6505 | 18 | return FRAMETIME; | |
| 6506 | } | ||
| 6507 | static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur,Trail;!;!;2;c1=8"; | ||
| 6508 | #undef MAX_BLOBS | ||
| 6509 | #endif // WLED_PS_DONT_REPLACE_FX | ||
| 6510 | |||
| 6511 | //////////////////////////// | ||
| 6512 | // 2D Scrolling text // | ||
| 6513 | //////////////////////////// | ||
| 6514 | 147 | uint16_t mode_2Dscrollingtext(void) { | |
| 6515 |
9/14✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 142 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 142 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 142 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 142 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
147 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6516 | // FPP: the global localTime is only set when the library loads, so #TIME | ||
| 6517 | // and the rest showed fppd's start time. Read the clock each frame. | ||
| 6518 | 142 | const time_t localTime = time(nullptr); | |
| 6519 | |||
| 6520 | 142 | const int cols = SEG_W; | |
| 6521 | 142 | const int rows = SEG_H; | |
| 6522 | |||
| 6523 | unsigned letterWidth, rotLW; | ||
| 6524 | unsigned letterHeight, rotLH; | ||
| 6525 |
5/9✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 134 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
|
142 | switch (map(SEGMENT.custom2, 0, 255, 1, 5)) { |
| 6526 | 4 | default: | |
| 6527 | 4 | case 1: letterWidth = 4; letterHeight = 6; break; | |
| 6528 | ✗ | case 2: letterWidth = 5; letterHeight = 8; break; | |
| 6529 | 134 | case 3: letterWidth = 6; letterHeight = 8; break; | |
| 6530 | ✗ | case 4: letterWidth = 7; letterHeight = 9; break; | |
| 6531 | 4 | case 5: letterWidth = 5; letterHeight = 12; break; | |
| 6532 | } | ||
| 6533 | // letters are rotated | ||
| 6534 |
3/6✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 142 times.
|
142 | if (((SEGMENT.custom3+1)>>3) % 2) { |
| 6535 | ✗ | rotLH = letterWidth; | |
| 6536 | ✗ | rotLW = letterHeight; | |
| 6537 | } else { | ||
| 6538 | 142 | rotLW = letterWidth; | |
| 6539 | 142 | rotLH = letterHeight; | |
| 6540 | } | ||
| 6541 | |||
| 6542 | // FPP: the segment name is the effect's Text argument, which is not held to | ||
| 6543 | // WLED_MAX_SEGNAME_LEN, so the buffer is sized from it rather than fixed. | ||
| 6544 |
6/10✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 124 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 124 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 124 times.
✗ Branch 9 not taken.
|
142 | const size_t nameLen = SEGMENT.name ? strlen(SEGMENT.name) : 0; |
| 6545 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
284 | std::vector<char> textBuf(std::max(nameLen, (size_t)WLED_MAX_SEGNAME_LEN) + 1, '\0'); |
| 6546 | 142 | char *text = textBuf.data(); | |
| 6547 |
15/26✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 124 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 16554 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16554 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 16554 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 16554 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 16554 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 16554 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 16554 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 16554 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 16554 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 16554 times.
✓ Branch 25 taken 124 times.
|
16696 | if (SEGMENT.name) for (size_t i=0,j=0; i<nameLen; i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i]; |
| 6548 | 142 | const bool zero = strchr(text, '0') != nullptr; | |
| 6549 | |||
| 6550 | char sec[5]; | ||
| 6551 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | int AmPmHour = hour(localTime); |
| 6552 | 142 | bool isitAM = true; | |
| 6553 | if (useAMPM) { | ||
| 6554 | if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; } | ||
| 6555 | if (AmPmHour == 0) { AmPmHour = 12; } | ||
| 6556 | sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM")); | ||
| 6557 | } else { | ||
| 6558 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | sprintf_P(sec, PSTR(":%02d"), second(localTime)); |
| 6559 | } | ||
| 6560 | |||
| 6561 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 124 times.
|
142 | if (!strlen(text)) { // fallback if empty segment name: display date and time |
| 6562 |
5/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
|
18 | sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec); |
| 6563 | } else { | ||
| 6564 |
4/4✓ Branch 0 taken 62 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 4030 times.
✓ Branch 3 taken 62 times.
|
4154 | if (text[0] == '#') for (auto &c : textBuf) c = std::toupper(c); |
| 6565 |
1/10✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
124 | if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime)); |
| 6566 |
1/8✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime)); |
| 6567 |
1/8✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime)); |
| 6568 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec); |
| 6569 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime)); |
| 6570 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf (text, zero? ("%02d") : ("%d"), AmPmHour); |
| 6571 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf (text, zero? ("%02d") : ("%d"), minute(localTime)); |
| 6572 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#SS"),3)) sprintf (text, ("%02d") , second(localTime)); |
| 6573 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#DD"),3)) sprintf (text, zero? ("%02d") : ("%d"), day(localTime)); |
| 6574 |
4/6✓ Branch 0 taken 62 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
|
124 | else if (!strncmp_P(text,PSTR("#DAY"),4)) sprintf (text, ("%s") , dayShortStr(weekday(localTime))); |
| 6575 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
62 | else if (!strncmp_P(text,PSTR("#DDDD"),5)) sprintf (text, ("%s") , dayStr(weekday(localTime))); |
| 6576 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
62 | else if (!strncmp_P(text,PSTR("#MO"),3)) sprintf (text, zero? ("%02d") : ("%d"), month(localTime)); |
| 6577 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
62 | else if (!strncmp_P(text,PSTR("#MON"),4)) sprintf (text, ("%s") , monthShortStr(month(localTime))); |
| 6578 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
62 | else if (!strncmp_P(text,PSTR("#MMMM"),5)) sprintf (text, ("%s") , monthStr(month(localTime))); |
| 6579 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
62 | else if (!strncmp_P(text,PSTR("#YY"),3)) sprintf (text, ("%02d") , year(localTime)%100); |
| 6580 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
62 | else if (!strncmp_P(text,PSTR("#YYYY"),5)) sprintf_P(text, zero?PSTR("%04d") : ("%d"), year(localTime)); |
| 6581 | } | ||
| 6582 | |||
| 6583 | 142 | const int numberOfLetters = strlen(text); | |
| 6584 | 142 | int width = (numberOfLetters * rotLW); | |
| 6585 |
2/4✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
|
142 | int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-rotLH)/2; |
| 6586 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 80 times.
|
142 | if (width <= cols) { |
| 6587 | // scroll vertically (e.g. ^^ Way out ^^) if it fits | ||
| 6588 |
2/4✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
|
62 | int speed = map(SEGMENT.speed, 0, 255, 5000, 1000); |
| 6589 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | int frac = strip().now % speed + 1; |
| 6590 |
3/6✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 62 times.
|
62 | if (SEGMENT.intensity == 255) { |
| 6591 | ✗ | yoffset = (2 * frac * rows)/speed - rows; | |
| 6592 |
3/6✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 62 times.
|
62 | } else if (SEGMENT.intensity == 0) { |
| 6593 | ✗ | yoffset = rows - (2 * frac * rows)/speed; | |
| 6594 | } | ||
| 6595 | } | ||
| 6596 | |||
| 6597 |
5/8✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 142 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✓ Branch 7 taken 103 times.
|
142 | if (SEGENV.step < strip().now) { |
| 6598 | // calculate start offset | ||
| 6599 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 16 times.
|
39 | if (width > cols) { |
| 6600 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check3) { |
| 6601 | ✗ | if (SEGENV.aux0 == 0) SEGENV.aux0 = width + cols - 1; | |
| 6602 | ✗ | else --SEGENV.aux0; | |
| 6603 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | } else ++SEGENV.aux0 %= width + cols; |
| 6604 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | } else SEGENV.aux0 = (cols + width)/2; |
| 6605 |
2/4✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
39 | ++SEGENV.aux1 &= 0xFF; // color shift |
| 6606 |
5/10✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 39 times.
✗ Branch 9 not taken.
|
39 | SEGENV.step = strip().now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms |
| 6607 | } | ||
| 6608 | |||
| 6609 |
8/16✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 142 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 142 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 142 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 142 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 142 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 142 times.
✗ Branch 15 not taken.
|
142 | if (!SEGMENT.check2) SEGMENT.fade_out(255 - (SEGMENT.custom1>>4)); // trail |
| 6610 | 142 | bool usePaletteGradient = false; | |
| 6611 |
9/18✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 142 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 142 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 142 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 142 times.
✓ Branch 12 taken 142 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 142 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 142 times.
✗ Branch 17 not taken.
|
142 | uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0); |
| 6612 | 142 | uint32_t col2 = BLACK; | |
| 6613 |
3/6✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 142 times.
|
142 | if (SEGMENT.check1) { // use gradient |
| 6614 | ✗ | if(SEGMENT.palette == 0) { // use colors for gradient | |
| 6615 | ✗ | col1 = SEGCOLOR(0); | |
| 6616 | ✗ | col2 = SEGCOLOR(2); | |
| 6617 | } | ||
| 6618 | ✗ | else usePaletteGradient = true; | |
| 6619 | } | ||
| 6620 | |||
| 6621 |
2/2✓ Branch 0 taken 15426 times.
✓ Branch 1 taken 142 times.
|
15568 | for (int i = 0; i < numberOfLetters; i++) { |
| 6622 |
2/4✓ Branch 0 taken 15426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15426 times.
✗ Branch 3 not taken.
|
15426 | int xoffset = int(cols) - int(SEGENV.aux0) + rotLW*i; |
| 6623 | if (xoffset + rotLW < 0) continue; // don't draw characters off-screen | ||
| 6624 |
5/10✓ Branch 0 taken 15426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15426 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15426 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15426 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15426 times.
✗ Branch 9 not taken.
|
15426 | SEGMENT.drawCharacter(text[i], xoffset, yoffset, letterWidth, letterHeight, col1, col2, map(SEGMENT.custom3, 0, 31, -2, 2), usePaletteGradient); |
| 6625 | } | ||
| 6626 | |||
| 6627 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | return FRAMETIME; |
| 6628 | } | ||
| 6629 | static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,Rotate,Gradient,Overlay,Reverse;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0"; | ||
| 6630 | |||
| 6631 | |||
| 6632 | //////////////////////////// | ||
| 6633 | // 2D Drift Rose // | ||
| 6634 | //////////////////////////// | ||
| 6635 | //// Drift Rose by stepko (c)2021 [https://editor.soulmatelights.com/gallery/1369-drift-rose-pattern], adapted by Blaz Kristan (AKA blazoncek) improved by @dedehai | ||
| 6636 | 23 | uint16_t mode_2Ddriftrose(void) { | |
| 6637 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6638 | |||
| 6639 | 18 | const int cols = SEG_W; | |
| 6640 | 18 | const int rows = SEG_H; | |
| 6641 | |||
| 6642 | 18 | const float CX = (cols-cols%2)/2.f - .5f; | |
| 6643 | 18 | const float CY = (rows-rows%2)/2.f - .5f; | |
| 6644 | 18 | const float L = min(cols, rows) / 2.f; | |
| 6645 | |||
| 6646 | 18 | SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); | |
| 6647 |
2/2✓ Branch 0 taken 648 times.
✓ Branch 1 taken 18 times.
|
666 | for (size_t i = 1; i < 37; i++) { |
| 6648 | 648 | float angle = radians(i * 10); | |
| 6649 | 648 | uint32_t x = (CX + (sin_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; | |
| 6650 | 648 | uint32_t y = (CY + (cos_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; | |
| 6651 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 648 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
648 | if(SEGMENT.palette == 0) SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); |
| 6652 |
2/4✓ Branch 0 taken 648 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 648 times.
✗ Branch 3 not taken.
|
648 | else SEGMENT.wu_pixel(x, y, ColorFromPalette(SEGPALETTE, i * 10)); |
| 6653 | } | ||
| 6654 | 18 | SEGMENT.blur(SEGMENT.intensity >> 4, SEGMENT.check1); | |
| 6655 | |||
| 6656 | 18 | return FRAMETIME; | |
| 6657 | } | ||
| 6658 | static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur,,,,Smear;;!;2;pal=11"; | ||
| 6659 | |||
| 6660 | ///////////////////////////// | ||
| 6661 | // 2D PLASMA ROTOZOOMER // | ||
| 6662 | ///////////////////////////// | ||
| 6663 | // Plasma Rotozoomer by ldirko (c)2020 [https://editor.soulmatelights.com/gallery/457-plasma-rotozoomer], adapted for WLED by Blaz Kristan (AKA blazoncek) | ||
| 6664 | 23 | uint16_t mode_2Dplasmarotozoom() { | |
| 6665 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6666 | |||
| 6667 | 18 | const int cols = SEG_W; | |
| 6668 | 18 | const int rows = SEG_H; | |
| 6669 | |||
| 6670 | 18 | unsigned dataSize = SEGMENT.length() + sizeof(float); | |
| 6671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 6672 | 18 | float *a = reinterpret_cast<float*>(SEGENV.data); | |
| 6673 | 18 | byte *plasma = reinterpret_cast<byte*>(SEGENV.data+sizeof(float)); | |
| 6674 | |||
| 6675 | 18 | unsigned ms = strip().now/15; | |
| 6676 | |||
| 6677 | // plasma | ||
| 6678 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 18 times.
|
241 | for (int j = 0; j < rows; j++) { |
| 6679 | 223 | int index = j*cols; | |
| 6680 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 223 times.
|
6984 | for (int i = 0; i < cols; i++) { |
| 6681 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6761 times.
|
6761 | if (SEGMENT.check1) plasma[index+i] = (i * 4 ^ j * 4) + ms / 6; |
| 6682 | 6761 | else plasma[index+i] = inoise8(i * 40, j * 40, ms); | |
| 6683 | } | ||
| 6684 | } | ||
| 6685 | |||
| 6686 | // rotozoom | ||
| 6687 | 18 | float f = (sin_t(*a/2)+((128-SEGMENT.intensity)/128.0f)+1.1f)/1.5f; // scale factor | |
| 6688 | 18 | float kosinus = cos_t(*a) * f; | |
| 6689 | 18 | float sinus = sin_t(*a) * f; | |
| 6690 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int i = 0; i < cols; i++) { |
| 6691 | 451 | float u1 = i * kosinus; | |
| 6692 | 451 | float v1 = i * sinus; | |
| 6693 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int j = 0; j < rows; j++) { |
| 6694 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6761 times.
|
6761 | byte u = abs8(u1 - j * sinus) % cols; |
| 6695 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 6698 times.
|
6761 | byte v = abs8(v1 + j * kosinus) % rows; |
| 6696 |
2/4✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6761 times.
|
6761 | SEGMENT.setPixelColorXY(i, j, SEGMENT.color_from_palette(plasma[v*cols+u], false, PALETTE_SOLID_WRAP, 255)); |
| 6697 | } | ||
| 6698 | } | ||
| 6699 | 18 | *a -= 0.03f + float(SEGENV.speed-128)*0.0002f; // rotation speed | |
| 6700 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if(*a < -6283.18530718f) *a += 6283.18530718f; // 1000*2*PI, protect sin/cos from very large input float values (will give wrong results) |
| 6701 | |||
| 6702 | 18 | return FRAMETIME; | |
| 6703 | } | ||
| 6704 | static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale,,,,Alt;;!;2;pal=54"; | ||
| 6705 | |||
| 6706 | #endif // WLED_DISABLE_2D | ||
| 6707 | |||
| 6708 | |||
| 6709 | /////////////////////////////////////////////////////////////////////////////// | ||
| 6710 | /******************** audio enhanced routines ************************/ | ||
| 6711 | /////////////////////////////////////////////////////////////////////////////// | ||
| 6712 | |||
| 6713 | |||
| 6714 | ///////////////////////////////// | ||
| 6715 | // * Ripple Peak // | ||
| 6716 | ///////////////////////////////// | ||
| 6717 | 23 | uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuline. | |
| 6718 | // This currently has no controls. | ||
| 6719 | #define MAXSTEPS 16 // Case statement wouldn't allow a variable. | ||
| 6720 | |||
| 6721 | 23 | unsigned maxRipples = 16; | |
| 6722 | 23 | unsigned dataSize = sizeof(Ripple) * maxRipples; | |
| 6723 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 6724 | 23 | Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data); | |
| 6725 | |||
| 6726 | 23 | um_data_t *um_data = getAudioData(); | |
| 6727 | 23 | uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; | |
| 6728 | #ifdef ESP32 | ||
| 6729 | float FFT_MajorPeak = *(float*) um_data->u_data[4]; | ||
| 6730 | #endif | ||
| 6731 | 23 | uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; | |
| 6732 | 23 | uint8_t *binNum = (uint8_t*)um_data->u_data[7]; | |
| 6733 | |||
| 6734 | // printUmData(); | ||
| 6735 | |||
| 6736 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 6737 | 5 | SEGMENT.custom1 = *binNum; | |
| 6738 | 5 | SEGMENT.custom2 = *maxVol * 2; | |
| 6739 | } | ||
| 6740 | |||
| 6741 | 23 | *binNum = SEGMENT.custom1; // Select a bin. | |
| 6742 | 23 | *maxVol = SEGMENT.custom2 / 2; // Our volume comparator. | |
| 6743 | |||
| 6744 | 23 | SEGMENT.fade_out(240); // Lower frame rate means less effective fading than FastLED | |
| 6745 | 23 | SEGMENT.fade_out(240); | |
| 6746 | |||
| 6747 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 23 times.
|
203 | for (int i = 0; i < SEGMENT.intensity/16; i++) { // Limit the number of ripples. |
| 6748 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 149 times.
|
180 | if (samplePeak) ripples[i].state = 255; |
| 6749 | |||
| 6750 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
|
180 | switch (ripples[i].state) { |
| 6751 | ✗ | case 254: // Inactive mode | |
| 6752 | ✗ | break; | |
| 6753 | |||
| 6754 | 31 | case 255: // Initialize ripple variables. | |
| 6755 | 31 | ripples[i].pos = hw_random16(SEGLEN); | |
| 6756 | #ifdef ESP32 | ||
| 6757 | if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception) | ||
| 6758 | ripples[i].color = (int)(log10f(FFT_MajorPeak)*128); | ||
| 6759 | else ripples[i].color = 0; | ||
| 6760 | #else | ||
| 6761 | 31 | ripples[i].color = hw_random8(); | |
| 6762 | #endif | ||
| 6763 | 31 | ripples[i].state = 0; | |
| 6764 | 31 | break; | |
| 6765 | |||
| 6766 | 47 | case 0: | |
| 6767 |
2/4✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
|
47 | SEGMENT.setPixelColor(ripples[i].pos, SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0)); |
| 6768 | 47 | ripples[i].state++; | |
| 6769 | 47 | break; | |
| 6770 | |||
| 6771 | ✗ | case MAXSTEPS: // At the end of the ripples. 254 is an inactive mode. | |
| 6772 | ✗ | ripples[i].state = 254; | |
| 6773 | ✗ | break; | |
| 6774 | |||
| 6775 | 102 | default: // Middle of the ripples. | |
| 6776 |
2/4✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
|
102 | SEGMENT.setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), uint8_t(2*255/ripples[i].state))); |
| 6777 |
2/4✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
|
102 | SEGMENT.setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), uint8_t(2*255/ripples[i].state))); |
| 6778 | 102 | ripples[i].state++; // Next step. | |
| 6779 | 102 | break; | |
| 6780 | } // switch step | ||
| 6781 | } // for i | ||
| 6782 | |||
| 6783 | 23 | return FRAMETIME; | |
| 6784 | } // mode_ripplepeak() | ||
| 6785 | static const char _data_FX_MODE_RIPPLEPEAK[] PROGMEM = "Ripple Peak@Fade rate,Max # of ripples,Select bin,Volume (min);!,!;!;1v;c2=0,m12=0,si=0"; // Pixel, Beatsin | ||
| 6786 | |||
| 6787 | |||
| 6788 | #ifndef WLED_DISABLE_2D | ||
| 6789 | ///////////////////////// | ||
| 6790 | // * 2D Swirl // | ||
| 6791 | ///////////////////////// | ||
| 6792 | // By: Mark Kriegsman https://gist.github.com/kriegsman/5adca44e14ad025e6d3b , modified by Andrew Tuline | ||
| 6793 | 23 | uint16_t mode_2DSwirl(void) { | |
| 6794 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6795 | |||
| 6796 | 18 | const int cols = SEG_W; | |
| 6797 | 18 | const int rows = SEG_H; | |
| 6798 | |||
| 6799 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 6800 | 4 | SEGMENT.fill(BLACK); | |
| 6801 | } | ||
| 6802 | |||
| 6803 | 18 | const uint8_t borderWidth = 2; | |
| 6804 | |||
| 6805 | 18 | SEGMENT.blur(SEGMENT.custom1); | |
| 6806 | |||
| 6807 | 18 | int i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); | |
| 6808 | 18 | int j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); | |
| 6809 | 18 | int ni = (cols - 1) - i; | |
| 6810 | 18 | int nj = (cols - 1) - j; | |
| 6811 | |||
| 6812 | 18 | um_data_t *um_data = getAudioData(); | |
| 6813 | 18 | float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg??? | |
| 6814 | 18 | int volumeRaw = *(int16_t*) um_data->u_data[1]; | |
| 6815 | |||
| 6816 | 18 | SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (strip().now / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255); | |
| 6817 | 18 | SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (strip().now / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255); | |
| 6818 | 18 | SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (strip().now / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255); | |
| 6819 | 18 | SEGMENT.addPixelColorXY(nj,ni, ColorFromPalette(SEGPALETTE, (strip().now / 29 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 29, 200, 255); | |
| 6820 | 18 | SEGMENT.addPixelColorXY( i,nj, ColorFromPalette(SEGPALETTE, (strip().now / 37 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 37, 200, 255); | |
| 6821 | 18 | SEGMENT.addPixelColorXY(ni, j, ColorFromPalette(SEGPALETTE, (strip().now / 41 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 41, 200, 255); | |
| 6822 | |||
| 6823 | 18 | return FRAMETIME; | |
| 6824 | } // mode_2DSwirl() | ||
| 6825 | static const char _data_FX_MODE_2DSWIRL[] PROGMEM = "Swirl@!,Sensitivity,Blur;,Bg Swirl;!;2v;ix=64,si=0"; // Beatsin // TODO: color 1 unused? | ||
| 6826 | |||
| 6827 | |||
| 6828 | ///////////////////////// | ||
| 6829 | // * 2D Waverly // | ||
| 6830 | ///////////////////////// | ||
| 6831 | // By: Stepko, https://editor.soulmatelights.com/gallery/652-wave , modified by Andrew Tuline | ||
| 6832 | 75 | uint16_t mode_2DWaverly(void) { | |
| 6833 |
5/6✓ Branch 0 taken 58 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 58 times.
|
75 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 6834 | |||
| 6835 | 58 | const int cols = SEG_W; | |
| 6836 | 58 | const int rows = SEG_H; | |
| 6837 | |||
| 6838 | 58 | um_data_t *um_data = getAudioData(); | |
| 6839 | 58 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 6840 | |||
| 6841 | 58 | SEGMENT.fadeToBlackBy(SEGMENT.speed); | |
| 6842 | |||
| 6843 | 58 | long t = strip().now / 2; | |
| 6844 |
2/2✓ Branch 0 taken 1231 times.
✓ Branch 1 taken 58 times.
|
1289 | for (int i = 0; i < cols; i++) { |
| 6845 | 1231 | unsigned thisVal = (1 + SEGMENT.intensity/64) * perlin8(i * 45 , t , t)/2; | |
| 6846 | // use audio if available | ||
| 6847 |
1/2✓ Branch 0 taken 1231 times.
✗ Branch 1 not taken.
|
1231 | if (um_data) { |
| 6848 | 1231 | thisVal /= 32; // reduce intensity of perlin8() | |
| 6849 | 1231 | thisVal *= volumeSmth; | |
| 6850 | } | ||
| 6851 | 1231 | int thisMax = map(thisVal, 0, 512, 0, rows); | |
| 6852 | |||
| 6853 |
2/2✓ Branch 0 taken 24456 times.
✓ Branch 1 taken 1231 times.
|
25687 | for (int j = 0; j < thisMax; j++) { |
| 6854 | 24456 | SEGMENT.addPixelColorXY(i, j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); | |
| 6855 | 24456 | SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); | |
| 6856 | } | ||
| 6857 | } | ||
| 6858 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | if (SEGMENT.check3) SEGMENT.blur(16, cols*rows < 100); |
| 6859 | |||
| 6860 | 58 | return FRAMETIME; | |
| 6861 | } // mode_2DWaverly() | ||
| 6862 | static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly@Amplification,Sensitivity,,,,,Blur;;!;2v;ix=64,si=0"; // Beatsin | ||
| 6863 | |||
| 6864 | #endif // WLED_DISABLE_2D | ||
| 6865 | |||
| 6866 | // Gravity struct requited for GRAV* effects | ||
| 6867 | typedef struct Gravity { | ||
| 6868 | int topLED; | ||
| 6869 | int gravityCounter; | ||
| 6870 | } gravity; | ||
| 6871 | |||
| 6872 | /////////////////////// | ||
| 6873 | // * GRAVCENTER // | ||
| 6874 | /////////////////////// | ||
| 6875 | // Gravcenter effects By Andrew Tuline. | ||
| 6876 | // Gravcenter base function for Gravcenter (0), Gravcentric (1), Gravimeter (2), Gravfreq (3) (merged by @dedehai) | ||
| 6877 | |||
| 6878 | 92 | uint16_t mode_gravcenter_base(unsigned mode) { | |
| 6879 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | if (SEGLEN == 1) return mode_static(); |
| 6880 | |||
| 6881 | 92 | const unsigned dataSize = sizeof(gravity); | |
| 6882 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 6883 | 92 | Gravity* gravcen = reinterpret_cast<Gravity*>(SEGENV.data); | |
| 6884 | |||
| 6885 | 92 | um_data_t *um_data = getAudioData(); | |
| 6886 | 92 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 6887 | |||
| 6888 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if(mode == 1) SEGMENT.fade_out(253); // //Gravcentric |
| 6889 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 46 times.
|
69 | else if(mode == 2) SEGMENT.fade_out(249); // Gravimeter |
| 6890 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | else if(mode == 3) SEGMENT.fade_out(250); // Gravfreq |
| 6891 | 23 | else SEGMENT.fade_out(251); // Gravcenter | |
| 6892 | |||
| 6893 | float mySampleAvg; | ||
| 6894 | int tempsamp; | ||
| 6895 | 92 | float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; | |
| 6896 | |||
| 6897 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if(mode == 2) { //Gravimeter |
| 6898 | 23 | segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivity" upscaling | |
| 6899 | 23 | mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment | |
| 6900 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 19 times.
|
23 | tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing. |
| 6901 | } | ||
| 6902 | else { // Gravcenter or Gravcentric or Gravfreq | ||
| 6903 | 69 | segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling | |
| 6904 | 69 | mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0f); // map to pixels availeable in current segment | |
| 6905 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 37 times.
|
69 | tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. |
| 6906 | } | ||
| 6907 | |||
| 6908 | 92 | uint8_t gravity = 8 - SEGMENT.speed/32; | |
| 6909 | 92 | int offset = 1; | |
| 6910 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if(mode == 2) offset = 0; // Gravimeter |
| 6911 |
2/2✓ Branch 0 taken 69 times.
✓ Branch 1 taken 23 times.
|
92 | if (tempsamp >= gravcen->topLED + offset) gravcen->topLED = tempsamp-offset; |
| 6912 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 14 times.
|
23 | else if (gravcen->gravityCounter % gravity == 0) gravcen->topLED--; |
| 6913 | |||
| 6914 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 69 times.
|
92 | if(mode == 1) { //Gravcentric |
| 6915 |
2/2✓ Branch 0 taken 520 times.
✓ Branch 1 taken 23 times.
|
543 | for (int i=0; i<tempsamp; i++) { |
| 6916 | 520 | uint8_t index = segmentSampleAvg*24+strip().now/200; | |
| 6917 |
2/4✓ Branch 0 taken 520 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 520 times.
|
520 | SEGMENT.setPixelColor(i+SEGLEN/2, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 6918 |
2/4✓ Branch 0 taken 520 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 520 times.
|
520 | SEGMENT.setPixelColor(SEGLEN/2-1-i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 6919 | } | ||
| 6920 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (gravcen->topLED >= 0) { |
| 6921 | 19 | SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, CRGB::Gray); | |
| 6922 | 19 | SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, CRGB::Gray); | |
| 6923 | } | ||
| 6924 | } | ||
| 6925 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 46 times.
|
69 | else if(mode == 2) { //Gravimeter |
| 6926 |
2/2✓ Branch 0 taken 892 times.
✓ Branch 1 taken 23 times.
|
915 | for (int i=0; i<tempsamp; i++) { |
| 6927 | 892 | uint8_t index = perlin8(i*segmentSampleAvg+strip().now, 5000+i*segmentSampleAvg); | |
| 6928 |
2/4✓ Branch 0 taken 892 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 892 times.
|
892 | SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), uint8_t(segmentSampleAvg*8))); |
| 6929 | } | ||
| 6930 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (gravcen->topLED > 0) { |
| 6931 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
|
19 | SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(strip().now, false, PALETTE_SOLID_WRAP, 0)); |
| 6932 | } | ||
| 6933 | } | ||
| 6934 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | else if(mode == 3) { //Gravfreq |
| 6935 |
2/2✓ Branch 0 taken 2512 times.
✓ Branch 1 taken 23 times.
|
2535 | for (int i=0; i<tempsamp; i++) { |
| 6936 | 2512 | float FFT_MajorPeak = *(float*)um_data->u_data[4]; // used in mode 3: Gravfreq | |
| 6937 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2512 times.
|
2512 | if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; |
| 6938 | 2512 | uint8_t index = (log10f(FFT_MajorPeak) - (MAX_FREQ_LOG10 - 1.78f)) * 255; | |
| 6939 |
2/4✓ Branch 0 taken 2512 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2512 times.
|
2512 | SEGMENT.setPixelColor(i+SEGLEN/2, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 6940 |
2/4✓ Branch 0 taken 2512 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2512 times.
|
2512 | SEGMENT.setPixelColor(SEGLEN/2-i-1, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 6941 | } | ||
| 6942 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (gravcen->topLED >= 0) { |
| 6943 | 19 | SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, CRGB::Gray); | |
| 6944 | 19 | SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, CRGB::Gray); | |
| 6945 | } | ||
| 6946 | } | ||
| 6947 | else { //Gravcenter | ||
| 6948 |
2/2✓ Branch 0 taken 536 times.
✓ Branch 1 taken 23 times.
|
559 | for (int i=0; i<tempsamp; i++) { |
| 6949 | 536 | uint8_t index = perlin8(i*segmentSampleAvg+strip().now, 5000+i*segmentSampleAvg); | |
| 6950 |
2/4✓ Branch 0 taken 536 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 536 times.
|
536 | SEGMENT.setPixelColor(i+SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), uint8_t(segmentSampleAvg*8))); |
| 6951 |
2/4✓ Branch 0 taken 536 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 536 times.
|
536 | SEGMENT.setPixelColor(SEGLEN/2-i-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), uint8_t(segmentSampleAvg*8))); |
| 6952 | } | ||
| 6953 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (gravcen->topLED >= 0) { |
| 6954 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
|
19 | SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(strip().now, false, PALETTE_SOLID_WRAP, 0)); |
| 6955 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
|
19 | SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(strip().now, false, PALETTE_SOLID_WRAP, 0)); |
| 6956 | } | ||
| 6957 | } | ||
| 6958 | 92 | gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; | |
| 6959 | |||
| 6960 | 92 | return FRAMETIME; | |
| 6961 | } | ||
| 6962 | |||
| 6963 | 23 | uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. | |
| 6964 | 23 | return mode_gravcenter_base(0); | |
| 6965 | } | ||
| 6966 | static const char _data_FX_MODE_GRAVCENTER[] PROGMEM = "Gravcenter@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=2,si=0"; // Circle, Beatsin | ||
| 6967 | |||
| 6968 | /////////////////////// | ||
| 6969 | // * GRAVCENTRIC // | ||
| 6970 | /////////////////////// | ||
| 6971 | 23 | uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew Tuline. | |
| 6972 | 23 | return mode_gravcenter_base(1); | |
| 6973 | } | ||
| 6974 | static const char _data_FX_MODE_GRAVCENTRIC[] PROGMEM = "Gravcentric@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=3,si=0"; // Corner, Beatsin | ||
| 6975 | |||
| 6976 | |||
| 6977 | /////////////////////// | ||
| 6978 | // * GRAVIMETER // | ||
| 6979 | /////////////////////// | ||
| 6980 | 23 | uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. | |
| 6981 | 23 | return mode_gravcenter_base(2); | |
| 6982 | } | ||
| 6983 | static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=2,si=0"; // Circle, Beatsin | ||
| 6984 | |||
| 6985 | |||
| 6986 | /////////////////////// | ||
| 6987 | // ** Gravfreq // | ||
| 6988 | /////////////////////// | ||
| 6989 | 23 | uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. | |
| 6990 | 23 | return mode_gravcenter_base(3); | |
| 6991 | } | ||
| 6992 | static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensitivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin | ||
| 6993 | |||
| 6994 | |||
| 6995 | ////////////////////// | ||
| 6996 | // * JUGGLES // | ||
| 6997 | ////////////////////// | ||
| 6998 | 23 | uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. | |
| 6999 | 23 | um_data_t *um_data = getAudioData(); | |
| 7000 | 23 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7001 | |||
| 7002 | 23 | SEGMENT.fade_out(224); // 6.25% | |
| 7003 | 23 | uint8_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); | |
| 7004 | |||
| 7005 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23 times.
|
134 | for (size_t i=0; i<SEGMENT.intensity/32+1U; i++) { |
| 7006 | // if SEGLEN equals 1, we will always set color to the first and only pixel, but the effect is still good looking | ||
| 7007 |
2/4✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 111 times.
|
111 | SEGMENT.setPixelColor(beatsin16_t(SEGMENT.speed/4+i*2,0,SEGLEN-1), color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip().now/4+i*2, false, PALETTE_SOLID_WRAP, 0), my_sampleAgc)); |
| 7008 | } | ||
| 7009 | |||
| 7010 | 23 | return FRAMETIME; | |
| 7011 | } // mode_juggles() | ||
| 7012 | static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!;01v;m12=0,si=0"; // Pixels, Beatsin | ||
| 7013 | |||
| 7014 | |||
| 7015 | ////////////////////// | ||
| 7016 | // * MATRIPIX // | ||
| 7017 | ////////////////////// | ||
| 7018 | 23 | uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. | |
| 7019 | // effect can work on single pixels, we just lose the shifting effect | ||
| 7020 | 23 | unsigned dataSize = sizeof(uint32_t) * SEGLEN; | |
| 7021 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 7022 | 23 | uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | |
| 7023 | |||
| 7024 | 23 | um_data_t *um_data = getAudioData(); | |
| 7025 | 23 | int volumeRaw = *(int16_t*)um_data->u_data[1]; | |
| 7026 | |||
| 7027 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 7028 |
2/2✓ Branch 0 taken 262 times.
✓ Branch 1 taken 5 times.
|
267 | for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer |
| 7029 | } | ||
| 7030 | |||
| 7031 | 23 | uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; | |
| 7032 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6 times.
|
23 | if(SEGENV.aux0 != secondHand) { |
| 7033 | 17 | SEGENV.aux0 = secondHand; | |
| 7034 | |||
| 7035 | 17 | int pixBri = volumeRaw * SEGMENT.intensity / 64; | |
| 7036 | 17 | unsigned k = SEGLEN-1; | |
| 7037 | // loop will not execute if SEGLEN equals 1 | ||
| 7038 |
2/2✓ Branch 0 taken 926 times.
✓ Branch 1 taken 17 times.
|
943 | for (unsigned i = 0; i < k; i++) { |
| 7039 | 926 | pixels[i] = pixels[i+1]; // shift left | |
| 7040 | 926 | SEGMENT.setPixelColor(i, pixels[i]); | |
| 7041 | } | ||
| 7042 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
|
17 | pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip().now, false, PALETTE_SOLID_WRAP, 0), pixBri); |
| 7043 | 17 | SEGMENT.setPixelColor(k, pixels[k]); | |
| 7044 | } | ||
| 7045 | |||
| 7046 | 23 | return FRAMETIME; | |
| 7047 | } // mode_matripix() | ||
| 7048 | static const char _data_FX_MODE_MATRIPIX[] PROGMEM = "Matripix@!,Brightness;!,!;!;1v;ix=64,m12=2,si=1"; //,rev=1,mi=1,rY=1,mY=1 Circle, WeWillRockYou, reverseX | ||
| 7049 | |||
| 7050 | |||
| 7051 | ////////////////////// | ||
| 7052 | // * MIDNOISE // | ||
| 7053 | ////////////////////// | ||
| 7054 | 23 | uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. | |
| 7055 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 7056 | // Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1. | ||
| 7057 | |||
| 7058 | 23 | um_data_t *um_data = getAudioData(); | |
| 7059 | 23 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7060 | |||
| 7061 | 23 | SEGMENT.fade_out(SEGMENT.speed); | |
| 7062 | 23 | SEGMENT.fade_out(SEGMENT.speed); | |
| 7063 | |||
| 7064 | 23 | float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive. | |
| 7065 | 23 | tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitivity/length. | |
| 7066 | |||
| 7067 | 23 | unsigned maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2); | |
| 7068 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
|
23 | if (maxLen >SEGLEN/2) maxLen = SEGLEN/2; |
| 7069 | |||
| 7070 |
2/2✓ Branch 0 taken 468 times.
✓ Branch 1 taken 23 times.
|
491 | for (unsigned i=(SEGLEN/2-maxLen); i<(SEGLEN/2+maxLen); i++) { |
| 7071 | 468 | uint8_t index = perlin8(i*volumeSmth+SEGENV.aux0, SEGENV.aux1+i*volumeSmth); // Get a value from the noise function. I'm using both x and y axis. | |
| 7072 |
2/4✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 468 times.
|
468 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 7073 | } | ||
| 7074 | |||
| 7075 | 23 | SEGENV.aux0=SEGENV.aux0+beatsin8_t(5,0,10); | |
| 7076 | 23 | SEGENV.aux1=SEGENV.aux1+beatsin8_t(4,0,10); | |
| 7077 | |||
| 7078 | 23 | return FRAMETIME; | |
| 7079 | } // mode_midnoise() | ||
| 7080 | static const char _data_FX_MODE_MIDNOISE[] PROGMEM = "Midnoise@Fade rate,Max. length;!,!;!;1v;ix=128,m12=1,si=0"; // Bar, Beatsin | ||
| 7081 | |||
| 7082 | |||
| 7083 | ////////////////////// | ||
| 7084 | // * NOISEFIRE // | ||
| 7085 | ////////////////////// | ||
| 7086 | // I am the god of hellfire. . . Volume (only) reactive fire routine. Oh, look how short this is. | ||
| 7087 | 23 | uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. | |
| 7088 | ✗ | CRGBPalette16 myPal = CRGBPalette16(CHSV(0,255,2), CHSV(0,255,4), CHSV(0,255,8), CHSV(0, 255, 8), // Fire palette definition. Lower value = darker. | |
| 7089 | ✗ | CHSV(0, 255, 16), CRGB::Red, CRGB::Red, CRGB::Red, | |
| 7090 | CRGB::DarkOrange, CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, | ||
| 7091 | 46 | CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); | |
| 7092 | |||
| 7093 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | um_data_t *um_data = getAudioData(); |
| 7094 | 23 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7095 | |||
| 7096 |
7/12✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
|
23 | if (SEGENV.call == 0) SEGMENT.fill(BLACK); |
| 7097 | |||
| 7098 |
2/2✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 23 times.
|
1263 | for (unsigned i = 0; i < SEGLEN; i++) { |
| 7099 |
6/12✓ Branch 0 taken 1240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1240 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1240 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1240 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1240 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1240 times.
✗ Branch 11 not taken.
|
1240 | unsigned index = perlin8(i*SEGMENT.speed/64,strip().now*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of millis(). By Andrew Tuline. |
| 7100 |
2/4✓ Branch 0 taken 1240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1240 times.
✗ Branch 3 not taken.
|
1240 | index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. |
| 7101 | // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. | ||
| 7102 | |||
| 7103 |
4/8✓ Branch 0 taken 1240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1240 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1240 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1240 times.
✗ Branch 7 not taken.
|
1240 | SEGMENT.setPixelColor(i, ColorFromPalette(myPal, index, volumeSmth*2, LINEARBLEND)); // Use my own palette. |
| 7104 | } | ||
| 7105 | |||
| 7106 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
46 | return FRAMETIME; |
| 7107 | } // mode_noisefire() | ||
| 7108 | static const char _data_FX_MODE_NOISEFIRE[] PROGMEM = "Noisefire@!,!;;;01v;m12=2,si=0"; // Circle, Beatsin | ||
| 7109 | |||
| 7110 | |||
| 7111 | /////////////////////// | ||
| 7112 | // * Noisemeter // | ||
| 7113 | /////////////////////// | ||
| 7114 | 23 | uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. | |
| 7115 | |||
| 7116 | 23 | um_data_t *um_data = getAudioData(); | |
| 7117 | 23 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7118 | 23 | int volumeRaw = *(int16_t*)um_data->u_data[1]; | |
| 7119 | |||
| 7120 | //uint8_t fadeRate = map(SEGMENT.speed,0,255,224,255); | ||
| 7121 | 23 | uint8_t fadeRate = map(SEGMENT.speed,0,255,200,254); | |
| 7122 | 23 | SEGMENT.fade_out(fadeRate); | |
| 7123 | |||
| 7124 | 23 | float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0; | |
| 7125 | 23 | unsigned maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. | |
| 7126 | if (maxLen < 0) maxLen = 0; | ||
| 7127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (maxLen > SEGLEN) maxLen = SEGLEN; |
| 7128 | |||
| 7129 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 23 times.
|
260 | for (unsigned i=0; i<maxLen; i++) { // The louder the sound, the wider the soundbar. By Andrew Tuline. |
| 7130 | 237 | uint8_t index = perlin8(i*volumeSmth+SEGENV.aux0, SEGENV.aux1+i*volumeSmth); // Get a value from the noise function. I'm using both x and y axis. | |
| 7131 |
2/4✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 237 times.
|
237 | SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); |
| 7132 | } | ||
| 7133 | |||
| 7134 | 23 | SEGENV.aux0+=beatsin8_t(5,0,10); | |
| 7135 | 23 | SEGENV.aux1+=beatsin8_t(4,0,10); | |
| 7136 | |||
| 7137 | 23 | return FRAMETIME; | |
| 7138 | } // mode_noisemeter() | ||
| 7139 | static const char _data_FX_MODE_NOISEMETER[] PROGMEM = "Noisemeter@Fade rate,Width;!,!;!;1v;ix=128,m12=2,si=0"; // Circle, Beatsin | ||
| 7140 | |||
| 7141 | |||
| 7142 | ////////////////////// | ||
| 7143 | // * PIXELWAVE // | ||
| 7144 | ////////////////////// | ||
| 7145 | 23 | uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. | |
| 7146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 7147 | // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment | ||
| 7148 | |||
| 7149 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 7150 | 5 | SEGMENT.fill(BLACK); | |
| 7151 | } | ||
| 7152 | |||
| 7153 | 23 | um_data_t *um_data = getAudioData(); | |
| 7154 | 23 | int volumeRaw = *(int16_t*)um_data->u_data[1]; | |
| 7155 | |||
| 7156 | 23 | uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 16; | |
| 7157 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (SEGENV.aux0 != secondHand) { |
| 7158 | 19 | SEGENV.aux0 = secondHand; | |
| 7159 | |||
| 7160 | 19 | uint8_t pixBri = volumeRaw * SEGMENT.intensity / 64; | |
| 7161 | |||
| 7162 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
|
19 | SEGMENT.setPixelColor(SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip().now, false, PALETTE_SOLID_WRAP, 0), pixBri)); |
| 7163 |
2/2✓ Branch 0 taken 495 times.
✓ Branch 1 taken 19 times.
|
514 | for (unsigned i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left |
| 7164 |
2/2✓ Branch 0 taken 499 times.
✓ Branch 1 taken 19 times.
|
518 | for (unsigned i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right |
| 7165 | } | ||
| 7166 | |||
| 7167 | 23 | return FRAMETIME; | |
| 7168 | } // mode_pixelwave() | ||
| 7169 | static const char _data_FX_MODE_PIXELWAVE[] PROGMEM = "Pixelwave@!,Sensitivity;!,!;!;1v;ix=64,m12=2,si=0"; // Circle, Beatsin | ||
| 7170 | |||
| 7171 | |||
| 7172 | ////////////////////// | ||
| 7173 | // * PLASMOID // | ||
| 7174 | ////////////////////// | ||
| 7175 | typedef struct Plasphase { | ||
| 7176 | int16_t thisphase; | ||
| 7177 | int16_t thatphase; | ||
| 7178 | } plasphase; | ||
| 7179 | |||
| 7180 | 23 | uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. | |
| 7181 | // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment | ||
| 7182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(sizeof(plasphase))) return mode_static(); //allocation failed |
| 7183 | 23 | Plasphase* plasmoip = reinterpret_cast<Plasphase*>(SEGENV.data); | |
| 7184 | |||
| 7185 | 23 | um_data_t *um_data = getAudioData(); | |
| 7186 | 23 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7187 | |||
| 7188 | 23 | SEGMENT.fadeToBlackBy(32); | |
| 7189 | |||
| 7190 | 23 | plasmoip->thisphase += beatsin8_t(6,-4,4); // You can change direction and speed individually. | |
| 7191 | 23 | plasmoip->thatphase += beatsin8_t(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. | |
| 7192 | |||
| 7193 |
2/2✓ Branch 0 taken 7511 times.
✓ Branch 1 taken 23 times.
|
7534 | for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. |
| 7194 | // updated, similar to "plasma" effect - softhack007 | ||
| 7195 | 7511 | uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; | |
| 7196 | 7511 | thisbright += cos8_t(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. | |
| 7197 | |||
| 7198 | 7511 | uint8_t colorIndex=thisbright; | |
| 7199 |
2/2✓ Branch 0 taken 6928 times.
✓ Branch 1 taken 583 times.
|
7511 | if (volumeSmth * SEGMENT.intensity / 64 < thisbright) {thisbright = 0;} |
| 7200 | |||
| 7201 |
2/4✓ Branch 0 taken 7511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7511 times.
|
7511 | SEGMENT.addPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0), thisbright)); |
| 7202 | } | ||
| 7203 | |||
| 7204 | 23 | return FRAMETIME; | |
| 7205 | } // mode_plasmoid() | ||
| 7206 | static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels;!,!;!;01v;sx=128,ix=128,m12=0,si=0"; // Pixels, Beatsin | ||
| 7207 | |||
| 7208 | |||
| 7209 | ////////////////////// | ||
| 7210 | // * PUDDLES // | ||
| 7211 | ////////////////////// | ||
| 7212 | // Puddles/Puddlepeak By Andrew Tuline. Merged by @dedehai | ||
| 7213 | 46 | uint16_t mode_puddles_base(bool peakdetect) { | |
| 7214 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (SEGLEN <= 1) return mode_static(); |
| 7215 | 46 | unsigned size = 0; | |
| 7216 | 46 | uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254); | |
| 7217 | 46 | unsigned pos = hw_random16(SEGLEN); // Set a random starting position. | |
| 7218 | 46 | SEGMENT.fade_out(fadeVal); | |
| 7219 | |||
| 7220 | 46 | um_data_t *um_data = getAudioData(); | |
| 7221 | 46 | int volumeRaw = *(int16_t*)um_data->u_data[1]; | |
| 7222 | 46 | uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; | |
| 7223 | 46 | uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; | |
| 7224 | 46 | uint8_t *binNum = (uint8_t*)um_data->u_data[7]; | |
| 7225 | 46 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7226 | |||
| 7227 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | if(peakdetect) { // puddles peak |
| 7228 | 23 | *binNum = SEGMENT.custom1; // Select a bin. | |
| 7229 | 23 | *maxVol = SEGMENT.custom2 / 2; // Our volume comparator. | |
| 7230 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (samplePeak == 1) { |
| 7231 | 1 | size = volumeSmth * SEGMENT.intensity /256 /4 + 1; // Determine size of the flash based on the volume. | |
| 7232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (pos+size>= SEGLEN) size = SEGLEN - pos; |
| 7233 | } | ||
| 7234 | } | ||
| 7235 | else { // puddles | ||
| 7236 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (volumeRaw > 1) { |
| 7237 | 23 | size = volumeRaw * SEGMENT.intensity /256 /8 + 1; // Determine size of the flash based on the volume. | |
| 7238 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (pos+size >= SEGLEN) size = SEGLEN - pos; |
| 7239 | } | ||
| 7240 | } | ||
| 7241 | |||
| 7242 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 46 times.
|
142 | for (unsigned i=0; i<size; i++) { // Flash the LED's. |
| 7243 |
2/4✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 96 times.
|
96 | SEGMENT.setPixelColor(pos+i, SEGMENT.color_from_palette(strip().now, false, PALETTE_SOLID_WRAP, 0)); |
| 7244 | } | ||
| 7245 | |||
| 7246 | 46 | return FRAMETIME; | |
| 7247 | } | ||
| 7248 | |||
| 7249 | 23 | uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. | |
| 7250 | 23 | return mode_puddles_base(true); | |
| 7251 | } | ||
| 7252 | static const char _data_FX_MODE_PUDDLEPEAK[] PROGMEM = "Puddlepeak@Fade rate,Puddle size,Select bin,Volume (min);!,!;!;1v;c2=0,m12=0,si=0"; // Pixels, Beatsin | ||
| 7253 | |||
| 7254 | 23 | uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline. | |
| 7255 | 23 | return mode_puddles_base(false); | |
| 7256 | } | ||
| 7257 | static const char _data_FX_MODE_PUDDLES[] PROGMEM = "Puddles@Fade rate,Puddle size;!,!;!;1v;m12=0,si=0"; // Pixels, Beatsin | ||
| 7258 | |||
| 7259 | |||
| 7260 | ////////////////////// | ||
| 7261 | // * PIXELS // | ||
| 7262 | ////////////////////// | ||
| 7263 | 23 | uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline. | |
| 7264 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 7265 | |||
| 7266 |
4/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
23 | if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed |
| 7267 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low. |
| 7268 | |||
| 7269 | um_data_t *um_data; | ||
| 7270 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | if (!UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { |
| 7271 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | um_data = simulateSound(SEGMENT.soundSim); |
| 7272 | } | ||
| 7273 | 23 | float volumeSmth = *(float*) um_data->u_data[0]; | |
| 7274 | |||
| 7275 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | myVals[strip().now%32] = volumeSmth; // filling values semi randomly |
| 7276 | |||
| 7277 |
5/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
|
23 | SEGMENT.fade_out(64+(SEGMENT.speed>>1)); |
| 7278 | |||
| 7279 |
4/6✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 387 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 364 times.
✓ Branch 5 taken 23 times.
|
387 | for (int i=0; i <SEGMENT.intensity/8; i++) { |
| 7280 | 364 | unsigned segLoc = hw_random16(SEGLEN); // 16 bit for larger strands of LED's. | |
| 7281 |
11/22✓ Branch 0 taken 364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 364 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 364 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 364 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 364 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 364 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 364 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 364 times.
✓ Branch 16 taken 364 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 364 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 364 times.
✗ Branch 21 not taken.
|
364 | SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(myVals[i%32]+i*4, false, PALETTE_SOLID_WRAP, 0), uint8_t(volumeSmth))); |
| 7282 | } | ||
| 7283 | |||
| 7284 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 7285 | } // mode_pixels() | ||
| 7286 | static const char _data_FX_MODE_PIXELS[] PROGMEM = "Pixels@Fade rate,# of pixels;!,!;!;1v;m12=0,si=0"; // Pixels, Beatsin | ||
| 7287 | |||
| 7288 | ////////////////////// | ||
| 7289 | // ** Blurz // | ||
| 7290 | ////////////////////// | ||
| 7291 | 23 | uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. | |
| 7292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 7293 | // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment | ||
| 7294 | |||
| 7295 | 23 | um_data_t *um_data = getAudioData(); | |
| 7296 | 23 | uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | |
| 7297 | |||
| 7298 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 7299 | 5 | SEGMENT.fill(BLACK); | |
| 7300 | 5 | SEGENV.aux0 = 0; | |
| 7301 | } | ||
| 7302 | |||
| 7303 | 23 | int fadeoutDelay = (256 - SEGMENT.speed) / 32; | |
| 7304 |
6/6✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 12 times.
|
23 | if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed); |
| 7305 | |||
| 7306 | 23 | SEGENV.step += FRAMETIME; | |
| 7307 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | if (SEGENV.step > SPEED_FORMULA_L) { |
| 7308 | 13 | unsigned segLoc = hw_random16(SEGLEN); | |
| 7309 |
2/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
13 | SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, (int)SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), uint8_t(2*fftResult[SEGENV.aux0%16]))); |
| 7310 | 13 | ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 | |
| 7311 | |||
| 7312 | 13 | SEGENV.step = 1; | |
| 7313 | 13 | SEGMENT.blur(SEGMENT.intensity); // note: blur > 210 results in a alternating pattern, this could be fixed by mapping but some may like it (very old bug) | |
| 7314 | } | ||
| 7315 | |||
| 7316 | 23 | return FRAMETIME; | |
| 7317 | } // mode_blurz() | ||
| 7318 | static const char _data_FX_MODE_BLURZ[] PROGMEM = "Blurz@Fade rate,Blur;!,Color mix;!;1f;m12=0,si=0"; // Pixels, Beatsin | ||
| 7319 | |||
| 7320 | |||
| 7321 | ///////////////////////// | ||
| 7322 | // ** DJLight // | ||
| 7323 | ///////////////////////// | ||
| 7324 | 23 | uint16_t mode_DJLight(void) { // Written by ??? Adapted by Will Tatam. | |
| 7325 | // No need to prevent from executing on single led strips, only mid will be set (mid = 0) | ||
| 7326 | 23 | const int mid = SEGLEN / 2; | |
| 7327 | |||
| 7328 | 23 | um_data_t *um_data = getAudioData(); | |
| 7329 | 23 | uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | |
| 7330 | |||
| 7331 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 7332 | 5 | SEGMENT.fill(BLACK); | |
| 7333 | } | ||
| 7334 | |||
| 7335 | 23 | uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 64; | |
| 7336 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
|
23 | if (SEGENV.aux0 != secondHand) { // Triggered millis timing. |
| 7337 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | SEGENV.aux0 = secondHand; |
| 7338 | |||
| 7339 | 19 | CRGB color = CRGB(fftResult[15]/2, fftResult[5]/2, fftResult[0]/2); // 16-> 15 as 16 is out of bounds | |
| 7340 |
4/8✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
|
19 | SEGMENT.setPixelColor(mid, color.fadeToBlackBy(map(fftResult[4], 0, 255, 255, 4))); // TODO - Update |
| 7341 | |||
| 7342 | // if SEGLEN equals 1 these loops won't execute | ||
| 7343 |
8/14✓ Branch 0 taken 481 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 481 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 481 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 481 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 481 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 481 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 481 times.
✓ Branch 13 taken 19 times.
|
500 | for (int i = SEGLEN - 1; i > mid; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); // move to the left |
| 7344 |
8/14✓ Branch 0 taken 485 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 485 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 485 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 485 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 485 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 485 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 485 times.
✓ Branch 13 taken 19 times.
|
504 | for (int i = 0; i < mid; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right |
| 7345 | } | ||
| 7346 | |||
| 7347 | 23 | return FRAMETIME; | |
| 7348 | } // mode_DJLight() | ||
| 7349 | static const char _data_FX_MODE_DJLIGHT[] PROGMEM = "DJ Light@Speed;;;01f;m12=2,si=0"; // Circle, Beatsin | ||
| 7350 | |||
| 7351 | |||
| 7352 | //////////////////// | ||
| 7353 | // ** Freqmap // | ||
| 7354 | //////////////////// | ||
| 7355 | 23 | uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. Would be better if a higher framerate. | |
| 7356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN <= 1) return mode_static(); |
| 7357 | // Start frequency = 60 Hz and log10(60) = 1.78 | ||
| 7358 | // End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10 | ||
| 7359 | |||
| 7360 | 23 | um_data_t *um_data = getAudioData(); | |
| 7361 | 23 | float FFT_MajorPeak = *(float*)um_data->u_data[4]; | |
| 7362 | 23 | float my_magnitude = *(float*)um_data->u_data[5] / 4.0f; | |
| 7363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) |
| 7364 | |||
| 7365 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) SEGMENT.fill(BLACK); |
| 7366 | 23 | int fadeoutDelay = (256 - SEGMENT.speed) / 32; | |
| 7367 |
6/6✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 12 times.
|
23 | if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed); |
| 7368 | |||
| 7369 | 23 | int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(MAX_FREQ_LOG10 - 1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN. | |
| 7370 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (locn < 1) locn = 0; // avoid underflow |
| 7371 | |||
| 7372 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (locn >= (int)SEGLEN) locn = SEGLEN-1; |
| 7373 | 23 | unsigned pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. | |
| 7374 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 22 times.
|
23 | if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow |
| 7375 | |||
| 7376 | 23 | uint8_t bright = (uint8_t)my_magnitude; | |
| 7377 | |||
| 7378 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
23 | SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), bright)); |
| 7379 | |||
| 7380 | 23 | return FRAMETIME; | |
| 7381 | } // mode_freqmap() | ||
| 7382 | static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting color;!,!;!;1f;m12=0,si=0"; // Pixels, Beatsin | ||
| 7383 | |||
| 7384 | |||
| 7385 | /////////////////////// | ||
| 7386 | // ** Freqmatrix // | ||
| 7387 | /////////////////////// | ||
| 7388 | 143 | uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. | |
| 7389 | // No need to prevent from executing on single led strips, we simply change pixel 0 each time and avoid the shift | ||
| 7390 | 143 | um_data_t *um_data = getAudioData(); | |
| 7391 | 143 | float FFT_MajorPeak = *(float*)um_data->u_data[4]; | |
| 7392 | 143 | float volumeSmth = *(float*)um_data->u_data[0]; | |
| 7393 | |||
| 7394 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 134 times.
|
143 | if (SEGENV.call == 0) { |
| 7395 | 9 | SEGMENT.fill(BLACK); | |
| 7396 | } | ||
| 7397 | |||
| 7398 | 143 | uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; | |
| 7399 |
2/2✓ Branch 0 taken 138 times.
✓ Branch 1 taken 5 times.
|
143 | if(SEGENV.aux0 != secondHand) { |
| 7400 |
2/4✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
|
138 | SEGENV.aux0 = secondHand; |
| 7401 | |||
| 7402 |
2/4✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
|
138 | uint8_t sensitivity = map(SEGMENT.custom3, 0, 31, 1, 10); // reduced resolution slider |
| 7403 |
2/4✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
|
138 | int pixVal = (volumeSmth * SEGMENT.intensity * sensitivity) / 256.0f; |
| 7404 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 129 times.
|
138 | if (pixVal > 255) pixVal = 255; |
| 7405 | |||
| 7406 | 138 | float intensity = map(pixVal, 0, 255, 0, 100) / 100.0f; // make a brightness from the last avg | |
| 7407 | |||
| 7408 | 138 | CRGB color = CRGB::Black; | |
| 7409 | |||
| 7410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 138 times.
|
138 | if (FFT_MajorPeak > MAX_FREQUENCY) FFT_MajorPeak = 1; |
| 7411 | // MajorPeak holds the freq. value which is most abundant in the last sample. | ||
| 7412 | // With our sampling rate of 10240Hz we have a usable freq range from roughly 80Hz to 10240/2 Hz | ||
| 7413 | // we will treat everything with less than 65Hz as 0 | ||
| 7414 | |||
| 7415 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 98 times.
|
138 | if (FFT_MajorPeak < 80) { |
| 7416 | color = CRGB::Black; | ||
| 7417 | } else { | ||
| 7418 |
2/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
|
98 | int upperLimit = 80 + 42 * SEGMENT.custom2; |
| 7419 |
2/4✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
|
98 | int lowerLimit = 80 + 3 * SEGMENT.custom1; |
| 7420 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 2 times.
|
98 | uint8_t i = lowerLimit!=upperLimit ? map(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255) : FFT_MajorPeak; // may under/overflow - so we enforce uint8_t |
| 7421 | 98 | unsigned b = 255 * intensity; | |
| 7422 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
|
98 | if (b > 255) b = 255; |
| 7423 | 196 | color = CHSV(i, 240, (uint8_t)b); // implicit conversion to RGB supplied by FastLED | |
| 7424 | } | ||
| 7425 | |||
| 7426 | // shift the pixels one pixel up | ||
| 7427 |
3/6✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
|
138 | SEGMENT.setPixelColor(0, color); |
| 7428 | // if SEGLEN equals 1 this loop won't execute | ||
| 7429 |
8/14✓ Branch 0 taken 2010 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2010 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2010 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2010 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2010 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2010 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2010 times.
✓ Branch 13 taken 138 times.
|
2148 | for (int i = SEGLEN - 1; i > 0; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left |
| 7430 | } | ||
| 7431 | |||
| 7432 | 143 | return FRAMETIME; | |
| 7433 | } // mode_freqmatrix() | ||
| 7434 | static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensitivity;;;01f;m12=3,si=0"; // Corner, Beatsin | ||
| 7435 | |||
| 7436 | |||
| 7437 | ////////////////////// | ||
| 7438 | // ** Freqpixels // | ||
| 7439 | ////////////////////// | ||
| 7440 | // Start frequency = 60 Hz and log10(60) = 1.78 | ||
| 7441 | // End frequency = 5120 Hz and lo10(5120) = 3.71 | ||
| 7442 | // SEGMENT.speed select faderate | ||
| 7443 | // SEGMENT.intensity select colour index | ||
| 7444 | 23 | uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. | |
| 7445 | 23 | um_data_t *um_data = getAudioData(); | |
| 7446 | 23 | float FFT_MajorPeak = *(float*)um_data->u_data[4]; | |
| 7447 | 23 | float my_magnitude = *(float*)um_data->u_data[5] / 16.0f; | |
| 7448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (FFT_MajorPeak < 1) FFT_MajorPeak = 1.0f; // log10(0) is "forbidden" (throws exception) |
| 7449 | |||
| 7450 | // this code translates to speed * (2 - speed/255) which is a) speed*2 or b) speed (when speed is 255) | ||
| 7451 | // and since fade_out() can only take 0-255 it will behave incorrectly when speed > 127 | ||
| 7452 | //uint16_t fadeRate = 2*SEGMENT.speed - SEGMENT.speed*SEGMENT.speed/255; // Get to 255 as quick as you can. | ||
| 7453 | 23 | unsigned fadeRate = SEGMENT.speed*SEGMENT.speed; // Get to 255 as quick as you can. | |
| 7454 | 23 | fadeRate = map(fadeRate, 0, 65535, 1, 255); | |
| 7455 | |||
| 7456 | 23 | int fadeoutDelay = (256 - SEGMENT.speed) / 64; | |
| 7457 |
6/6✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 9 times.
|
23 | if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(fadeRate); |
| 7458 | |||
| 7459 | 23 | uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. | |
| 7460 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow |
| 7461 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 23 times.
|
134 | for (int i=0; i < SEGMENT.intensity/32+1; i++) { |
| 7462 | 111 | unsigned locn = hw_random16(0,SEGLEN); | |
| 7463 |
2/4✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 111 times.
|
111 | SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude)); |
| 7464 | } | ||
| 7465 | |||
| 7466 | 23 | return FRAMETIME; | |
| 7467 | } // mode_freqpixels() | ||
| 7468 | static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Starting color and # of pixels;!,!,;!;1f;m12=0,si=0"; // Pixels, Beatsin | ||
| 7469 | |||
| 7470 | |||
| 7471 | ////////////////////// | ||
| 7472 | // ** Freqwave // | ||
| 7473 | ////////////////////// | ||
| 7474 | // Assign a color to the central (starting pixels) based on the predominant frequencies and the volume. The color is being determined by mapping the MajorPeak from the FFT | ||
| 7475 | // and then mapping this to the HSV color circle. Currently we are sampling at 10240 Hz, so the highest frequency we can look at is 5120Hz. | ||
| 7476 | // | ||
| 7477 | // SEGMENT.custom1: the lower cut off point for the FFT. (many, most time the lowest values have very little information since they are FFT conversion artifacts. Suggested value is close to but above 0 | ||
| 7478 | // SEGMENT.custom2: The high cut off point. This depends on your sound profile. Most music looks good when this slider is between 50% and 100%. | ||
| 7479 | // SEGMENT.custom3: "preamp" for the audio signal for audio10. | ||
| 7480 | // | ||
| 7481 | // I suggest that for this effect you turn the brightness to 95%-100% but again it depends on your soundprofile you find yourself in. | ||
| 7482 | // Instead of using colorpalettes, This effect works on the HSV color circle with red being the lowest frequency | ||
| 7483 | // | ||
| 7484 | // As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz. | ||
| 7485 | // Depending on the music stream you have you might find it useful to change the frequency mapping. | ||
| 7486 | 23 | uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung. | |
| 7487 | // As before, this effect can also work on single pixels, we just lose the shifting effect | ||
| 7488 | 23 | um_data_t *um_data = getAudioData(); | |
| 7489 | 23 | float FFT_MajorPeak = *(float*)um_data->u_data[4]; | |
| 7490 | 23 | float volumeSmth = *(float*)um_data->u_data[0]; | |
| 7491 | |||
| 7492 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 7493 | 5 | SEGMENT.fill(BLACK); | |
| 7494 | } | ||
| 7495 | |||
| 7496 | 23 | uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; | |
| 7497 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
|
23 | if(SEGENV.aux0 != secondHand) { |
| 7498 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | SEGENV.aux0 = secondHand; |
| 7499 | |||
| 7500 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | float sensitivity = mapf(SEGMENT.custom3, 1, 31, 1, 10); // reduced resolution slider |
| 7501 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | float pixVal = min(255.0f, volumeSmth * (float)SEGMENT.intensity / 256.0f * sensitivity); |
| 7502 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | float intensity = mapf(pixVal, 0.0f, 255.0f, 0.0f, 100.0f) / 100.0f; // make a brightness from the last avg |
| 7503 | |||
| 7504 | 18 | CRGB color = 0; | |
| 7505 | |||
| 7506 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (FFT_MajorPeak > MAX_FREQUENCY) FFT_MajorPeak = 1.0f; |
| 7507 | // MajorPeak holds the freq. value which is most abundant in the last sample. | ||
| 7508 | // With our sampling rate of 10240Hz we have a usable freq range from roughly 80Hz to 10240/2 Hz | ||
| 7509 | // we will treat everything with less than 65Hz as 0 | ||
| 7510 | |||
| 7511 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
|
18 | if (FFT_MajorPeak < 80) { |
| 7512 | color = CRGB::Black; | ||
| 7513 | } else { | ||
| 7514 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | int upperLimit = 80 + 42 * SEGMENT.custom2; |
| 7515 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | int lowerLimit = 80 + 3 * SEGMENT.custom1; |
| 7516 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
|
17 | uint8_t i = lowerLimit!=upperLimit ? map(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255) : FFT_MajorPeak; // may under/overflow - so we enforce uint8_t |
| 7517 | 17 | unsigned b = min(255.0f, 255.0f * intensity); | |
| 7518 | 34 | color = CHSV(i, 240, (uint8_t)b); // implicit conversion to RGB supplied by FastLED | |
| 7519 | } | ||
| 7520 | |||
| 7521 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | SEGMENT.setPixelColor(SEGLEN/2, color); |
| 7522 | |||
| 7523 | // shift the pixels one pixel outwards | ||
| 7524 | // if SEGLEN equals 1 these loops won't execute | ||
| 7525 |
8/14✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 478 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 478 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 478 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 478 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 478 times.
✓ Branch 13 taken 18 times.
|
496 | for (unsigned i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left |
| 7526 |
8/14✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 482 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 482 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 482 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 482 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 482 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 482 times.
✓ Branch 13 taken 18 times.
|
500 | for (unsigned i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right |
| 7527 | } | ||
| 7528 | |||
| 7529 | 23 | return FRAMETIME; | |
| 7530 | } // mode_freqwave() | ||
| 7531 | static const char _data_FX_MODE_FREQWAVE[] PROGMEM = "Freqwave@Speed,Sound effect,Low bin,High bin,Pre-amp;;;01f;m12=2,si=0"; // Circle, Beatsin | ||
| 7532 | |||
| 7533 | |||
| 7534 | ////////////////////// | ||
| 7535 | // ** Noisemove // | ||
| 7536 | ////////////////////// | ||
| 7537 | 23 | uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline | |
| 7538 | 23 | um_data_t *um_data = getAudioData(); | |
| 7539 | 23 | uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | |
| 7540 | |||
| 7541 | 23 | int fadeoutDelay = (256 - SEGMENT.speed) / 96; | |
| 7542 |
6/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 2 times.
|
23 | if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(4+ SEGMENT.speed/4); |
| 7543 | |||
| 7544 | 23 | uint8_t numBins = map(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins. | |
| 7545 |
2/2✓ Branch 0 taken 184 times.
✓ Branch 1 taken 23 times.
|
207 | for (int i=0; i<numBins; i++) { // How many active bins are we using. |
| 7546 | 184 | unsigned locn = perlin16(strip().now*SEGMENT.speed+i*50000, strip().now*SEGMENT.speed); // Get a new pixel location from moving noise. | |
| 7547 | // if SEGLEN equals 1 locn will be always 0, hence we set the first pixel only | ||
| 7548 | 184 | locn = map(locn, 7500, 58000, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. | |
| 7549 |
2/4✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 184 times.
|
184 | SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*64, false, PALETTE_SOLID_WRAP, 0), uint8_t(fftResult[i % 16]*4))); |
| 7550 | } | ||
| 7551 | |||
| 7552 | 23 | return FRAMETIME; | |
| 7553 | } // mode_noisemove() | ||
| 7554 | static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Move speed,Fade rate;!,!;!;01f;m12=0,si=0"; // Pixels, Beatsin | ||
| 7555 | |||
| 7556 | |||
| 7557 | ////////////////////// | ||
| 7558 | // ** Rocktaves // | ||
| 7559 | ////////////////////// | ||
| 7560 | 83 | uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline | |
| 7561 | 83 | um_data_t *um_data = getAudioData(); | |
| 7562 | 83 | float FFT_MajorPeak = *(float*) um_data->u_data[4]; | |
| 7563 | 83 | float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; | |
| 7564 | |||
| 7565 | 83 | SEGMENT.fadeToBlackBy(16); // Just in case something doesn't get faded. | |
| 7566 | |||
| 7567 | 83 | float frTemp = FFT_MajorPeak; | |
| 7568 | 83 | uint8_t octCount = 0; // Octave counter. | |
| 7569 | 83 | uint8_t volTemp = 0; | |
| 7570 | |||
| 7571 | 83 | volTemp = 32.0f + my_magnitude * 1.5f; // brightness = volume (overflows are handled in next lines) | |
| 7572 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 79 times.
|
83 | if (my_magnitude < 48) volTemp = 0; // We need to squelch out the background noise. |
| 7573 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | if (my_magnitude > 144) volTemp = 255; // everything above this is full brightness |
| 7574 | |||
| 7575 |
2/2✓ Branch 0 taken 238 times.
✓ Branch 1 taken 83 times.
|
321 | while ( frTemp > 249 ) { |
| 7576 | 238 | octCount++; // This should go up to 5. | |
| 7577 | 238 | frTemp = frTemp/2; | |
| 7578 | } | ||
| 7579 | |||
| 7580 | 83 | frTemp -= 132.0f; // This should give us a base musical note of C3 | |
| 7581 | 83 | frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255; | |
| 7582 | |||
| 7583 | 83 | unsigned i = map(beatsin8_t(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); | |
| 7584 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | i = constrain(i, 0U, SEGLEN-1U); |
| 7585 |
2/4✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 83 times.
|
83 | SEGMENT.addPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp)); |
| 7586 | |||
| 7587 | 83 | return FRAMETIME; | |
| 7588 | } // mode_rocktaves() | ||
| 7589 | static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12=1,si=0"; // Bar, Beatsin | ||
| 7590 | |||
| 7591 | |||
| 7592 | /////////////////////// | ||
| 7593 | // ** Waterfall // | ||
| 7594 | /////////////////////// | ||
| 7595 | // Combines peak detection with FFT_MajorPeak and FFT_Magnitude. | ||
| 7596 | 23 | uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline | |
| 7597 | // effect can work on single pixels, we just lose the shifting effect | ||
| 7598 | 23 | unsigned dataSize = sizeof(uint32_t) * SEGLEN; | |
| 7599 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed |
| 7600 | 23 | uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); | |
| 7601 | |||
| 7602 | 23 | um_data_t *um_data = getAudioData(); | |
| 7603 | 23 | uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; | |
| 7604 | 23 | float FFT_MajorPeak = *(float*) um_data->u_data[4]; | |
| 7605 | 23 | uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; | |
| 7606 | 23 | uint8_t *binNum = (uint8_t*)um_data->u_data[7]; | |
| 7607 | 23 | float my_magnitude = *(float*) um_data->u_data[5] / 8.0f; | |
| 7608 | |||
| 7609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) |
| 7610 | |||
| 7611 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (SEGENV.call == 0) { |
| 7612 |
2/2✓ Branch 0 taken 262 times.
✓ Branch 1 taken 5 times.
|
267 | for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer |
| 7613 | 5 | SEGENV.aux0 = 255; | |
| 7614 | 5 | SEGMENT.custom1 = *binNum; | |
| 7615 | 5 | SEGMENT.custom2 = *maxVol * 2; | |
| 7616 | } | ||
| 7617 | |||
| 7618 | 23 | *binNum = SEGMENT.custom1; // Select a bin. | |
| 7619 | 23 | *maxVol = SEGMENT.custom2 / 2; // Our volume comparator. | |
| 7620 | |||
| 7621 | 23 | uint8_t secondHand = micros() / (256-SEGMENT.speed)/500 + 1 % 16; | |
| 7622 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
|
23 | if (SEGENV.aux0 != secondHand) { // Triggered millis timing. |
| 7623 | 18 | SEGENV.aux0 = secondHand; | |
| 7624 | |||
| 7625 | //uint8_t pixCol = (log10f((float)FFT_MajorPeak) - 2.26f) * 177; // 10Khz sampling - log10 frequency range is from 2.26 (182hz) to 3.7 (5012hz). Let's scale accordingly. | ||
| 7626 | 18 | uint8_t pixCol = (log10f(FFT_MajorPeak) - 2.26f) * 150; // 22Khz sampling - log10 frequency range is from 2.26 (182hz) to 3.967 (9260hz). Let's scale accordingly. | |
| 7627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (FFT_MajorPeak < 182.0f) pixCol = 0; // handle underflow |
| 7628 | |||
| 7629 | 18 | unsigned k = SEGLEN-1; | |
| 7630 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
|
18 | if (samplePeak) { |
| 7631 | 1 | pixels[k] = (uint32_t)CRGB(CHSV(92,92,92)); | |
| 7632 | } else { | ||
| 7633 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
|
17 | pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude); |
| 7634 | } | ||
| 7635 | 18 | SEGMENT.setPixelColor(k, pixels[k]); | |
| 7636 | // loop will not execute if SEGLEN equals 1 | ||
| 7637 |
2/2✓ Branch 0 taken 960 times.
✓ Branch 1 taken 18 times.
|
978 | for (unsigned i = 0; i < k; i++) { |
| 7638 | 960 | pixels[i] = pixels[i+1]; // shift left | |
| 7639 | 960 | SEGMENT.setPixelColor(i, pixels[i]); | |
| 7640 | } | ||
| 7641 | } | ||
| 7642 | |||
| 7643 | 23 | return FRAMETIME; | |
| 7644 | } // mode_waterfall() | ||
| 7645 | static const char _data_FX_MODE_WATERFALL[] PROGMEM = "Waterfall@!,Adjust color,Select bin,Volume (min);!,!;!;01f;c2=0,m12=2,si=0"; // Circles, Beatsin | ||
| 7646 | |||
| 7647 | |||
| 7648 | #ifndef WLED_DISABLE_2D | ||
| 7649 | ///////////////////////// | ||
| 7650 | // ** 2D GEQ // | ||
| 7651 | ///////////////////////// | ||
| 7652 | 497 | uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. | |
| 7653 |
5/6✓ Branch 0 taken 492 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 492 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 492 times.
|
497 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 7654 | |||
| 7655 | 492 | const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); | |
| 7656 | 492 | const int CENTER_BIN = map(SEGMENT.custom3, 0, 31, 0, 15); | |
| 7657 | 492 | const int cols = SEG_W; | |
| 7658 | 492 | const int rows = SEG_H; | |
| 7659 | |||
| 7660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 492 times.
|
492 | if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed |
| 7661 | 492 | uint16_t *previousBarHeight = reinterpret_cast<uint16_t*>(SEGENV.data); //array of previous bar heights per frequency band | |
| 7662 | |||
| 7663 | 492 | um_data_t *um_data = getAudioData(); | |
| 7664 | 492 | uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | |
| 7665 | |||
| 7666 |
4/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 482 times.
✓ Branch 2 taken 199 times.
✓ Branch 3 taken 10 times.
|
691 | if (SEGENV.call == 0) for (int i=0; i<cols; i++) previousBarHeight[i] = 0; |
| 7667 | |||
| 7668 | 492 | bool rippleTime = false; | |
| 7669 |
2/2✓ Branch 0 taken 483 times.
✓ Branch 1 taken 9 times.
|
492 | if (strip().now - SEGENV.step >= (256U - SEGMENT.intensity)) { |
| 7670 | 483 | SEGENV.step = strip().now; | |
| 7671 | 483 | rippleTime = true; | |
| 7672 | } | ||
| 7673 | |||
| 7674 | 492 | int fadeoutDelay = (256 - SEGMENT.speed) / 64; | |
| 7675 |
6/6✓ Branch 0 taken 14 times.
✓ Branch 1 taken 478 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 485 times.
✓ Branch 5 taken 7 times.
|
492 | if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); |
| 7676 | |||
| 7677 |
2/2✓ Branch 0 taken 8035 times.
✓ Branch 1 taken 492 times.
|
8527 | for (int x=0; x < cols; x++) { |
| 7678 | 8035 | int band = map(x, 0, cols, 0, NUM_BANDS); | |
| 7679 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 7907 times.
|
8035 | if (NUM_BANDS < 16) { |
| 7680 |
1/2✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
|
128 | int startBin = constrain(CENTER_BIN - NUM_BANDS/2, 0, 15 - NUM_BANDS + 1); |
| 7681 |
1/2✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
|
128 | if (NUM_BANDS <= 1) |
| 7682 | 128 | band = CENTER_BIN; // map() does not work for single band | |
| 7683 | else | ||
| 7684 | ✗ | band = map(band, 0, NUM_BANDS - 1, startBin, startBin + NUM_BANDS - 1); | |
| 7685 | } | ||
| 7686 | 8035 | band = constrain(band, 0, 15); | |
| 7687 | 8035 | unsigned colorIndex = band * 17; | |
| 7688 | 8035 | int barHeight = map(fftResult[band], 0, 255, 0, rows); // do not subtract -1 from rows here | |
| 7689 |
2/2✓ Branch 0 taken 5890 times.
✓ Branch 1 taken 2145 times.
|
8035 | if (barHeight > previousBarHeight[x]) previousBarHeight[x] = barHeight; //drive the peak up |
| 7690 | |||
| 7691 | 8035 | uint32_t ledColor = BLACK; | |
| 7692 |
2/2✓ Branch 0 taken 18834 times.
✓ Branch 1 taken 8035 times.
|
26869 | for (int y=0; y < barHeight; y++) { |
| 7693 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18834 times.
|
18834 | if (SEGMENT.check1) //color_vertical / color bars toggle |
| 7694 | ✗ | colorIndex = map(y, 0, rows-1, 0, 255); | |
| 7695 | |||
| 7696 |
2/4✓ Branch 0 taken 18834 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18834 times.
|
18834 | ledColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0); |
| 7697 | 18834 | SEGMENT.setPixelColorXY(x, rows-1 - y, ledColor); | |
| 7698 | } | ||
| 7699 |
2/2✓ Branch 0 taken 6273 times.
✓ Branch 1 taken 1762 times.
|
8035 | if (previousBarHeight[x] > 0) |
| 7700 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6273 times.
|
6273 | SEGMENT.setPixelColorXY(x, rows - previousBarHeight[x], (SEGCOLOR(2) != BLACK) ? SEGCOLOR(2) : ledColor); |
| 7701 | |||
| 7702 |
4/4✓ Branch 0 taken 7822 times.
✓ Branch 1 taken 213 times.
✓ Branch 2 taken 6086 times.
✓ Branch 3 taken 1736 times.
|
8035 | if (rippleTime && previousBarHeight[x]>0) previousBarHeight[x]--; //delay/ripple effect |
| 7703 | } | ||
| 7704 | |||
| 7705 | 492 | return FRAMETIME; | |
| 7706 | } // mode_2DGEQ() | ||
| 7707 | static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ@Fade speed,Ripple decay,# of bands,,Bin,Color bars;!,,Peaks;!;2f;c1=255,c2=64,pal=11,si=0,c3=0"; // Beatsin | ||
| 7708 | |||
| 7709 | |||
| 7710 | ///////////////////////// | ||
| 7711 | // ** 2D Funky plank // | ||
| 7712 | ///////////////////////// | ||
| 7713 | 23 | uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Will Tatam. | |
| 7714 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 7715 | |||
| 7716 | 18 | const int cols = SEG_W; | |
| 7717 | 18 | const int rows = SEG_H; | |
| 7718 | |||
| 7719 | 18 | int NUMB_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); | |
| 7720 | 18 | int barWidth = (cols / NUMB_BANDS); | |
| 7721 | 18 | int bandInc = 1; | |
| 7722 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
|
18 | if (barWidth == 0) { |
| 7723 | // Matrix narrower than fft bands | ||
| 7724 | 5 | barWidth = 1; | |
| 7725 | 5 | bandInc = (NUMB_BANDS / cols); | |
| 7726 | } | ||
| 7727 | |||
| 7728 | 18 | um_data_t *um_data = getAudioData(); | |
| 7729 | 18 | uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | |
| 7730 | |||
| 7731 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (SEGENV.call == 0) { |
| 7732 | 4 | SEGMENT.fill(BLACK); | |
| 7733 | } | ||
| 7734 | |||
| 7735 | 18 | uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 64; | |
| 7736 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | if (SEGENV.aux0 != secondHand) { // Triggered millis timing. |
| 7737 | 15 | SEGENV.aux0 = secondHand; | |
| 7738 | |||
| 7739 | // display values of | ||
| 7740 | 15 | int b = 0; | |
| 7741 |
2/2✓ Branch 0 taken 131 times.
✓ Branch 1 taken 15 times.
|
146 | for (int band = 0; band < NUMB_BANDS; band += bandInc, b++) { |
| 7742 | 131 | int hue = fftResult[band % 16]; | |
| 7743 | 131 | int v = map(fftResult[band % 16], 0, 255, 10, 255); | |
| 7744 |
2/2✓ Branch 0 taken 384 times.
✓ Branch 1 taken 131 times.
|
515 | for (int w = 0; w < barWidth; w++) { |
| 7745 | 384 | int xpos = (barWidth * b) + w; | |
| 7746 |
1/2✓ Branch 0 taken 384 times.
✗ Branch 1 not taken.
|
768 | SEGMENT.setPixelColorXY(xpos, 0, CHSV(hue, 255, v)); |
| 7747 | } | ||
| 7748 | } | ||
| 7749 | |||
| 7750 | // Update the display: | ||
| 7751 |
2/2✓ Branch 0 taken 173 times.
✓ Branch 1 taken 15 times.
|
188 | for (int i = (rows - 1); i > 0; i--) { |
| 7752 |
2/2✓ Branch 0 taken 5336 times.
✓ Branch 1 taken 173 times.
|
5509 | for (int j = (cols - 1); j >= 0; j--) { |
| 7753 | 5336 | SEGMENT.setPixelColorXY(j, i, SEGMENT.getPixelColorXY(j, i-1)); | |
| 7754 | } | ||
| 7755 | } | ||
| 7756 | } | ||
| 7757 | |||
| 7758 | 18 | return FRAMETIME; | |
| 7759 | } // mode_2DFunkyPlank | ||
| 7760 | static const char _data_FX_MODE_2DFUNKYPLANK[] PROGMEM = "Funky Plank@Scroll speed,,# of bands;;;2f;si=0"; // Beatsin | ||
| 7761 | |||
| 7762 | |||
| 7763 | ///////////////////////// | ||
| 7764 | // 2D Akemi // | ||
| 7765 | ///////////////////////// | ||
| 7766 | static uint8_t akemi[] PROGMEM = { | ||
| 7767 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7768 | 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7769 | 0,0,0,0,0,0,0,0,0,0,0,2,2,3,3,3,3,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7770 | 0,0,0,0,0,0,0,0,0,0,2,3,3,0,0,0,0,0,0,3,3,2,0,0,0,0,0,0,0,0,0,0, | ||
| 7771 | 0,0,0,0,0,0,0,0,0,2,3,0,0,0,6,5,5,4,0,0,0,3,2,0,0,0,0,0,0,0,0,0, | ||
| 7772 | 0,0,0,0,0,0,0,0,2,3,0,0,6,6,5,5,5,5,4,4,0,0,3,2,0,0,0,0,0,0,0,0, | ||
| 7773 | 0,0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0,0, | ||
| 7774 | 0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0, | ||
| 7775 | 0,0,0,0,0,0,0,3,2,0,6,5,5,5,5,5,5,5,5,5,5,4,0,2,3,0,0,0,0,0,0,0, | ||
| 7776 | 0,0,0,0,0,0,3,2,3,6,5,5,7,7,5,5,5,5,7,7,5,5,4,3,2,3,0,0,0,0,0,0, | ||
| 7777 | 0,0,0,0,0,2,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,2,0,0,0,0,0, | ||
| 7778 | 0,0,0,0,0,8,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,8,0,0,0,0,0, | ||
| 7779 | 0,0,0,0,0,8,3,1,3,6,5,5,1,1,5,5,5,5,1,1,5,5,4,3,1,3,8,0,0,0,0,0, | ||
| 7780 | 0,0,0,0,0,2,3,1,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,1,3,2,0,0,0,0,0, | ||
| 7781 | 0,0,0,0,0,0,3,2,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,2,3,0,0,0,0,0,0, | ||
| 7782 | 0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,7,7,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0, | ||
| 7783 | 0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0, | ||
| 7784 | 1,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,2, | ||
| 7785 | 0,2,2,2,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,2,2,2,0, | ||
| 7786 | 0,0,0,3,2,0,0,0,6,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,2,2,0,0,0, | ||
| 7787 | 0,0,0,3,2,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,2,3,0,0,0, | ||
| 7788 | 0,0,0,0,3,2,0,0,0,0,3,3,0,3,3,0,0,3,3,0,3,3,0,0,0,0,2,2,0,0,0,0, | ||
| 7789 | 0,0,0,0,3,2,0,0,0,0,3,2,0,3,2,0,0,3,2,0,3,2,0,0,0,0,2,3,0,0,0,0, | ||
| 7790 | 0,0,0,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,2,3,0,0,0,0,0, | ||
| 7791 | 0,0,0,0,0,3,2,2,2,2,0,0,0,3,2,0,0,3,2,0,0,0,3,2,2,2,3,0,0,0,0,0, | ||
| 7792 | 0,0,0,0,0,0,3,3,3,0,0,0,0,3,2,0,0,3,2,0,0,0,0,3,3,3,0,0,0,0,0,0, | ||
| 7793 | 0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7794 | 0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7795 | 0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7796 | 0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7797 | 0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 7798 | 0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | ||
| 7799 | }; | ||
| 7800 | |||
| 7801 | 23 | uint16_t mode_2DAkemi(void) { | |
| 7802 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 7803 | |||
| 7804 | 18 | const int cols = SEG_W; | |
| 7805 | 18 | const int rows = SEG_H; | |
| 7806 | |||
| 7807 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | unsigned counter = (strip().now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; |
| 7808 | 18 | counter = counter >> 8; | |
| 7809 | |||
| 7810 | 18 | const float lightFactor = 0.15f; | |
| 7811 | 18 | const float normalFactor = 0.4f; | |
| 7812 | |||
| 7813 | um_data_t *um_data; | ||
| 7814 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | if (!UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { |
| 7815 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | um_data = simulateSound(SEGMENT.soundSim); |
| 7816 | } | ||
| 7817 | 18 | uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; | |
| 7818 | 18 | float base = fftResult[0]/255.0f; | |
| 7819 | |||
| 7820 | //draw and color Akemi | ||
| 7821 |
4/4✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 223 times.
✓ Branch 2 taken 223 times.
✓ Branch 3 taken 18 times.
|
7002 | for (int y=0; y < rows; y++) for (int x=0; x < cols; x++) { |
| 7822 | CRGB color; | ||
| 7823 | 6761 | CRGB soundColor = CRGB::Orange; | |
| 7824 |
3/6✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6761 times.
✗ Branch 5 not taken.
|
6761 | CRGB faceColor = CRGB(SEGMENT.color_wheel(counter)); |
| 7825 |
1/2✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
|
6761 | CRGB armsAndLegsColor = CRGB(SEGCOLOR(1) > 0 ? SEGCOLOR(1) : 0xFFE0A0); //default warmish white 0xABA8FF; //0xFF52e5;// |
| 7826 | 6761 | uint8_t ak = pgm_read_byte_near(akemi + ((y * 32)/rows) * 32 + (x * 32)/cols); // akemi[(y * 32)/rows][(x * 32)/cols] | |
| 7827 |
9/9✓ Branch 0 taken 561 times.
✓ Branch 1 taken 551 times.
✓ Branch 2 taken 130 times.
✓ Branch 3 taken 122 times.
✓ Branch 4 taken 1066 times.
✓ Branch 5 taken 122 times.
✓ Branch 6 taken 88 times.
✓ Branch 7 taken 26 times.
✓ Branch 8 taken 4095 times.
|
6761 | switch (ak) { |
| 7828 | 561 | case 3: armsAndLegsColor.r *= lightFactor; armsAndLegsColor.g *= lightFactor; armsAndLegsColor.b *= lightFactor; color = armsAndLegsColor; break; //light arms and legs 0x9B9B9B | |
| 7829 | 551 | case 2: armsAndLegsColor.r *= normalFactor; armsAndLegsColor.g *= normalFactor; armsAndLegsColor.b *= normalFactor; color = armsAndLegsColor; break; //normal arms and legs 0x888888 | |
| 7830 | 130 | case 1: color = armsAndLegsColor; break; //dark arms and legs 0x686868 | |
| 7831 | 122 | case 6: faceColor.r *= lightFactor; faceColor.g *= lightFactor; faceColor.b *= lightFactor; color=faceColor; break; //light face 0x31AAFF | |
| 7832 | 1066 | case 5: faceColor.r *= normalFactor; faceColor.g *= normalFactor; faceColor.b *= normalFactor; color=faceColor; break; //normal face 0x0094FF | |
| 7833 | 122 | case 4: color = faceColor; break; //dark face 0x007DC6 | |
| 7834 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
176 | case 7: color = SEGCOLOR(2) > 0 ? SEGCOLOR(2) : 0xFFFFFF; break; //eyes and mouth default white |
| 7835 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 12 times.
|
26 | case 8: if (base > 0.4) {soundColor.r *= base; soundColor.g *= base; soundColor.b *= base; color=soundColor;} else color = armsAndLegsColor; break; |
| 7836 | 8190 | default: color = BLACK; break; | |
| 7837 | } | ||
| 7838 | |||
| 7839 |
7/12✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2048 times.
✓ Branch 5 taken 4713 times.
✓ Branch 6 taken 2048 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2048 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 6761 times.
|
6761 | if (SEGMENT.intensity > 128 && fftResult && fftResult[0] > 128) { //dance if base is high |
| 7840 | ✗ | SEGMENT.setPixelColorXY(x, 0, BLACK); | |
| 7841 | ✗ | SEGMENT.setPixelColorXY(x, y+1, color); | |
| 7842 | } else | ||
| 7843 |
3/6✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6761 times.
✗ Branch 5 not taken.
|
6761 | SEGMENT.setPixelColorXY(x, y, color); |
| 7844 | } | ||
| 7845 | |||
| 7846 | //add geq left and right | ||
| 7847 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | if (um_data && fftResult) { |
| 7848 | 18 | int xMax = cols/8; | |
| 7849 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 18 times.
|
70 | for (int x=0; x < xMax; x++) { |
| 7850 | 52 | unsigned band = map(x, 0, max(xMax,4), 0, 15); // map 0..cols/8 to 16 GEQ bands | |
| 7851 | 52 | band = constrain(band, 0, 15); | |
| 7852 | 52 | int barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32); | |
| 7853 |
7/14✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 52 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 52 times.
✓ Branch 12 taken 52 times.
✗ Branch 13 not taken.
|
52 | uint32_t color = SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0); |
| 7854 | |||
| 7855 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 52 times.
|
232 | for (int y=0; y < barHeight; y++) { |
| 7856 |
3/6✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 180 times.
✗ Branch 5 not taken.
|
180 | SEGMENT.setPixelColorXY(x, rows/2-y, color); |
| 7857 |
3/6✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 180 times.
✗ Branch 5 not taken.
|
180 | SEGMENT.setPixelColorXY(cols-1-x, rows/2-y, color); |
| 7858 | } | ||
| 7859 | } | ||
| 7860 | } | ||
| 7861 | |||
| 7862 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 7863 | } // mode_2DAkemi | ||
| 7864 | static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;2f;si=0"; //beatsin | ||
| 7865 | |||
| 7866 | |||
| 7867 | // Distortion waves - ldirko | ||
| 7868 | // https://editor.soulmatelights.com/gallery/1089-distorsion-waves | ||
| 7869 | // adapted for WLED by @blazoncek | ||
| 7870 | 23 | uint16_t mode_2Ddistortionwaves() { | |
| 7871 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 7872 | |||
| 7873 | 18 | const int cols = SEG_W; | |
| 7874 | 18 | const int rows = SEG_H; | |
| 7875 | |||
| 7876 | 18 | uint8_t speed = SEGMENT.speed/32; | |
| 7877 | 18 | uint8_t scale = SEGMENT.intensity/32; | |
| 7878 | |||
| 7879 | 18 | uint8_t w = 2; | |
| 7880 | |||
| 7881 | 18 | unsigned a = strip().now/32; | |
| 7882 | 18 | unsigned a2 = a/2; | |
| 7883 | 18 | unsigned a3 = a/3; | |
| 7884 | |||
| 7885 | 18 | unsigned cx = beatsin8_t(10-speed,0,cols-1)*scale; | |
| 7886 | 18 | unsigned cy = beatsin8_t(12-speed,0,rows-1)*scale; | |
| 7887 | 18 | unsigned cx1 = beatsin8_t(13-speed,0,cols-1)*scale; | |
| 7888 | 18 | unsigned cy1 = beatsin8_t(15-speed,0,rows-1)*scale; | |
| 7889 | 18 | unsigned cx2 = beatsin8_t(17-speed,0,cols-1)*scale; | |
| 7890 | 18 | unsigned cy2 = beatsin8_t(14-speed,0,rows-1)*scale; | |
| 7891 | |||
| 7892 | 18 | unsigned xoffs = 0; | |
| 7893 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int x = 0; x < cols; x++) { |
| 7894 | 451 | xoffs += scale; | |
| 7895 | 451 | unsigned yoffs = 0; | |
| 7896 | |||
| 7897 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int y = 0; y < rows; y++) { |
| 7898 | 6761 | yoffs += scale; | |
| 7899 | |||
| 7900 | 6761 | byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; | |
| 7901 | 6761 | byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; | |
| 7902 | 6761 | byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; | |
| 7903 | |||
| 7904 | 6761 | byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); | |
| 7905 | 6761 | byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); | |
| 7906 | 6761 | byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); | |
| 7907 | |||
| 7908 | 6761 | valueR = gamma8(cos8_t(valueR)); | |
| 7909 | 6761 | valueG = gamma8(cos8_t(valueG)); | |
| 7910 | 6761 | valueB = gamma8(cos8_t(valueB)); | |
| 7911 | |||
| 7912 | 6761 | SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); | |
| 7913 | } | ||
| 7914 | } | ||
| 7915 | |||
| 7916 | 18 | return FRAMETIME; | |
| 7917 | } | ||
| 7918 | static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2"; | ||
| 7919 | |||
| 7920 | |||
| 7921 | //Soap | ||
| 7922 | //@Stepko | ||
| 7923 | //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick | ||
| 7924 | // adapted for WLED by @blazoncek, optimization by @dedehai | ||
| 7925 | 36 | static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { | |
| 7926 | 72 | const int cols = SEG_W; | |
| 7927 | 36 | const int rows = SEG_H; | |
| 7928 | 40566 | const auto XY = [&](int x, int y) { return x + y * cols; }; | |
| 7929 | 28392 | const auto abs = [](int x) { return x<0 ? -x : x; }; | |
| 7930 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
|
36 | const int tRC = isRow ? rows : cols; // transpose if isRow |
| 7931 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
|
36 | const int tCR = isRow ? cols : rows; // transpose if isRow |
| 7932 |
2/4✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
36 | const int amplitude = max(1, (tCR - 8) >> 3) * (1 + (SEGMENT.custom1 >> 5)); |
| 7933 | 36 | const int shift = 0; //(128 - SEGMENT.custom2)*2; | |
| 7934 | |||
| 7935 |
2/2✓ Branch 0 taken 674 times.
✓ Branch 1 taken 36 times.
|
710 | CRGB ledsbuff[tCR]; |
| 7936 | |||
| 7937 |
2/2✓ Branch 0 taken 674 times.
✓ Branch 1 taken 36 times.
|
710 | for (int i = 0; i < tRC; i++) { |
| 7938 |
2/2✓ Branch 0 taken 223 times.
✓ Branch 1 taken 451 times.
|
674 | int amount = ((int)noise3d[isRow ? i*cols : i] - 128) * amplitude + shift; // use first row/column: XY(0,i)/XY(i,0) |
| 7939 | 674 | int delta = abs(amount) >> 8; | |
| 7940 | 674 | int fraction = abs(amount) & 255; | |
| 7941 |
2/2✓ Branch 0 taken 13522 times.
✓ Branch 1 taken 674 times.
|
14196 | for (int j = 0; j < tCR; j++) { |
| 7942 | int zD, zF; | ||
| 7943 |
2/2✓ Branch 0 taken 9351 times.
✓ Branch 1 taken 4171 times.
|
13522 | if (amount < 0) { |
| 7944 | 9351 | zD = j - delta; | |
| 7945 | 9351 | zF = zD - 1; | |
| 7946 | } else { | ||
| 7947 | 4171 | zD = j + delta; | |
| 7948 | 4171 | zF = zD + 1; | |
| 7949 | } | ||
| 7950 | 13522 | int yA = abs(zD)%tCR; | |
| 7951 | 13522 | int yB = abs(zF)%tCR; | |
| 7952 | 13522 | int xA = i; | |
| 7953 | 13522 | int xB = i; | |
| 7954 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 6761 times.
|
13522 | if (isRow) { |
| 7955 | 6761 | std::swap(xA,yA); | |
| 7956 | 6761 | std::swap(xB,yB); | |
| 7957 | } | ||
| 7958 | 13522 | const int indxA = XY(xA,yA); | |
| 7959 | 13522 | const int indxB = XY(xB,yB); | |
| 7960 | CRGB PixelA; | ||
| 7961 | CRGB PixelB; | ||
| 7962 |
4/4✓ Branch 0 taken 12074 times.
✓ Branch 1 taken 1448 times.
✓ Branch 2 taken 12054 times.
✓ Branch 3 taken 20 times.
|
13522 | if ((zD >= 0) && (zD < tCR)) PixelA = pixels[indxA]; |
| 7963 |
1/2✓ Branch 0 taken 1468 times.
✗ Branch 1 not taken.
|
1468 | else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[indxA]*3); |
| 7964 |
4/4✓ Branch 0 taken 11646 times.
✓ Branch 1 taken 1876 times.
✓ Branch 2 taken 11429 times.
✓ Branch 3 taken 217 times.
|
13522 | if ((zF >= 0) && (zF < tCR)) PixelB = pixels[indxB]; |
| 7965 |
1/2✓ Branch 0 taken 2093 times.
✗ Branch 1 not taken.
|
2093 | else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[indxB]*3); |
| 7966 |
3/6✓ Branch 0 taken 13522 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13522 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13522 times.
|
27044 | ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); |
| 7967 | } | ||
| 7968 |
2/2✓ Branch 0 taken 13522 times.
✓ Branch 1 taken 674 times.
|
14196 | for (int j = 0; j < tCR; j++) { |
| 7969 | 13522 | CRGB c = ledsbuff[j]; | |
| 7970 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 6761 times.
|
13522 | if (isRow) std::swap(j,i); |
| 7971 |
3/6✓ Branch 0 taken 13522 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13522 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13522 times.
✗ Branch 5 not taken.
|
13522 | SEGMENT.setPixelColorXY(i, j, pixels[XY(i,j)] = c); |
| 7972 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 6761 times.
|
13522 | if (isRow) std::swap(j,i); |
| 7973 | } | ||
| 7974 | } | ||
| 7975 | 72 | } | |
| 7976 | |||
| 7977 | 23 | uint16_t mode_2Dsoap() { | |
| 7978 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 7979 | |||
| 7980 | 18 | const int cols = SEG_W; | |
| 7981 | 18 | const int rows = SEG_H; | |
| 7982 | 15079 | const auto XY = [&](int x, int y) { return x + y * cols; }; | |
| 7983 | |||
| 7984 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | const size_t segSize = SEGMENT.width() * SEGMENT.height(); // prevent reallocation if mirrored or grouped |
| 7985 | 18 | const size_t dataSize = segSize * (sizeof(uint8_t) + sizeof(CRGB)); // pixels and noise | |
| 7986 |
4/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
18 | if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed |
| 7987 | |||
| 7988 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t *noise3d = reinterpret_cast<uint8_t*>(SEGENV.data); |
| 7989 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | CRGB *pixels = reinterpret_cast<CRGB*>(SEGENV.data + segSize * sizeof(uint8_t)); |
| 7990 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t *noisecoord = reinterpret_cast<uint32_t*>(SEGENV.data + dataSize); // x, y, z coordinates |
| 7991 | 18 | const uint32_t scale32_x = 160000U/cols; | |
| 7992 | 18 | const uint32_t scale32_y = 160000U/rows; | |
| 7993 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2; |
| 7994 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
|
18 | const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes |
| 7995 | |||
| 7996 |
6/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 4 times.
|
30 | if (SEGENV.call == 0) for (int i = 0; i < 3; i++) noisecoord[i] = hw_random(); // init |
| 7997 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 14 times.
|
56 | else for (int i = 0; i < 3; i++) noisecoord[i] += mov; |
| 7998 | |||
| 7999 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int i = 0; i < cols; i++) { |
| 8000 | 451 | int32_t ioffset = scale32_x * (i - cols / 2); | |
| 8001 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int j = 0; j < rows; j++) { |
| 8002 | 6761 | int32_t joffset = scale32_y * (j - rows / 2); | |
| 8003 |
1/2✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
|
6761 | uint8_t data = perlin16(noisecoord[0] + ioffset, noisecoord[1] + joffset, noisecoord[2]) >> 8; |
| 8004 | 20283 | noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness); | |
| 8005 | } | ||
| 8006 | } | ||
| 8007 | // init also if dimensions changed | ||
| 8008 |
12/20✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 14 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 14 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 14 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 14 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 14 times.
|
18 | if (SEGENV.call == 0 || SEGMENT.aux0 != cols || SEGMENT.aux1 != rows) { |
| 8009 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGMENT.aux0 = cols; |
| 8010 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGMENT.aux1 = rows; |
| 8011 |
2/2✓ Branch 0 taken 103 times.
✓ Branch 1 taken 4 times.
|
107 | for (int i = 0; i < cols; i++) { |
| 8012 |
2/2✓ Branch 0 taken 1557 times.
✓ Branch 1 taken 103 times.
|
1660 | for (int j = 0; j < rows; j++) { |
| 8013 |
4/8✓ Branch 0 taken 1557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1557 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1557 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1557 times.
✗ Branch 7 not taken.
|
1557 | SEGMENT.setPixelColorXY(i, j, ColorFromPalette(SEGPALETTE,~noise3d[XY(i,j)]*3)); |
| 8014 | } | ||
| 8015 | } | ||
| 8016 | } | ||
| 8017 | |||
| 8018 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | soapPixels(true, noise3d, pixels); // rows |
| 8019 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | soapPixels(false, noise3d, pixels); // cols |
| 8020 | |||
| 8021 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8022 | } | ||
| 8023 | static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; | ||
| 8024 | |||
| 8025 | |||
| 8026 | //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 | ||
| 8027 | //Octopus (https://editor.soulmatelights.com/gallery/671-octopus) | ||
| 8028 | //Stepko and Sutaburosu | ||
| 8029 | // adapted for WLED by @blazoncek | ||
| 8030 | 23 | uint16_t mode_2Doctopus() { | |
| 8031 |
9/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 8032 | |||
| 8033 | 18 | const int cols = SEG_W; | |
| 8034 | 18 | const int rows = SEG_H; | |
| 8035 | 16636 | const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; | |
| 8036 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | const uint8_t mapp = 180 / MAX(cols,rows); |
| 8037 | |||
| 8038 | typedef struct { | ||
| 8039 | uint8_t angle; | ||
| 8040 | uint8_t radius; | ||
| 8041 | } map_t; | ||
| 8042 | |||
| 8043 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(map_t); // prevent reallocation if mirrored or grouped |
| 8044 |
4/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
18 | if (!SEGENV.allocateData(dataSize + 2)) return mode_static(); //allocation failed |
| 8045 | |||
| 8046 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | map_t *rMap = reinterpret_cast<map_t*>(SEGENV.data); |
| 8047 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t *offsX = reinterpret_cast<uint8_t*>(SEGENV.data + dataSize); |
| 8048 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t *offsY = reinterpret_cast<uint8_t*>(SEGENV.data + dataSize + 1); |
| 8049 | |||
| 8050 | // re-init if SEGMENT dimensions or offset changed | ||
| 8051 |
18/32✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 14 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 14 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 14 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 14 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 14 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 14 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 14 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 14 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 14 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 14 times.
✓ Branch 30 taken 4 times.
✓ Branch 31 taken 14 times.
|
18 | if (SEGENV.call == 0 || SEGENV.aux0 != cols || SEGENV.aux1 != rows || SEGMENT.custom1 != *offsX || SEGMENT.custom2 != *offsY) { |
| 8052 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.step = 0; // t |
| 8053 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux0 = cols; |
| 8054 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux1 = rows; |
| 8055 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | *offsX = SEGMENT.custom1; |
| 8056 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | *offsY = SEGMENT.custom2; |
| 8057 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | const int C_X = (cols / 2) + ((SEGMENT.custom1 - 128)*cols)/255; |
| 8058 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; |
| 8059 |
2/2✓ Branch 0 taken 103 times.
✓ Branch 1 taken 4 times.
|
107 | for (int x = 0; x < cols; x++) { |
| 8060 |
2/2✓ Branch 0 taken 1557 times.
✓ Branch 1 taken 103 times.
|
1660 | for (int y = 0; y < rows; y++) { |
| 8061 | 1557 | int dx = (x - C_X); | |
| 8062 | 1557 | int dy = (y - C_Y); | |
| 8063 |
1/2✓ Branch 0 taken 1557 times.
✗ Branch 1 not taken.
|
1557 | rMap[XY(x, y)].angle = int(40.7436f * atan2_t(dy, dx)); // avoid 128*atan2()/PI |
| 8064 | 1557 | rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu | |
| 8065 | } | ||
| 8066 | } | ||
| 8067 | } | ||
| 8068 | |||
| 8069 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | SEGENV.step += SEGMENT.speed / 32 + 1; // 1-4 range |
| 8070 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int x = 0; x < cols; x++) { |
| 8071 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int y = 0; y < rows; y++) { |
| 8072 | 6761 | byte angle = rMap[XY(x,y)].angle; | |
| 8073 | 6761 | byte radius = rMap[XY(x,y)].radius; | |
| 8074 | //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); | ||
| 8075 |
8/16✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6761 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6761 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6761 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6761 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6761 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6761 times.
✗ Branch 15 not taken.
|
6761 | unsigned intensity = sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); |
| 8076 | 6761 | intensity = map((intensity*intensity) & 0xFFFF, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display | |
| 8077 |
6/12✓ Branch 0 taken 6761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6761 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6761 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6761 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6761 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6761 times.
✗ Branch 11 not taken.
|
6761 | SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity)); |
| 8078 | } | ||
| 8079 | } | ||
| 8080 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8081 | } | ||
| 8082 | static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs,fasttan;;!;2;"; | ||
| 8083 | |||
| 8084 | |||
| 8085 | //Waving Cell | ||
| 8086 | //@Stepko (https://editor.soulmatelights.com/gallery/1704-wavingcells) | ||
| 8087 | // adapted for WLED by @blazoncek, improvements by @dedehai | ||
| 8088 | 23 | uint16_t mode_2Dwavingcell() { | |
| 8089 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (!strip().isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up |
| 8090 | |||
| 8091 | 18 | const int cols = SEG_W; | |
| 8092 | 18 | const int rows = SEG_H; | |
| 8093 | |||
| 8094 | 18 | uint32_t t = (strip().now*(SEGMENT.speed + 1))>>3; | |
| 8095 | 18 | uint32_t aX = SEGMENT.custom1/16 + 9; | |
| 8096 | 18 | uint32_t aY = SEGMENT.custom2/16 + 1; | |
| 8097 | 18 | uint32_t aZ = SEGMENT.custom3 + 1; | |
| 8098 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 18 times.
|
469 | for (int x = 0; x < cols; x++) { |
| 8099 |
2/2✓ Branch 0 taken 6761 times.
✓ Branch 1 taken 451 times.
|
7212 | for (int y = 0; y < rows; y++) { |
| 8100 | 6761 | uint32_t wave = sin8_t((x * aX) + sin8_t((((y<<8) + t) * aY)>>8)) + cos8_t(y * aZ); // bit shifts to increase temporal resolution | |
| 8101 | 6761 | uint8_t colorIndex = wave + (t>>(8-(SEGMENT.check2*3))); | |
| 8102 | 6761 | SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, colorIndex)); | |
| 8103 | } | ||
| 8104 | } | ||
| 8105 | 18 | SEGMENT.blur(SEGMENT.intensity); | |
| 8106 | 18 | return FRAMETIME; | |
| 8107 | } | ||
| 8108 | static const char _data_FX_MODE_2DWAVINGCELL[] PROGMEM = "Waving Cell@!,Blur,Amplitude 1,Amplitude 2,Amplitude 3,,Flow;;!;2;ix=0"; | ||
| 8109 | |||
| 8110 | #ifndef WLED_DISABLE_PARTICLESYSTEM2D | ||
| 8111 | |||
| 8112 | /* | ||
| 8113 | Particle System Vortex | ||
| 8114 | Particles sprayed from center with a rotating spray | ||
| 8115 | Uses palette for particle color | ||
| 8116 | by DedeHai (Damian Schneider) | ||
| 8117 | */ | ||
| 8118 | #define NUMBEROFSOURCES 8 | ||
| 8119 | 23 | uint16_t mode_particlevortex(void) { | |
| 8120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (SEGLEN == 1) |
| 8121 | ✗ | return mode_static(); | |
| 8122 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8123 | uint32_t i, j; | ||
| 8124 | |||
| 8125 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8126 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, NUMBEROFSOURCES)) |
| 8127 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed |
| 8128 | #ifdef ESP8266 | ||
| 8129 | PartSys->setMotionBlur(180); | ||
| 8130 | #else | ||
| 8131 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setMotionBlur(130); |
| 8132 | #endif | ||
| 8133 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
|
36 | for (i = 0; i < min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); i++) { |
| 8134 | 32 | PartSys->sources[i].source.x = (PartSys->maxX + 1) >> 1; // center | |
| 8135 | 32 | PartSys->sources[i].source.y = (PartSys->maxY + 1) >> 1; // center | |
| 8136 | 32 | PartSys->sources[i].maxLife = 900; | |
| 8137 | 32 | PartSys->sources[i].minLife = 800; | |
| 8138 | } | ||
| 8139 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); |
| 8140 | } | ||
| 8141 | else | ||
| 8142 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8143 | |||
| 8144 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8145 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8146 | |||
| 8147 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8148 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t spraycount = min(PartSys->numSources, (uint32_t)(1 + (SEGMENT.custom1 >> 5))); // number of sprays to display, 1-8 |
| 8149 | #ifdef ESP8266 | ||
| 8150 | for (i = 1; i < 4; i++) { // need static particles in the center to reduce blinking (would be black every other frame without this hack), just set them there fixed | ||
| 8151 | int partindex = (int)PartSys->usedParticles - (int)i; | ||
| 8152 | if (partindex >= 0) { | ||
| 8153 | PartSys->particles[partindex].x = (PartSys->maxX + 1) >> 1; // center | ||
| 8154 | PartSys->particles[partindex].y = (PartSys->maxY + 1) >> 1; // center | ||
| 8155 | PartSys->particles[partindex].sat = 230; | ||
| 8156 | PartSys->particles[partindex].ttl = 256; //keep alive | ||
| 8157 | } | ||
| 8158 | } | ||
| 8159 | #endif | ||
| 8160 | |||
| 8161 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check1) |
| 8162 | ✗ | PartSys->setSmearBlur(90); // enable smear blur | |
| 8163 | else | ||
| 8164 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->setSmearBlur(0); // disable smear blur |
| 8165 | |||
| 8166 | // update colors of the sprays | ||
| 8167 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 18 times.
|
124 | for (i = 0; i < spraycount; i++) { |
| 8168 | 106 | uint32_t coloroffset = 0xFF / spraycount; | |
| 8169 | 106 | PartSys->sources[i].source.hue = coloroffset * i; | |
| 8170 | } | ||
| 8171 | |||
| 8172 | // set rotation direction and speed | ||
| 8173 | // can use direction flag to determine current direction | ||
| 8174 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | bool direction = SEGMENT.check2; //no automatic direction change, set it to flag |
| 8175 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | int32_t currentspeed = (int32_t)SEGENV.step; // make a signed integer out of step |
| 8176 | |||
| 8177 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.custom2 > 0) { // automatic direction change enabled |
| 8178 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | uint32_t changeinterval = 1040 - ((uint32_t)SEGMENT.custom2 << 2); |
| 8179 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | direction = SEGENV.aux1 & 0x01; //set direction according to flag |
| 8180 | |||
| 8181 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if (SEGMENT.check3) // random interval |
| 8182 | ✗ | changeinterval = 20 + changeinterval + hw_random16(changeinterval); | |
| 8183 | |||
| 8184 |
4/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
|
4 | if (SEGMENT.call % changeinterval == 0) { //flip direction on next frame |
| 8185 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | SEGENV.aux1 |= 0x02; // set the update flag (for random interval update) |
| 8186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (direction) |
| 8187 | ✗ | SEGENV.aux1 &= ~0x01; // clear the direction flag | |
| 8188 | else | ||
| 8189 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | SEGENV.aux1 |= 0x01; // set the direction flag |
| 8190 | } | ||
| 8191 | } | ||
| 8192 | |||
| 8193 |
4/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | int32_t targetspeed = (direction ? 1 : -1) * (SEGMENT.speed << 3); |
| 8194 | 18 | int32_t speeddiff = targetspeed - currentspeed; | |
| 8195 | 18 | int32_t speedincrement = speeddiff / 50; | |
| 8196 | |||
| 8197 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
|
18 | if (speedincrement == 0) { //if speeddiff is not zero, make the increment at least 1 so it reaches target speed |
| 8198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (speeddiff < 0) |
| 8199 | ✗ | speedincrement = -1; | |
| 8200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | else if (speeddiff > 0) |
| 8201 | ✗ | speedincrement = 1; | |
| 8202 | } | ||
| 8203 | |||
| 8204 | 18 | currentspeed += speedincrement; | |
| 8205 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | SEGENV.aux0 += currentspeed; |
| 8206 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | SEGENV.step = (uint32_t)currentspeed; //save it back |
| 8207 | |||
| 8208 | 18 | uint16_t angleoffset = 0xFFFF / spraycount; // angle offset for an even distribution | |
| 8209 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t skip = PS_P_HALFRADIUS / (SEGMENT.intensity + 1) + 1; // intensity is emit speed, emit less on low speeds |
| 8210 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 3 times.
|
18 | if (SEGMENT.call % skip == 0) { |
| 8211 | 15 | j = hw_random16(spraycount); // start with random spray so all get a chance to emit a particle if maximum number of particles alive is reached. | |
| 8212 |
2/2✓ Branch 0 taken 103 times.
✓ Branch 1 taken 15 times.
|
118 | for (i = 0; i < spraycount; i++) { // emit one particle per spray (if available) |
| 8213 |
2/4✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103 times.
✗ Branch 3 not taken.
|
103 | PartSys->sources[j].var = (SEGMENT.custom3 >> 1); //update speed variation |
| 8214 | #ifdef ESP8266 | ||
| 8215 | if (SEGMENT.call & 0x01) // every other frame, do not emit to save particles | ||
| 8216 | #endif | ||
| 8217 |
5/10✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103 times.
✗ Branch 9 not taken.
|
103 | PartSys->angleEmit(PartSys->sources[j], SEGENV.aux0 + angleoffset * j, (SEGMENT.intensity >> 2)+1); |
| 8218 | 103 | j = (j + 1) % spraycount; | |
| 8219 | } | ||
| 8220 | } | ||
| 8221 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); //update all particles and render to frame |
| 8222 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8223 | } | ||
| 8224 | #undef NUMBEROFSOURCES | ||
| 8225 | static const char _data_FX_MODE_PARTICLEVORTEX[] PROGMEM = "PS Vortex@Rotation Speed,Particle Speed,Arms,Flip,Nozzle,Smear,Direction,Random Flip;;!;2;pal=27,c1=200,c2=0,c3=0"; | ||
| 8226 | |||
| 8227 | /* | ||
| 8228 | Particle Fireworks | ||
| 8229 | Rockets shoot up and explode in a random color, sometimes in a defined pattern | ||
| 8230 | by DedeHai (Damian Schneider) | ||
| 8231 | */ | ||
| 8232 | #define NUMBEROFSOURCES 8 | ||
| 8233 | |||
| 8234 | 23 | uint16_t mode_particlefireworks(void) { | |
| 8235 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8236 | uint32_t numRockets; | ||
| 8237 | |||
| 8238 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8239 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, NUMBEROFSOURCES)) |
| 8240 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed |
| 8241 | |||
| 8242 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return (except on top, taken care of by gravity setting) |
| 8243 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallHardness(120); // ground bounce is fixed |
| 8244 | 4 | numRockets = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); | |
| 8245 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
|
36 | for (uint32_t j = 0; j < numRockets; j++) { |
| 8246 | 32 | PartSys->sources[j].source.ttl = 500 * j; // first rocket starts immediately, others follow soon | |
| 8247 | 32 | PartSys->sources[j].source.vy = -1; // at negative speed, no particles are emitted and if rocket dies, it will be relaunched | |
| 8248 | } | ||
| 8249 | } | ||
| 8250 | else | ||
| 8251 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8252 | |||
| 8253 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8254 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8255 | |||
| 8256 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8257 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | numRockets = map(SEGMENT.speed, 0 , 255, 4, min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES)); |
| 8258 | |||
| 8259 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check1); |
| 8260 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceY(SEGMENT.check2); |
| 8261 |
6/12✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
|
18 | PartSys->setGravity(map(SEGMENT.custom3, 0, 31, SEGMENT.check2 ? 1 : 0, 10)); // if bounded, set gravity to minimum of 1 or they will bounce at top |
| 8262 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setMotionBlur(map(SEGMENT.custom2, 0, 255, 0, 245)); // anable motion blur |
| 8263 | |||
| 8264 | // update the rockets, set the speed state | ||
| 8265 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 18 times.
|
126 | for (uint32_t j = 0; j < numRockets; j++) { |
| 8266 |
1/2✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
|
108 | PartSys->applyGravity(PartSys->sources[j].source); |
| 8267 |
1/2✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
|
108 | PartSys->particleMoveUpdate(PartSys->sources[j].source, PartSys->sources[j].sourceFlags); |
| 8268 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 103 times.
|
108 | if (PartSys->sources[j].source.ttl == 0) { |
| 8269 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | if (PartSys->sources[j].source.vy > 0) { // rocket has died and is moving up. stop it so it will explode (is handled in the code below) |
| 8270 | 1 | PartSys->sources[j].source.vy = 0; | |
| 8271 | } | ||
| 8272 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | else if (PartSys->sources[j].source.vy < 0) { // rocket is exploded and time is up (ttl=0 and negative speed), relaunch it |
| 8273 | 4 | PartSys->sources[j].source.y = PS_P_RADIUS; // start from bottom | |
| 8274 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->sources[j].source.x = (PartSys->maxX >> 2) + hw_random(PartSys->maxX >> 1); // centered half |
| 8275 |
4/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
4 | PartSys->sources[j].source.vy = (SEGMENT.custom3) + hw_random16(SEGMENT.custom1 >> 3) + 5; // rocket speed TODO: need to adjust for segment height |
| 8276 | 4 | PartSys->sources[j].source.vx = hw_random16(7) - 3; // not perfectly straight up | |
| 8277 | 4 | PartSys->sources[j].source.sat = 30; // low saturation -> exhaust is off-white | |
| 8278 |
4/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
4 | PartSys->sources[j].source.ttl = hw_random16(SEGMENT.custom1) + (SEGMENT.custom1 >> 1); // set fuse time |
| 8279 | 4 | PartSys->sources[j].maxLife = 40; // exhaust particle life | |
| 8280 | 4 | PartSys->sources[j].minLife = 10; | |
| 8281 | 4 | PartSys->sources[j].vx = 0; // emitting speed | |
| 8282 | 4 | PartSys->sources[j].vy = -5; // emitting speed | |
| 8283 | 4 | PartSys->sources[j].var = 4; // speed variation around vx,vy (+/- var) | |
| 8284 | } | ||
| 8285 | } | ||
| 8286 | } | ||
| 8287 | // check each rocket's state and emit particles according to its state: moving up = emit exhaust, at top = explode; falling down = standby time | ||
| 8288 | uint32_t emitparticles, frequency, baseangle, hueincrement; // number of particles to emit for each rocket's state | ||
| 8289 | // variables for circular explosions | ||
| 8290 | [[maybe_unused]] int32_t speed, currentspeed, speedvariation, percircle; | ||
| 8291 | 18 | int32_t counter = 0; | |
| 8292 | [[maybe_unused]] uint16_t angle; | ||
| 8293 | [[maybe_unused]] unsigned angleincrement; | ||
| 8294 | 18 | bool circularexplosion = false; | |
| 8295 | |||
| 8296 | // emit particles for each rocket | ||
| 8297 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 18 times.
|
126 | for (uint32_t j = 0; j < numRockets; j++) { |
| 8298 | // determine rocket state by its speed: | ||
| 8299 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 93 times.
|
108 | if (PartSys->sources[j].source.vy > 0) { // moving up, emit exhaust |
| 8300 | 15 | emitparticles = 1; | |
| 8301 | } | ||
| 8302 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1 times.
|
93 | else if (PartSys->sources[j].source.vy < 0) { // falling down, standby time |
| 8303 | 92 | emitparticles = 0; | |
| 8304 | } | ||
| 8305 | else { // speed is zero, explode! | ||
| 8306 | 1 | PartSys->sources[j].source.hue = hw_random16(); // random color | |
| 8307 | 1 | PartSys->sources[j].source.sat = hw_random16(55) + 200; | |
| 8308 | 1 | PartSys->sources[j].maxLife = 200; | |
| 8309 | 1 | PartSys->sources[j].minLife = 100; | |
| 8310 |
4/8✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | PartSys->sources[j].source.ttl = hw_random16((2000 - ((uint32_t)SEGMENT.speed << 2))) + 550 - (SEGMENT.speed << 1); // standby time til next launch |
| 8311 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | PartSys->sources[j].var = ((SEGMENT.intensity >> 4) + 5); // speed variation around vx,vy (+/- var) |
| 8312 | 1 | PartSys->sources[j].source.vy = -1; // set speed negative so it will emit no more particles after this explosion until relaunch | |
| 8313 | #ifdef ESP8266 | ||
| 8314 | emitparticles = hw_random16(SEGMENT.intensity >> 3) + (SEGMENT.intensity >> 3) + 5; // defines the size of the explosion | ||
| 8315 | #else | ||
| 8316 |
4/8✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | emitparticles = hw_random16(SEGMENT.intensity >> 2) + (SEGMENT.intensity >> 2) + 5; // defines the size of the explosion |
| 8317 | #endif | ||
| 8318 | |||
| 8319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (random16() & 1) { // 50% chance for circular explosion |
| 8320 | ✗ | circularexplosion = true; | |
| 8321 | ✗ | speed = 2 + hw_random16(3) + ((SEGMENT.intensity >> 6)); | |
| 8322 | ✗ | currentspeed = speed; | |
| 8323 | ✗ | angleincrement = 2730 + hw_random16(5461); // minimum 15° + random(30°) | |
| 8324 | ✗ | angle = hw_random16(); // random start angle | |
| 8325 | ✗ | baseangle = angle; // save base angle for modulation | |
| 8326 | ✗ | percircle = 0xFFFF / angleincrement + 1; // number of particles to make complete circles | |
| 8327 | ✗ | hueincrement = hw_random16() & 127; // &127 is equivalent to %128 | |
| 8328 | ✗ | int circles = 1 + hw_random16(3) + ((SEGMENT.intensity >> 6)); | |
| 8329 | ✗ | frequency = hw_random16() & 127; // modulation frequency (= "waves per circle"), x.4 fixed point | |
| 8330 | ✗ | emitparticles = percircle * circles; | |
| 8331 | ✗ | PartSys->sources[j].var = angle & 1; // 0 or 1 variation, angle is random | |
| 8332 | } | ||
| 8333 | } | ||
| 8334 | uint32_t i; | ||
| 8335 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 108 times.
|
128 | for (i = 0; i < emitparticles; i++) { |
| 8336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (circularexplosion) { |
| 8337 | ✗ | int32_t sineMod = 0xEFFF + sin16_t((uint16_t)(((angle * frequency) >> 4) + baseangle)); // shifted to positive values | |
| 8338 | ✗ | currentspeed = (speed/2 + ((sineMod * speed) >> 16)) >> 1; // sine modulation on speed based on emit angle | |
| 8339 | ✗ | PartSys->angleEmit(PartSys->sources[j], angle, currentspeed); // note: compiler warnings can be ignored, variables are set just above | |
| 8340 | ✗ | counter++; | |
| 8341 | ✗ | if (counter > percircle) { // full circle completed, increase speed | |
| 8342 | ✗ | counter = 0; | |
| 8343 | ✗ | speed += 3 + ((SEGMENT.intensity >> 6)); // increase speed to form a second wave | |
| 8344 | ✗ | PartSys->sources[j].source.hue += hueincrement; // new color for next circle | |
| 8345 | ✗ | PartSys->sources[j].source.sat = 100 + hw_random16(156); | |
| 8346 | } | ||
| 8347 | ✗ | angle += angleincrement; // set angle for next particle | |
| 8348 | } | ||
| 8349 | else { // random explosion or exhaust | ||
| 8350 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | PartSys->sprayEmit(PartSys->sources[j]); |
| 8351 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if ((j % 3) == 0) { |
| 8352 | 20 | PartSys->sources[j].source.hue = hw_random16(); // random color for each particle (this is also true for exhaust, but that is white anyways) | |
| 8353 | } | ||
| 8354 | } | ||
| 8355 | } | ||
| 8356 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 16 times.
|
108 | if (i == 0) // no particles emitted, this rocket is falling |
| 8357 | 92 | PartSys->sources[j].source.y = 1000; // reset position so gravity wont pull it to the ground and bounce it (vy MUST stay negative until relaunch) | |
| 8358 | 108 | circularexplosion = false; // reset for next rocket | |
| 8359 | } | ||
| 8360 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check3) { // fast speed, move particles twice |
| 8361 | ✗ | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { | |
| 8362 | ✗ | PartSys->particleMoveUpdate(PartSys->particles[i], PartSys->particleFlags[i], nullptr, nullptr); | |
| 8363 | } | ||
| 8364 | } | ||
| 8365 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8366 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8367 | } | ||
| 8368 | #undef NUMBEROFSOURCES | ||
| 8369 | static const char _data_FX_MODE_PARTICLEFIREWORKS[] PROGMEM = "PS Fireworks@Launches,Explosion Size,Fuse,Blur,Gravity,Cylinder,Ground,Fast;;!;2;pal=11,ix=50,c1=40,c2=0,c3=12"; | ||
| 8370 | |||
| 8371 | /* | ||
| 8372 | Particle Volcano | ||
| 8373 | Particles are sprayed from below, spray moves back and forth if option is set | ||
| 8374 | Uses palette for particle color | ||
| 8375 | by DedeHai (Damian Schneider) | ||
| 8376 | */ | ||
| 8377 | #define NUMBEROFSOURCES 1 | ||
| 8378 | 23 | uint16_t mode_particlevolcano(void) { | |
| 8379 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8380 | PSsettings2D volcanosettings; | ||
| 8381 | 23 | volcanosettings.asByte = 0b00000100; // PS settings for volcano movement: bounceX is enabled | |
| 8382 | uint8_t numSprays; // note: so far only one tested but more is possible | ||
| 8383 | 23 | uint32_t i = 0; | |
| 8384 | |||
| 8385 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8386 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, NUMBEROFSOURCES)) // init, no additional data needed |
| 8387 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8388 | |||
| 8389 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceY(true); |
| 8390 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setGravity(); // enable with default gforce |
| 8391 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return (except on top, taken care of by gravity setting) |
| 8392 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setMotionBlur(230); // anable motion blur |
| 8393 | |||
| 8394 | 4 | numSprays = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); // number of sprays | |
| 8395 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | for (i = 0; i < numSprays; i++) { |
| 8396 | 4 | PartSys->sources[i].source.hue = hw_random16(); | |
| 8397 | 4 | PartSys->sources[i].source.x = PartSys->maxX / (numSprays + 1) * (i + 1); // distribute evenly | |
| 8398 | 4 | PartSys->sources[i].maxLife = 300; // lifetime in frames | |
| 8399 | 4 | PartSys->sources[i].minLife = 250; | |
| 8400 | 4 | PartSys->sources[i].sourceFlags.collide = true; // seeded particles will collide (if enabled) | |
| 8401 | 4 | PartSys->sources[i].sourceFlags.perpetual = true; // source never dies | |
| 8402 | } | ||
| 8403 | } | ||
| 8404 | else | ||
| 8405 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8406 | |||
| 8407 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8408 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8409 | |||
| 8410 | 18 | numSprays = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); // number of volcanoes | |
| 8411 | |||
| 8412 | // change source emitting color from time to time, emit one particle per spray | ||
| 8413 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 9 times.
|
18 | if (SEGMENT.call % (11 - (SEGMENT.intensity / 25)) == 0) { // every nth frame, cycle color and emit particles (and update the sources) |
| 8414 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
|
18 | for (i = 0; i < numSprays; i++) { |
| 8415 | 9 | PartSys->sources[i].source.y = PS_P_RADIUS + 5; // reset to just above the lower edge that is allowed for bouncing particles, if zero, particles already 'bounce' at start and loose speed. | |
| 8416 | 9 | PartSys->sources[i].source.vy = 0; //reset speed (so no extra particlesettin is required to keep the source 'afloat') | |
| 8417 | 9 | PartSys->sources[i].source.hue++; // = hw_random16(); //change hue of spray source (note: random does not look good) | |
| 8418 |
3/10✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
|
9 | PartSys->sources[i].source.vx = PartSys->sources[i].source.vx > 0 ? (SEGMENT.custom1 >> 2) : -(SEGMENT.custom1 >> 2); // set moving speed but keep the direction given by PS |
| 8419 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | PartSys->sources[i].vy = SEGMENT.speed >> 2; // emitting speed (upwards) |
| 8420 | 9 | PartSys->sources[i].vx = 0; | |
| 8421 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | PartSys->sources[i].var = SEGMENT.custom3 >> 1; // emiting variation = nozzle size (custom 3 goes from 0-31) |
| 8422 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | PartSys->sprayEmit(PartSys->sources[i]); |
| 8423 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | PartSys->setWallHardness(255); // full hardness for source bounce |
| 8424 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | PartSys->particleMoveUpdate(PartSys->sources[i].source, PartSys->sources[i].sourceFlags, &volcanosettings); //move the source |
| 8425 | } | ||
| 8426 | } | ||
| 8427 | |||
| 8428 | // Particle System settings | ||
| 8429 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8430 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setColorByAge(SEGMENT.check1); |
| 8431 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(SEGMENT.check2); |
| 8432 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWallHardness(SEGMENT.custom2); |
| 8433 | |||
| 8434 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check3) // collisions enabled |
| 8435 | ✗ | PartSys->enableParticleCollisions(true, SEGMENT.custom2); // enable collisions and set particle collision hardness | |
| 8436 | else | ||
| 8437 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->enableParticleCollisions(false); |
| 8438 | |||
| 8439 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8440 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8441 | } | ||
| 8442 | #undef NUMBEROFSOURCES | ||
| 8443 | static const char _data_FX_MODE_PARTICLEVOLCANO[] PROGMEM = "PS Volcano@Speed,Intensity,Move,Bounce,Spread,AgeColor,Walls,Collide;;!;2;pal=35,sx=100,ix=190,c1=0,c2=160,c3=6,o1=1"; | ||
| 8444 | |||
| 8445 | /* | ||
| 8446 | Particle Fire | ||
| 8447 | realistic fire effect using particles. heat based and using perlin-noise for wind | ||
| 8448 | by DedeHai (Damian Schneider) | ||
| 8449 | */ | ||
| 8450 | 23 | uint16_t mode_particlefire(void) { | |
| 8451 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8452 | uint32_t i; // index variable | ||
| 8453 | uint32_t numFlames; // number of flames: depends on fire width. for a fire width of 16 pixels, about 25-30 flames give good results | ||
| 8454 | |||
| 8455 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8456 |
6/10✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, SEGMENT.virtualWidth(), 4)) //maximum number of source (PS may limit based on segment size); need 4 additional bytes for time keeping (uint32_t lastcall) |
| 8457 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8458 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux0 = hw_random16(); // aux0 is wind position (index) in the perlin noise |
| 8459 | } | ||
| 8460 | else | ||
| 8461 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8462 | |||
| 8463 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8464 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8465 | |||
| 8466 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8467 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check2); |
| 8468 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setMotionBlur(SEGMENT.check1 * 170); // anable/disable motion blur |
| 8469 | |||
| 8470 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t firespeed = max((uint8_t)100, SEGMENT.speed); //limit speed to 100 minimum, reduce frame rate to make it slower (slower speeds than 100 do not look nice) |
| 8471 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.speed < 100) { //slow, limit FPS |
| 8472 | 4 | uint32_t *lastcall = reinterpret_cast<uint32_t *>(PartSys->PSdataEnd); | |
| 8473 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | uint32_t period = strip().now - *lastcall; |
| 8474 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if (period < (uint32_t)map(SEGMENT.speed, 0, 99, 50, 10)) { // limit to 90FPS - 20FPS |
| 8475 | ✗ | SEGMENT.call--; //skipping a frame, decrement the counter (on call0, this is never executed as lastcall is 0, so its fine to not check if >0) | |
| 8476 | //still need to render the frame or flickering will occur in transitions | ||
| 8477 | ✗ | PartSys->updateFire(SEGMENT.intensity, true); // render the fire without updating particles (render only) | |
| 8478 | ✗ | return FRAMETIME; //do not update this frame | |
| 8479 | } | ||
| 8480 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | *lastcall = strip().now; |
| 8481 | } | ||
| 8482 | |||
| 8483 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t spread = (PartSys->maxX >> 5) * (SEGMENT.custom3 + 1); //fire around segment center (in subpixel points) |
| 8484 | 18 | numFlames = min((uint32_t)PartSys->numSources, (4 + ((spread / PS_P_RADIUS) << 1))); // number of flames used depends on spread with, good value is (fire width in pixel) * 2 | |
| 8485 | 18 | uint32_t percycle = (numFlames * 2) / 3; // maximum number of particles emitted per cycle (TODO: for ESP826 maybe use flames/2) | |
| 8486 | |||
| 8487 | // update the flame sprays: | ||
| 8488 |
2/2✓ Branch 0 taken 344 times.
✓ Branch 1 taken 18 times.
|
362 | for (i = 0; i < numFlames; i++) { |
| 8489 |
7/10✓ Branch 0 taken 344 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 152 times.
✓ Branch 5 taken 192 times.
✓ Branch 6 taken 152 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 152 times.
✓ Branch 9 taken 192 times.
|
344 | if (SEGMENT.call & 1 && PartSys->sources[i].source.ttl > 0) { // every second frame |
| 8490 | 152 | PartSys->sources[i].source.ttl--; | |
| 8491 | } else { // flame source is dead: initialize new flame: set properties of source | ||
| 8492 |
1/2✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
|
192 | PartSys->sources[i].source.x = (PartSys->maxX >> 1) - (spread >> 1) + hw_random(spread); // change flame position: distribute randomly on chosen width |
| 8493 | 192 | PartSys->sources[i].source.y = -(PS_P_RADIUS << 2); // set the source below the frame | |
| 8494 |
4/8✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 192 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 192 times.
✗ Branch 7 not taken.
|
192 | PartSys->sources[i].source.ttl = 20 + hw_random16((SEGMENT.custom1 * SEGMENT.custom1) >> 8) / (1 + (firespeed >> 5)); //'hotness' of fire, faster flames reduce the effect or flame height will scale too much with speed |
| 8495 |
3/6✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 192 times.
✗ Branch 5 not taken.
|
192 | PartSys->sources[i].maxLife = hw_random16(SEGMENT.virtualHeight() >> 1) + 16; // defines flame height together with the vy speed, vy speed*maxlife/PS_P_RADIUS is the average flame height |
| 8496 | 192 | PartSys->sources[i].minLife = PartSys->sources[i].maxLife >> 1; | |
| 8497 | 192 | PartSys->sources[i].vx = hw_random16(4) - 2; // emitting speed (sideways) | |
| 8498 |
5/10✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 192 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 192 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 192 times.
✗ Branch 9 not taken.
|
192 | PartSys->sources[i].vy = (SEGMENT.virtualHeight() >> 1) + (firespeed >> 4) + (SEGMENT.custom1 >> 4); // emitting speed (upwards) |
| 8499 | 192 | PartSys->sources[i].var = 2 + hw_random16(2 + (firespeed >> 4)); // speed variation around vx,vy (+/- var) | |
| 8500 | } | ||
| 8501 | } | ||
| 8502 | |||
| 8503 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 10 times.
|
18 | if (SEGMENT.call % 3 == 0) { // update noise position and add wind |
| 8504 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | SEGENV.aux0++; // position in the perlin noise matrix for wind generation |
| 8505 |
4/6✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
|
8 | if (SEGMENT.call % 10 == 0) |
| 8506 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux1++; // move in noise y direction so noise does not repeat as often |
| 8507 | // add wind force to all particles | ||
| 8508 |
7/14✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8 times.
✗ Branch 13 not taken.
|
8 | int8_t windspeed = ((int16_t)(perlin8(SEGENV.aux0, SEGENV.aux1) - 127) * SEGMENT.custom2) >> 7; |
| 8509 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | PartSys->applyForce(windspeed, 0); |
| 8510 | } | ||
| 8511 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | SEGENV.step++; |
| 8512 | |||
| 8513 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check3) { //add turbulance (parameters and algorithm found by experimentation) |
| 8514 | ✗ | if (SEGMENT.call % map(firespeed, 0, 255, 4, 15) == 0) { | |
| 8515 | ✗ | for (i = 0; i < PartSys->usedParticles; i++) { | |
| 8516 | ✗ | if (PartSys->particles[i].y < PartSys->maxY / 4) { // do not apply turbulance everywhere -> bottom quarter seems a good balance | |
| 8517 | ✗ | int32_t curl = ((int32_t)perlin8(PartSys->particles[i].x, PartSys->particles[i].y, SEGENV.step << 4) - 127); | |
| 8518 | ✗ | PartSys->particles[i].vx += (curl * (firespeed + 10)) >> 9; | |
| 8519 | } | ||
| 8520 | } | ||
| 8521 | } | ||
| 8522 | } | ||
| 8523 | |||
| 8524 | 18 | uint8_t j = hw_random16(); // start with a random flame (so each flame gets the chance to emit a particle if available particles is smaller than number of flames) | |
| 8525 |
2/2✓ Branch 0 taken 222 times.
✓ Branch 1 taken 18 times.
|
240 | for (i = 0; i < percycle; i++) { |
| 8526 | 222 | j = (j + 1) % numFlames; | |
| 8527 |
1/2✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
|
222 | PartSys->flameEmit(PartSys->sources[j]); |
| 8528 | } | ||
| 8529 | |||
| 8530 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->updateFire(SEGMENT.intensity, false); // update and render the fire |
| 8531 | |||
| 8532 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8533 | } | ||
| 8534 | static const char _data_FX_MODE_PARTICLEFIRE[] PROGMEM = "PS Fire@Speed,Intensity,Flame Height,Wind,Spread,Smooth,Cylinder,Turbulence;;!;2;pal=35,sx=110,c1=110,c2=50,c3=31,o1=1"; | ||
| 8535 | |||
| 8536 | /* | ||
| 8537 | PS Ballpit: particles falling down, user can enable these three options: X-wraparound, side bounce, ground bounce | ||
| 8538 | sliders control falling speed, intensity (number of particles spawned), inter-particle collision hardness (0 means no particle collisions) and render saturation | ||
| 8539 | this is quite versatile, can be made to look like rain or snow or confetti etc. | ||
| 8540 | Uses palette for particle color | ||
| 8541 | by DedeHai (Damian Schneider) | ||
| 8542 | */ | ||
| 8543 | 23 | uint16_t mode_particlepit(void) { | |
| 8544 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8545 | |||
| 8546 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8547 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 0, 0, true, false)) // init |
| 8548 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8549 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); |
| 8550 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setGravity(); // enable with default gravity |
| 8551 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setUsedParticles(170); // use 75% of available particles |
| 8552 | } | ||
| 8553 | else | ||
| 8554 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8555 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8556 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8557 | |||
| 8558 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8559 | |||
| 8560 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check1); |
| 8561 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(SEGMENT.check2); |
| 8562 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceY(SEGMENT.check3); |
| 8563 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWallHardness(min(SEGMENT.custom2, (uint8_t)150)); // limit to 100 min (if collisions are disabled, still want bouncy) |
| 8564 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
|
18 | if (SEGMENT.custom2 > 0) |
| 8565 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | PartSys->enableParticleCollisions(true, SEGMENT.custom2); // enable collisions and set particle collision hardness |
| 8566 | else | ||
| 8567 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->enableParticleCollisions(false); |
| 8568 | |||
| 8569 | uint32_t i; | ||
| 8570 |
12/18✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 11 times.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 6 times.
✓ Branch 17 taken 12 times.
|
18 | if (SEGMENT.call % (128 - (SEGMENT.intensity >> 1)) == 0 && SEGMENT.intensity > 0) { // every nth frame emit particles, stop emitting if set to zero |
| 8571 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | for (i = 0; i < PartSys->usedParticles; i++) { // emit particles |
| 8572 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (PartSys->particles[i].ttl == 0) { // find a dead particle |
| 8573 | // emit particle at random position over the top of the matrix (random16 is not random enough) | ||
| 8574 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | PartSys->particles[i].ttl = 1500 - (SEGMENT.speed << 2) + hw_random16(500); // if speed is higher, make them die sooner |
| 8575 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | PartSys->particles[i].x = hw_random(PartSys->maxX); //random(PartSys->maxX >> 1) + (PartSys->maxX >> 2); |
| 8576 | 6 | PartSys->particles[i].y = (PartSys->maxY << 1); // particles appear somewhere above the matrix, maximum is double the height | |
| 8577 |
4/8✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
|
6 | PartSys->particles[i].vx = (int16_t)hw_random16(SEGMENT.speed >> 1) - (SEGMENT.speed >> 2); // side speed is +/- |
| 8578 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | PartSys->particles[i].vy = map(SEGMENT.speed, 0, 255, -5, -100); // downward speed |
| 8579 | 6 | PartSys->particles[i].hue = hw_random16(); // set random color | |
| 8580 | 6 | PartSys->particleFlags[i].collide = true; // enable collision for particle | |
| 8581 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | PartSys->particles[i].sat = ((SEGMENT.custom3) << 3) + 7; |
| 8582 | // set particle size | ||
| 8583 |
4/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
|
6 | if (SEGMENT.custom1 == 255) { |
| 8584 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setParticleSize(1); // set global size to 1 for advanced rendering (no single pixel particles) |
| 8585 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | PartSys->advPartProps[i].size = hw_random16(SEGMENT.custom1); // set each particle to random size |
| 8586 | } else { | ||
| 8587 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | PartSys->setParticleSize(SEGMENT.custom1); // set global size |
| 8588 | 2 | PartSys->advPartProps[i].size = 0; // use global size | |
| 8589 | } | ||
| 8590 | 6 | break; // emit only one particle per round | |
| 8591 | } | ||
| 8592 | } | ||
| 8593 | } | ||
| 8594 | |||
| 8595 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t frictioncoefficient = 1 + SEGMENT.check1; //need more friction if wrapX is set, see below note |
| 8596 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.speed < 50) // for low speeds, apply more friction |
| 8597 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | frictioncoefficient = 50 - SEGMENT.speed; |
| 8598 | |||
| 8599 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.call % 6 == 0)// (3 + max(3, (SEGMENT.speed >> 2))) == 0) // note: if friction is too low, hard particles uncontrollably 'wander' left and right if wrapX is enabled |
| 8600 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->applyFriction(frictioncoefficient); |
| 8601 | |||
| 8602 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8603 | |||
| 8604 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8605 | } | ||
| 8606 | static const char _data_FX_MODE_PARTICLEPIT[] PROGMEM = "PS Ballpit@Speed,Intensity,Size,Hardness,Saturation,Cylinder,Walls,Ground;;!;2;pal=11,sx=100,ix=220,c1=120,c2=130,c3=31,o3=1"; | ||
| 8607 | |||
| 8608 | /* | ||
| 8609 | Particle Waterfall | ||
| 8610 | Uses palette for particle color, spray source at top emitting particles, many config options | ||
| 8611 | by DedeHai (Damian Schneider) | ||
| 8612 | */ | ||
| 8613 | 23 | uint16_t mode_particlewaterfall(void) { | |
| 8614 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8615 | uint8_t numSprays; | ||
| 8616 | 23 | uint32_t i = 0; | |
| 8617 | |||
| 8618 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8619 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 12)) // init, request 12 sources, no additional data needed |
| 8620 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8621 | |||
| 8622 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setGravity(); // enable with default gforce |
| 8623 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return (except on top, taken care of by gravity setting) |
| 8624 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setMotionBlur(190); // anable motion blur |
| 8625 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setSmearBlur(30); // enable 2D blurring (smearing) |
| 8626 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 4 times.
|
48 | for (i = 0; i < PartSys->numSources; i++) { |
| 8627 | 44 | PartSys->sources[i].source.hue = i*90; | |
| 8628 | 44 | PartSys->sources[i].sourceFlags.collide = true; // seeded particles will collide | |
| 8629 | #ifdef ESP8266 | ||
| 8630 | PartSys->sources[i].maxLife = 250; // lifetime in frames (ESP8266 has less particles, make them short lived to keep the water flowing) | ||
| 8631 | PartSys->sources[i].minLife = 100; | ||
| 8632 | #else | ||
| 8633 | 44 | PartSys->sources[i].maxLife = 400; // lifetime in frames | |
| 8634 | 44 | PartSys->sources[i].minLife = 150; | |
| 8635 | #endif | ||
| 8636 | } | ||
| 8637 | } | ||
| 8638 | else | ||
| 8639 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8640 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8641 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8642 | |||
| 8643 | // Particle System settings | ||
| 8644 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8645 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check1); // cylinder |
| 8646 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(SEGMENT.check2); // walls |
| 8647 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceY(SEGMENT.check3); // ground |
| 8648 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWallHardness(SEGMENT.custom2); |
| 8649 | 18 | numSprays = min((int32_t)PartSys->numSources, max(PartSys->maxXpixel / 6, (int32_t)2)); // number of sprays depends on segment width | |
| 8650 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
|
18 | if (SEGMENT.custom2 > 0) // collisions enabled |
| 8651 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | PartSys->enableParticleCollisions(true, SEGMENT.custom2); // enable collisions and set particle collision hardness |
| 8652 | else { | ||
| 8653 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->enableParticleCollisions(false); |
| 8654 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallHardness(120); // set hardness (for ground bounce) to fixed value if not using collisions |
| 8655 | } | ||
| 8656 | |||
| 8657 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 18 times.
|
93 | for (i = 0; i < numSprays; i++) { |
| 8658 |
2/4✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
|
75 | PartSys->sources[i].source.hue += 1 + hw_random16(SEGMENT.custom1>>1); // change hue of spray source |
| 8659 | } | ||
| 8660 | |||
| 8661 |
12/18✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 14 times.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 3 times.
✓ Branch 17 taken 15 times.
|
18 | if (SEGMENT.call % (12 - (SEGMENT.intensity >> 5)) == 0 && SEGMENT.intensity > 0) { // every nth frame, emit particles, do not emit if intensity is zero |
| 8662 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
|
15 | for (i = 0; i < numSprays; i++) { |
| 8663 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | PartSys->sources[i].vy = -SEGMENT.speed >> 3; // emitting speed, down |
| 8664 | //PartSys->sources[i].source.x = map(SEGMENT.custom3, 0, 31, 0, (PartSys->maxXpixel - numSprays * 2) * PS_P_RADIUS) + i * PS_P_RADIUS * 2; // emitter position | ||
| 8665 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | PartSys->sources[i].source.x = map(SEGMENT.custom3, 0, 31, 0, (PartSys->maxXpixel - numSprays) * PS_P_RADIUS) + i * PS_P_RADIUS * 2; // emitter position |
| 8666 | 12 | PartSys->sources[i].source.y = PartSys->maxY + (PS_P_RADIUS * ((i<<2) + 4)); // source y position, few pixels above the top to increase spreading before entering the matrix | |
| 8667 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | PartSys->sources[i].var = (SEGMENT.custom1 >> 3); // emiting variation 0-32 |
| 8668 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | PartSys->sprayEmit(PartSys->sources[i]); |
| 8669 | } | ||
| 8670 | } | ||
| 8671 | |||
| 8672 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.call % 20 == 0) |
| 8673 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->applyFriction(1); // add just a tiny amount of friction to help smooth things |
| 8674 | |||
| 8675 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8676 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8677 | } | ||
| 8678 | static const char _data_FX_MODE_PARTICLEWATERFALL[] PROGMEM = "PS Waterfall@Speed,Intensity,Variation,Collide,Position,Cylinder,Walls,Ground;;!;2;pal=9,sx=15,ix=200,c1=32,c2=160,o3=1"; | ||
| 8679 | |||
| 8680 | /* | ||
| 8681 | Particle Box, applies gravity to particles in either a random direction or random but only downwards (sloshing) | ||
| 8682 | Uses palette for particle color | ||
| 8683 | by DedeHai (Damian Schneider) | ||
| 8684 | */ | ||
| 8685 | 23 | uint16_t mode_particlebox(void) { | |
| 8686 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8687 | uint32_t i; | ||
| 8688 | |||
| 8689 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8690 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1)) // init |
| 8691 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8692 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceX(true); |
| 8693 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceY(true); |
| 8694 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux0 = hw_random16(); // position in perlin noise |
| 8695 | } | ||
| 8696 | else | ||
| 8697 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8698 | |||
| 8699 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8700 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8701 | |||
| 8702 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8703 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setParticleSize(SEGMENT.custom3<<3); |
| 8704 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWallHardness(min(SEGMENT.custom2, (uint8_t)200)); // wall hardness is 200 or more |
| 8705 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->enableParticleCollisions(true, max(2, (int)SEGMENT.custom2)); // enable collisions and set particle collision hardness |
| 8706 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setUsedParticles(map(SEGMENT.intensity, 0, 255, 2, 153)); // 1% - 60% |
| 8707 | // add in new particles if amount has changed | ||
| 8708 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 2 times.
|
49 | for (i = 0; i < PartSys->usedParticles; i++) { |
| 8709 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 31 times.
|
47 | if (PartSys->particles[i].ttl < 260) { // initialize handed over particles and dead particles |
| 8710 | 16 | PartSys->particles[i].ttl = 260; // full brigthness | |
| 8711 | 16 | PartSys->particles[i].x = hw_random16(PartSys->maxX); | |
| 8712 | 16 | PartSys->particles[i].y = hw_random16(PartSys->maxY); | |
| 8713 | 16 | PartSys->particles[i].hue = hw_random8(); // make it colorful | |
| 8714 | 16 | PartSys->particleFlags[i].perpetual = true; // never die | |
| 8715 | 16 | PartSys->particleFlags[i].collide = true; // all particles colllide | |
| 8716 | 16 | break; // only spawn one particle per frame for less chaotic transitions | |
| 8717 | } | ||
| 8718 | } | ||
| 8719 | |||
| 8720 |
12/18✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 11 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 11 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 10 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 10 times.
✓ Branch 17 taken 8 times.
|
18 | if (SEGMENT.call % (((255 - SEGMENT.speed) >> 6) + 1) == 0 && SEGMENT.speed > 0) { // how often the force is applied depends on speed setting |
| 8721 | int32_t xgravity; | ||
| 8722 | int32_t ygravity; | ||
| 8723 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | int32_t increment = (SEGMENT.speed >> 6) + 1; |
| 8724 | |||
| 8725 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
|
10 | if (SEGMENT.check2) { // washing machine |
| 8726 | ✗ | int speed = tristate_square8(strip().now >> 7, 90, 15) / ((400 - SEGMENT.speed) >> 3); | |
| 8727 | ✗ | SEGENV.aux0 += speed; | |
| 8728 | ✗ | if (speed == 0) SEGENV.aux0 = 190; //down (= 270°) | |
| 8729 | } | ||
| 8730 | else | ||
| 8731 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | SEGENV.aux0 -= increment; |
| 8732 | |||
| 8733 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | if (SEGMENT.check1) { // random, use perlin noise |
| 8734 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | xgravity = ((int16_t)perlin8(SEGENV.aux0) - 127); |
| 8735 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | ygravity = ((int16_t)perlin8(SEGENV.aux0 + 10000) - 127); |
| 8736 | // scale the gravity force | ||
| 8737 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | xgravity = (xgravity * SEGMENT.custom1) / 128; |
| 8738 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | ygravity = (ygravity * SEGMENT.custom1) / 128; |
| 8739 | } | ||
| 8740 | else { // go in a circle | ||
| 8741 | ✗ | xgravity = ((int32_t)(SEGMENT.custom1) * cos16_t(SEGENV.aux0 << 8)) / 0xFFFF; | |
| 8742 | ✗ | ygravity = ((int32_t)(SEGMENT.custom1) * sin16_t(SEGENV.aux0 << 8)) / 0xFFFF; | |
| 8743 | } | ||
| 8744 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
|
10 | if (SEGMENT.check3) { // sloshing, y force is always downwards |
| 8745 | ✗ | if (ygravity > 0) | |
| 8746 | ✗ | ygravity = -ygravity; | |
| 8747 | } | ||
| 8748 | |||
| 8749 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | PartSys->applyForce(xgravity, ygravity); |
| 8750 | } | ||
| 8751 | |||
| 8752 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if ((SEGMENT.call & 0x0F) == 0) // every 16th frame |
| 8753 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->applyFriction(1); |
| 8754 | |||
| 8755 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8756 | |||
| 8757 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8758 | } | ||
| 8759 | static const char _data_FX_MODE_PARTICLEBOX[] PROGMEM = "PS Box@!,Particles,Tilt,Hardness,Size,Random,Washing Machine,Sloshing;;!;2;pal=53,ix=50,c3=1,o1=1"; | ||
| 8760 | |||
| 8761 | /* | ||
| 8762 | Fuzzy Noise: Perlin noise 'gravity' mapping as in particles on 'noise hills' viewed from above | ||
| 8763 | calculates slope gradient at the particle positions and applies 'downhill' force, resulting in a fuzzy perlin noise display | ||
| 8764 | by DedeHai (Damian Schneider) | ||
| 8765 | */ | ||
| 8766 | 23 | uint16_t mode_particleperlin(void) { | |
| 8767 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8768 | uint32_t i; | ||
| 8769 | |||
| 8770 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8771 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1, 0, true)) // init with 1 source and advanced properties |
| 8772 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8773 | |||
| 8774 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); // should never happen, but lets make sure there are no stray particles |
| 8775 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setMotionBlur(230); // anable motion blur |
| 8776 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceY(true); |
| 8777 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux0 = rand(); |
| 8778 | } | ||
| 8779 | else | ||
| 8780 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8781 | |||
| 8782 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8783 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8784 | |||
| 8785 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8786 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check1); |
| 8787 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(!SEGMENT.check1); |
| 8788 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWallHardness(SEGMENT.custom1); // wall hardness |
| 8789 |
5/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
|
18 | PartSys->enableParticleCollisions(SEGMENT.check3, SEGMENT.custom1); // enable collisions and set particle collision hardness |
| 8790 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setUsedParticles(map(SEGMENT.intensity, 0, 255, 25, 128)); // min is 10%, max is 50% |
| 8791 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setSmearBlur(SEGMENT.check2 * 15); // enable 2D blurring (smearing) |
| 8792 | |||
| 8793 | // apply 'gravity' from a 2D perlin noise map | ||
| 8794 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | SEGENV.aux0 += 1 + (SEGMENT.speed >> 5); // noise z-position |
| 8795 | // update position in noise | ||
| 8796 |
2/2✓ Branch 0 taken 1957 times.
✓ Branch 1 taken 18 times.
|
1975 | for (i = 0; i < PartSys->usedParticles; i++) { |
| 8797 |
2/2✓ Branch 0 taken 443 times.
✓ Branch 1 taken 1514 times.
|
1957 | if (PartSys->particles[i].ttl == 0) { // revive dead particles (do not keep them alive forever, they can clump up, need to reseed) |
| 8798 | 443 | PartSys->particles[i].ttl = hw_random16(500) + 200; | |
| 8799 |
1/2✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
|
443 | PartSys->particles[i].x = hw_random(PartSys->maxX); |
| 8800 |
1/2✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
|
443 | PartSys->particles[i].y = hw_random(PartSys->maxY); |
| 8801 | 443 | PartSys->particleFlags[i].collide = true; // particle colllides | |
| 8802 | } | ||
| 8803 |
2/4✓ Branch 0 taken 1957 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1957 times.
✗ Branch 3 not taken.
|
1957 | uint32_t scale = 16 - ((31 - SEGMENT.custom3) >> 1); |
| 8804 | 1957 | uint16_t xnoise = PartSys->particles[i].x / scale; // position in perlin noise, scaled by slider | |
| 8805 | 1957 | uint16_t ynoise = PartSys->particles[i].y / scale; | |
| 8806 |
3/6✓ Branch 0 taken 1957 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1957 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1957 times.
✗ Branch 5 not taken.
|
1957 | int16_t baseheight = perlin8(xnoise, ynoise, SEGENV.aux0); // noise value at particle position |
| 8807 | 1957 | PartSys->particles[i].hue = baseheight; // color particles to perlin noise value | |
| 8808 |
4/6✓ Branch 0 taken 1957 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1957 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 443 times.
✓ Branch 5 taken 1514 times.
|
1957 | if (SEGMENT.call % 8 == 0) { // do not apply the force every frame, is too chaotic |
| 8809 |
3/6✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 443 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 443 times.
✗ Branch 5 not taken.
|
443 | int8_t xslope = (baseheight + (int16_t)perlin8(xnoise - 10, ynoise, SEGENV.aux0)); |
| 8810 |
3/6✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 443 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 443 times.
✗ Branch 5 not taken.
|
443 | int8_t yslope = (baseheight + (int16_t)perlin8(xnoise, ynoise - 10, SEGENV.aux0)); |
| 8811 |
1/2✓ Branch 0 taken 443 times.
✗ Branch 1 not taken.
|
443 | PartSys->applyForce(i, xslope, yslope); |
| 8812 | } | ||
| 8813 | } | ||
| 8814 | |||
| 8815 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 11 times.
|
18 | if (SEGMENT.call % (16 - (SEGMENT.custom2 >> 4)) == 0) |
| 8816 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | PartSys->applyFriction(2); |
| 8817 | |||
| 8818 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8819 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8820 | } | ||
| 8821 | static const char _data_FX_MODE_PARTICLEPERLIN[] PROGMEM = "PS Fuzzy Noise@Speed,Particles,Bounce,Friction,Scale,Cylinder,Smear,Collide;;!;2;pal=64,sx=50,ix=200,c1=130,c2=30,c3=5,o3=1"; | ||
| 8822 | |||
| 8823 | /* | ||
| 8824 | Particle smashing down like meteors and exploding as they hit the ground, has many parameters to play with | ||
| 8825 | by DedeHai (Damian Schneider) | ||
| 8826 | */ | ||
| 8827 | #define NUMBEROFSOURCES 8 | ||
| 8828 | 23 | uint16_t mode_particleimpact(void) { | |
| 8829 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8830 | 23 | uint32_t i = 0; | |
| 8831 | uint32_t numMeteors; | ||
| 8832 | PSsettings2D meteorsettings; | ||
| 8833 | 23 | meteorsettings.asByte = 0b00101000; // PS settings for meteors: bounceY and gravity enabled | |
| 8834 | |||
| 8835 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8836 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, NUMBEROFSOURCES)) // init, no additional data needed |
| 8837 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8838 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); |
| 8839 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setGravity(); // enable default gravity |
| 8840 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceY(true); // always use ground bounce |
| 8841 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallRoughness(220); // high roughness |
| 8842 | 4 | numMeteors = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); | |
| 8843 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
|
36 | for (i = 0; i < numMeteors; i++) { |
| 8844 | 32 | PartSys->sources[i].source.ttl = hw_random16(10 * i); // set initial delay for meteors | |
| 8845 | 32 | PartSys->sources[i].source.vy = 10; // at positive speeds, no particles are emitted and if particle dies, it will be relaunched | |
| 8846 | } | ||
| 8847 | } | ||
| 8848 | else | ||
| 8849 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8850 | |||
| 8851 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8852 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8853 | |||
| 8854 | // Particle System settings | ||
| 8855 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8856 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check1); |
| 8857 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(SEGMENT.check2); |
| 8858 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setMotionBlur(SEGMENT.custom3<<3); |
| 8859 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t hardness = map(SEGMENT.custom2, 0, 255, PS_P_MINSURFACEHARDNESS - 2, 255); |
| 8860 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->setWallHardness(hardness); |
| 8861 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->enableParticleCollisions(SEGMENT.check3, hardness); // enable collisions and set particle collision hardness |
| 8862 | 18 | numMeteors = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); | |
| 8863 | uint32_t emitparticles; // number of particles to emit for each rocket's state | ||
| 8864 | |||
| 8865 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 18 times.
|
162 | for (i = 0; i < numMeteors; i++) { |
| 8866 | // determine meteor state by its speed: | ||
| 8867 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 126 times.
|
144 | if ( PartSys->sources[i].source.vy < 0) // moving down, emit sparks |
| 8868 | 18 | emitparticles = 1; | |
| 8869 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | else if ( PartSys->sources[i].source.vy > 0) // moving up means meteor is on 'standby' |
| 8870 | 126 | emitparticles = 0; | |
| 8871 | else { // speed is zero, explode! | ||
| 8872 | ✗ | PartSys->sources[i].source.vy = 10; // set source speed positive so it goes into timeout and launches again | |
| 8873 | ✗ | emitparticles = map(SEGMENT.intensity, 0, 255, 10, hw_random16(PartSys->usedParticles>>2)); // defines the size of the explosion | |
| 8874 | } | ||
| 8875 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 144 times.
|
162 | for (int e = emitparticles; e > 0; e--) { |
| 8876 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->sprayEmit(PartSys->sources[i]); |
| 8877 | } | ||
| 8878 | } | ||
| 8879 | |||
| 8880 | // update the meteors, set the speed state | ||
| 8881 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 18 times.
|
162 | for (i = 0; i < numMeteors; i++) { |
| 8882 |
2/2✓ Branch 0 taken 137 times.
✓ Branch 1 taken 7 times.
|
144 | if (PartSys->sources[i].source.ttl) { |
| 8883 | 137 | PartSys->sources[i].source.ttl--; // note: this saves an if statement, but moving down particles age twice | |
| 8884 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 119 times.
|
137 | if (PartSys->sources[i].source.vy < 0) { // move down |
| 8885 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->applyGravity(PartSys->sources[i].source); |
| 8886 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->particleMoveUpdate(PartSys->sources[i].source, PartSys->sources[i].sourceFlags, &meteorsettings); |
| 8887 | |||
| 8888 | // if source reaches the bottom, set speed to 0 so it will explode on next function call (handled above) | ||
| 8889 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (PartSys->sources[i].source.y < PS_P_RADIUS<<1) { // reached the bottom pixel on its way down |
| 8890 | ✗ | PartSys->sources[i].source.vy = 0; // set speed zero so it will explode | |
| 8891 | ✗ | PartSys->sources[i].source.vx = 0; | |
| 8892 | ✗ | PartSys->sources[i].sourceFlags.collide = true; | |
| 8893 | #ifdef ESP8266 | ||
| 8894 | PartSys->sources[i].maxLife = 900; | ||
| 8895 | PartSys->sources[i].minLife = 100; | ||
| 8896 | #else | ||
| 8897 | ✗ | PartSys->sources[i].maxLife = 1250; | |
| 8898 | ✗ | PartSys->sources[i].minLife = 250; | |
| 8899 | #endif | ||
| 8900 | ✗ | PartSys->sources[i].source.ttl = hw_random16((768 - (SEGMENT.speed << 1))) + 40; // standby time til next launch (in frames) | |
| 8901 | ✗ | PartSys->sources[i].vy = (SEGMENT.custom1 >> 2); // emitting speed y | |
| 8902 | ✗ | PartSys->sources[i].var = (SEGMENT.custom1 >> 2); // speed variation around vx,vy (+/- var) | |
| 8903 | } | ||
| 8904 | } | ||
| 8905 | } | ||
| 8906 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | else if (PartSys->sources[i].source.vy > 0) { // meteor is exploded and time is up (ttl==0 and positive speed), relaunch it |
| 8907 | // reinitialize meteor | ||
| 8908 | 7 | PartSys->sources[i].source.y = PartSys->maxY + (PS_P_RADIUS << 2); // start 4 pixels above the top | |
| 8909 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | PartSys->sources[i].source.x = hw_random(PartSys->maxX); |
| 8910 | 7 | PartSys->sources[i].source.vy = -hw_random16(30) - 30; // meteor downward speed | |
| 8911 | 7 | PartSys->sources[i].source.vx = hw_random16(50) - 25; // TODO: make this dependent on position so they do not move out of frame | |
| 8912 | 7 | PartSys->sources[i].source.hue = hw_random16(); // random color | |
| 8913 | 7 | PartSys->sources[i].source.ttl = 500; // long life, will explode at bottom | |
| 8914 | 7 | PartSys->sources[i].sourceFlags.collide = false; // trail particles will not collide | |
| 8915 | 7 | PartSys->sources[i].maxLife = 300; // spark particle life | |
| 8916 | 7 | PartSys->sources[i].minLife = 100; | |
| 8917 | 7 | PartSys->sources[i].vy = -9; // emitting speed (down) | |
| 8918 | 7 | PartSys->sources[i].var = 3; // speed variation around vx,vy (+/- var) | |
| 8919 | } | ||
| 8920 | } | ||
| 8921 | |||
| 8922 |
2/2✓ Branch 0 taken 6776 times.
✓ Branch 1 taken 18 times.
|
6794 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 8923 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 6738 times.
|
6776 | if (PartSys->particles[i].ttl > 5) PartSys->particles[i].ttl -= 5; //ttl is linked to brightness, this allows to use higher brightness but still a short spark lifespan |
| 8924 | } | ||
| 8925 | |||
| 8926 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 8927 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 8928 | } | ||
| 8929 | #undef NUMBEROFSOURCES | ||
| 8930 | static const char _data_FX_MODE_PARTICLEIMPACT[] PROGMEM = "PS Impact@Launches,!,Force,Hardness,Blur,Cylinder,Walls,Collide;;!;2;pal=0,sx=32,ix=85,c1=70,c2=130,c3=0,o3=1"; | ||
| 8931 | |||
| 8932 | /* | ||
| 8933 | Particle Attractor, a particle attractor sits in the matrix center, a spray bounces around and seeds particles | ||
| 8934 | uses inverse square law like in planetary motion | ||
| 8935 | Uses palette for particle color | ||
| 8936 | by DedeHai (Damian Schneider) | ||
| 8937 | */ | ||
| 8938 | 23 | uint16_t mode_particleattractor(void) { | |
| 8939 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 8940 | PSsettings2D sourcesettings; | ||
| 8941 | 23 | sourcesettings.asByte = 0b00001100; // PS settings for bounceY, bounceY used for source movement (it always bounces whereas particles do not) | |
| 8942 | PSparticleFlags attractorFlags; | ||
| 8943 | 23 | attractorFlags.asByte = 0; // no flags set | |
| 8944 | PSparticle *attractor; // particle pointer to the attractor | ||
| 8945 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 8946 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1, sizeof(PSparticle), true)) // init using 1 source and advanced particle settings |
| 8947 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 8948 | 4 | PartSys->sources[0].source.hue = hw_random16(); | |
| 8949 | 4 | PartSys->sources[0].source.vx = -7; // will collied with wall and get random bounce direction | |
| 8950 | 4 | PartSys->sources[0].sourceFlags.collide = true; // seeded particles will collide | |
| 8951 | 4 | PartSys->sources[0].sourceFlags.perpetual = true; //source does not age | |
| 8952 | #ifdef ESP8266 | ||
| 8953 | PartSys->sources[0].maxLife = 200; // lifetime in frames (ESP8266 has less particles) | ||
| 8954 | PartSys->sources[0].minLife = 30; | ||
| 8955 | #else | ||
| 8956 | 4 | PartSys->sources[0].maxLife = 350; // lifetime in frames | |
| 8957 | 4 | PartSys->sources[0].minLife = 50; | |
| 8958 | #endif | ||
| 8959 | 4 | PartSys->sources[0].var = 4; // emiting variation | |
| 8960 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallHardness(255); //bounce forever |
| 8961 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallRoughness(200); //randomize wall bounce |
| 8962 | } | ||
| 8963 | else { | ||
| 8964 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 8965 | } | ||
| 8966 | |||
| 8967 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 8968 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 8969 | |||
| 8970 | // Particle System settings | ||
| 8971 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 8972 | 18 | attractor = reinterpret_cast<PSparticle *>(PartSys->PSdataEnd); | |
| 8973 | |||
| 8974 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setColorByAge(SEGMENT.check1); |
| 8975 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setParticleSize(SEGMENT.custom1 >> 1); //set size globally |
| 8976 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setUsedParticles(map(SEGMENT.intensity, 0, 255, 25, 190)); |
| 8977 | |||
| 8978 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.custom2 > 0) // collisions enabled |
| 8979 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | PartSys->enableParticleCollisions(true, map(SEGMENT.custom2, 1, 255, 120, 255)); // enable collisions and set particle collision hardness |
| 8980 | else | ||
| 8981 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | PartSys->enableParticleCollisions(false); |
| 8982 | |||
| 8983 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.call == 0) { |
| 8984 | 4 | attractor->vx = PartSys->sources[0].source.vy; // set to spray movemement but reverse x and y | |
| 8985 | 4 | attractor->vy = PartSys->sources[0].source.vx; | |
| 8986 | } | ||
| 8987 | |||
| 8988 | // set attractor properties | ||
| 8989 | 18 | attractor->ttl = 100; // never dies | |
| 8990 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check2) { |
| 8991 | ✗ | if ((SEGMENT.call % 3) == 0) // move slowly | |
| 8992 | ✗ | PartSys->particleMoveUpdate(*attractor, attractorFlags, &sourcesettings); // move the attractor | |
| 8993 | } | ||
| 8994 | else { | ||
| 8995 | 18 | attractor->x = PartSys->maxX >> 1; // set to center | |
| 8996 | 18 | attractor->y = PartSys->maxY >> 1; | |
| 8997 | } | ||
| 8998 | |||
| 8999 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.call % 5 == 0) |
| 9000 | 4 | PartSys->sources[0].source.hue++; | |
| 9001 | |||
| 9002 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | SEGENV.aux0 += 256; // emitting angle, one full turn in 255 frames (0xFFFF is 360°) |
| 9003 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 8 times.
|
18 | if (SEGMENT.call % 2 == 0) // alternate direction of emit |
| 9004 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | PartSys->angleEmit(PartSys->sources[0], SEGENV.aux0, 12); |
| 9005 | else | ||
| 9006 |
3/6✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | PartSys->angleEmit(PartSys->sources[0], SEGENV.aux0 + 0x7FFF, 12); // emit at 180° as well |
| 9007 | // apply force | ||
| 9008 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t strength = SEGMENT.speed; |
| 9009 | #ifdef USERMOD_AUDIOREACTIVE | ||
| 9010 | um_data_t *um_data; | ||
| 9011 | if (UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // AR active, do not use simulated data | ||
| 9012 | uint32_t volumeSmth = (uint32_t)(*(float*) um_data->u_data[0]); // 0-255 | ||
| 9013 | strength = (SEGMENT.speed * volumeSmth) >> 8; | ||
| 9014 | } | ||
| 9015 | #endif | ||
| 9016 |
2/2✓ Branch 0 taken 2138 times.
✓ Branch 1 taken 18 times.
|
2156 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 9017 |
3/6✓ Branch 0 taken 2138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2138 times.
✗ Branch 5 not taken.
|
2138 | PartSys->pointAttractor(i, *attractor, strength, SEGMENT.check3); |
| 9018 | } | ||
| 9019 | |||
| 9020 | |||
| 9021 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 13 times.
|
18 | if (SEGMENT.call % (33 - SEGMENT.custom3) == 0) |
| 9022 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->applyFriction(2); |
| 9023 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags, &sourcesettings); // move the source |
| 9024 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9025 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9026 | } | ||
| 9027 | static const char _data_FX_MODE_PARTICLEATTRACTOR[] PROGMEM = "PS Attractor@Mass,Particles,Size,Collide,Friction,AgeColor,Move,Swallow;;!;2;pal=9,sx=100,ix=82,c1=2,c2=0"; | ||
| 9028 | |||
| 9029 | /* | ||
| 9030 | Particle Spray, just a particle spray with many parameters | ||
| 9031 | Uses palette for particle color | ||
| 9032 | by DedeHai (Damian Schneider) | ||
| 9033 | */ | ||
| 9034 | 23 | uint16_t mode_particlespray(void) { | |
| 9035 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 9036 | 23 | const uint8_t hardness = 200; // collision hardness is fixed | |
| 9037 | |||
| 9038 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9039 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1)) // init, no additional data needed |
| 9040 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 9041 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return (except on top, taken care of by gravity setting) |
| 9042 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceY(true); |
| 9043 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setMotionBlur(200); // anable motion blur |
| 9044 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setSmearBlur(10); // anable motion blur |
| 9045 | 4 | PartSys->sources[0].source.hue = hw_random16(); | |
| 9046 | 4 | PartSys->sources[0].sourceFlags.collide = true; // seeded particles will collide (if enabled) | |
| 9047 | 4 | PartSys->sources[0].var = 3; | |
| 9048 | } | ||
| 9049 | else | ||
| 9050 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9051 | |||
| 9052 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 9053 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 9054 | |||
| 9055 | // Particle System settings | ||
| 9056 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9057 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(!SEGMENT.check2); |
| 9058 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check2); |
| 9059 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->setWallHardness(hardness); |
| 9060 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setGravity(8 * SEGMENT.check1); // enable gravity if checked (8 is default strength) |
| 9061 | //numSprays = min(PartSys->numSources, (uint8_t)1); // number of sprays | ||
| 9062 | |||
| 9063 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check3) // collisions enabled |
| 9064 | ✗ | PartSys->enableParticleCollisions(true, hardness); // enable collisions and set particle collision hardness | |
| 9065 | else | ||
| 9066 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->enableParticleCollisions(false); |
| 9067 | |||
| 9068 | //position according to sliders | ||
| 9069 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys->sources[0].source.x = map(SEGMENT.custom1, 0, 255, 0, PartSys->maxX); |
| 9070 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys->sources[0].source.y = map(SEGMENT.custom2, 0, 255, 0, PartSys->maxY); |
| 9071 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint16_t angle = (256 - (((int32_t)SEGMENT.custom3 + 1) << 3)) << 8; |
| 9072 | |||
| 9073 | #ifdef USERMOD_AUDIOREACTIVE | ||
| 9074 | um_data_t *um_data; | ||
| 9075 | if (UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // get AR data, do not use simulated data | ||
| 9076 | uint32_t volumeSmth = (uint8_t)(*(float*) um_data->u_data[0]); //0 to 255 | ||
| 9077 | uint32_t volumeRaw = *(int16_t*)um_data->u_data[1]; //0 to 255 | ||
| 9078 | PartSys->sources[0].minLife = 30; | ||
| 9079 | |||
| 9080 | if (SEGMENT.call % 20 == 0 || SEGMENT.call % (11 - volumeSmth / 25) == 0) { // defines interval of particle emit | ||
| 9081 | PartSys->sources[0].maxLife = (volumeSmth >> 1) + (SEGMENT.intensity >> 1); // lifetime in frames | ||
| 9082 | PartSys->sources[0].var = 1 + ((volumeRaw * SEGMENT.speed) >> 12); | ||
| 9083 | uint32_t emitspeed = (SEGMENT.speed >> 2) + (volumeRaw >> 3); | ||
| 9084 | PartSys->sources[0].source.hue += volumeSmth/30; | ||
| 9085 | PartSys->angleEmit(PartSys->sources[0], angle, emitspeed); | ||
| 9086 | } | ||
| 9087 | } | ||
| 9088 | else { //no AR data, fall back to normal mode | ||
| 9089 | // change source properties | ||
| 9090 | if (SEGMENT.call % (11 - (SEGMENT.intensity / 25)) == 0) { // every nth frame, cycle color and emit particles | ||
| 9091 | PartSys->sources[0].maxLife = 300 + SEGMENT.intensity; // lifetime in frames | ||
| 9092 | PartSys->sources[0].minLife = 150 + SEGMENT.intensity; | ||
| 9093 | PartSys->sources[0].source.hue++; // = hw_random16(); //change hue of spray source | ||
| 9094 | PartSys->angleEmit(PartSys->sources[0], angle, SEGMENT.speed >> 2); | ||
| 9095 | } | ||
| 9096 | } | ||
| 9097 | #else | ||
| 9098 | // change source properties | ||
| 9099 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 11 times.
|
18 | if (SEGMENT.call % (11 - (SEGMENT.intensity / 25)) == 0) { // every nth frame, cycle color and emit particles |
| 9100 | 7 | PartSys->sources[0].maxLife = 300; // lifetime in frames. note: could be done in init part, but AR moderequires this to be dynamic | |
| 9101 | 7 | PartSys->sources[0].minLife = 100; | |
| 9102 | 7 | PartSys->sources[0].source.hue++; // = hw_random16(); //change hue of spray source | |
| 9103 | // PartSys->sources[i].var = SEGMENT.custom3; // emiting variation = nozzle size (custom 3 goes from 0-32) | ||
| 9104 | // spray[j].source.hue = hw_random16(); //set random color for each particle (using palette) | ||
| 9105 |
3/6✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | PartSys->angleEmit(PartSys->sources[0], angle, SEGMENT.speed >> 2); |
| 9106 | } | ||
| 9107 | #endif | ||
| 9108 | |||
| 9109 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9110 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9111 | } | ||
| 9112 | static const char _data_FX_MODE_PARTICLESPRAY[] PROGMEM = "PS Spray@Speed,!,Left/Right,Up/Down,Angle,Gravity,Cylinder/Square,Collide;;!;2v;pal=0,sx=150,ix=150,c1=220,c2=30,c3=21"; | ||
| 9113 | |||
| 9114 | |||
| 9115 | /* | ||
| 9116 | Particle base Graphical Equalizer | ||
| 9117 | Uses palette for particle color | ||
| 9118 | by DedeHai (Damian Schneider) | ||
| 9119 | */ | ||
| 9120 | 23 | uint16_t mode_particleGEQ(void) { | |
| 9121 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 9122 | |||
| 9123 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9124 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1)) |
| 9125 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 9126 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); |
| 9127 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setUsedParticles(170); // use 2/3 of available particles |
| 9128 | } | ||
| 9129 | else | ||
| 9130 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9131 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 9132 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 9133 | |||
| 9134 | uint32_t i; | ||
| 9135 | // set particle system properties | ||
| 9136 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9137 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWrapX(SEGMENT.check1); |
| 9138 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceX(SEGMENT.check2); |
| 9139 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setBounceY(SEGMENT.check3); |
| 9140 | //PartSys->enableParticleCollisions(false); | ||
| 9141 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setWallHardness(SEGMENT.custom2); |
| 9142 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setGravity(SEGMENT.custom3 << 2); // set gravity strength |
| 9143 | |||
| 9144 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | um_data_t *um_data = getAudioData(); |
| 9145 | 18 | uint8_t *fftResult = (uint8_t *)um_data->u_data[2]; // 16 bins with FFT data, log mapped already, each band contains frequency amplitude 0-255 | |
| 9146 | |||
| 9147 | //map the bands into 16 positions on x axis, emit some particles according to frequency loudness | ||
| 9148 | 18 | i = 0; | |
| 9149 | 18 | uint32_t binwidth = (PartSys->maxX + 1)>>4; //emit poisition variation for one bin (+/-) is equal to width/16 (for 16 bins) | |
| 9150 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t threshold = 300 - SEGMENT.intensity; |
| 9151 | 18 | uint32_t emitparticles = 0; | |
| 9152 | |||
| 9153 |
2/2✓ Branch 0 taken 288 times.
✓ Branch 1 taken 18 times.
|
306 | for (uint32_t bin = 0; bin < 16; bin++) { |
| 9154 | 288 | uint32_t xposition = binwidth*bin + (binwidth>>1); // emit position according to frequency band | |
| 9155 |
2/4✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
✗ Branch 3 not taken.
|
288 | uint8_t emitspeed = ((uint32_t)fftResult[bin] * (uint32_t)SEGMENT.speed) >> 9; // emit speed according to loudness of band (127 max!) |
| 9156 | 288 | emitparticles = 0; | |
| 9157 | |||
| 9158 |
2/2✓ Branch 0 taken 107 times.
✓ Branch 1 taken 181 times.
|
288 | if (fftResult[bin] > threshold) { |
| 9159 | 107 | emitparticles = 1;// + (fftResult[bin]>>6); | |
| 9160 | } | ||
| 9161 |
2/2✓ Branch 0 taken 167 times.
✓ Branch 1 taken 14 times.
|
181 | else if (fftResult[bin] > 0) { // band has low volue |
| 9162 | 167 | uint32_t restvolume = ((threshold - fftResult[bin])>>2) + 2; | |
| 9163 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 161 times.
|
167 | if (hw_random16() % restvolume == 0) |
| 9164 | 6 | emitparticles = 1; | |
| 9165 | } | ||
| 9166 | |||
| 9167 |
4/4✓ Branch 0 taken 519 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 275 times.
✓ Branch 3 taken 244 times.
|
563 | while (i < PartSys->usedParticles && emitparticles > 0) { // emit particles if there are any left, low frequencies take priority |
| 9168 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 185 times.
|
275 | if (PartSys->particles[i].ttl == 0) { // find a dead particle |
| 9169 | //set particle properties TODO: could also use the spray... | ||
| 9170 |
2/4✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
|
90 | PartSys->particles[i].ttl = 20 + map(SEGMENT.intensity, 0,255, emitspeed>>1, emitspeed + hw_random16(emitspeed)) ; // set particle alive, particle lifespan is in number of frames |
| 9171 | 90 | PartSys->particles[i].x = xposition + hw_random16(binwidth) - (binwidth>>1); // position randomly, deviating half a bin width | |
| 9172 | 90 | PartSys->particles[i].y = PS_P_RADIUS; // start at the bottom (PS_P_RADIUS is minimum position a particle is fully in frame) | |
| 9173 |
4/8✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 90 times.
✗ Branch 7 not taken.
|
90 | PartSys->particles[i].vx = hw_random16(SEGMENT.custom1>>1)-(SEGMENT.custom1>>2) ; //x-speed variation: +/- custom1/4 |
| 9174 | 90 | PartSys->particles[i].vy = emitspeed; | |
| 9175 | 90 | PartSys->particles[i].hue = (bin<<4) + hw_random16(17) - 8; // color from palette according to bin | |
| 9176 | 90 | emitparticles--; | |
| 9177 | } | ||
| 9178 | 275 | i++; | |
| 9179 | } | ||
| 9180 | } | ||
| 9181 | |||
| 9182 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9183 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9184 | } | ||
| 9185 | |||
| 9186 | static const char _data_FX_MODE_PARTICLEGEQ[] PROGMEM = "PS GEQ 2D@Speed,Intensity,Diverge,Bounce,Gravity,Cylinder,Walls,Floor;;!;2f;pal=0,sx=155,ix=200,c1=0"; | ||
| 9187 | |||
| 9188 | /* | ||
| 9189 | Particle rotating GEQ | ||
| 9190 | Particles sprayed from center with rotating spray | ||
| 9191 | Uses palette for particle color | ||
| 9192 | by DedeHai (Damian Schneider) | ||
| 9193 | */ | ||
| 9194 | #define NUMBEROFSOURCES 16 | ||
| 9195 | 23 | uint16_t mode_particlecenterGEQ(void) { | |
| 9196 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 9197 | uint8_t numSprays; | ||
| 9198 | uint32_t i; | ||
| 9199 | |||
| 9200 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9201 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, NUMBEROFSOURCES)) // init, request 16 sources |
| 9202 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 9203 | |||
| 9204 | 4 | numSprays = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); | |
| 9205 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 4 times.
|
60 | for (i = 0; i < numSprays; i++) { |
| 9206 | 56 | PartSys->sources[i].source.x = (PartSys->maxX + 1) >> 1; // center | |
| 9207 | 56 | PartSys->sources[i].source.y = (PartSys->maxY + 1) >> 1; // center | |
| 9208 | 56 | PartSys->sources[i].source.hue = i * 16; // even color distribution | |
| 9209 | 56 | PartSys->sources[i].maxLife = 400; | |
| 9210 | 56 | PartSys->sources[i].minLife = 200; | |
| 9211 | } | ||
| 9212 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); |
| 9213 | } | ||
| 9214 | else | ||
| 9215 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9216 | |||
| 9217 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 9218 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 9219 | |||
| 9220 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9221 | 18 | numSprays = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES); | |
| 9222 | |||
| 9223 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | um_data_t *um_data = getAudioData(); |
| 9224 | 18 | uint8_t *fftResult = (uint8_t *)um_data->u_data[2]; // 16 bins with FFT data, log mapped already, each band contains frequency amplitude 0-255 | |
| 9225 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint32_t threshold = 300 - SEGMENT.intensity; |
| 9226 | |||
| 9227 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check2) |
| 9228 | ✗ | SEGENV.aux0 += SEGMENT.custom1 << 2; | |
| 9229 | else | ||
| 9230 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | SEGENV.aux0 -= SEGMENT.custom1 << 2; |
| 9231 | |||
| 9232 | 18 | uint16_t angleoffset = (uint16_t)0xFFFF / (uint16_t)numSprays; | |
| 9233 | 18 | uint32_t j = hw_random16(numSprays); // start with random spray so all get a chance to emit a particle if maximum number of particles alive is reached. | |
| 9234 |
2/2✓ Branch 0 taken 248 times.
✓ Branch 1 taken 18 times.
|
266 | for (i = 0; i < numSprays; i++) { |
| 9235 |
12/18✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 248 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 248 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 104 times.
✓ Branch 9 taken 144 times.
✓ Branch 10 taken 104 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 104 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 64 times.
✓ Branch 15 taken 40 times.
✓ Branch 16 taken 64 times.
✓ Branch 17 taken 184 times.
|
248 | if (SEGMENT.call % (32 - (SEGMENT.custom2 >> 3)) == 0 && SEGMENT.custom2 > 0) |
| 9236 |
2/4✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | PartSys->sources[j].source.hue += 1 + (SEGMENT.custom2 >> 4); |
| 9237 | |||
| 9238 |
2/4✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
|
248 | PartSys->sources[j].var = SEGMENT.custom3 >> 2; |
| 9239 |
2/4✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
|
248 | int8_t emitspeed = 5 + (((uint32_t)fftResult[j] * ((uint32_t)SEGMENT.speed + 20)) >> 10); // emit speed according to loudness of band |
| 9240 |
2/4✓ Branch 0 taken 248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
|
248 | uint16_t emitangle = j * angleoffset + SEGENV.aux0; |
| 9241 | |||
| 9242 | 248 | uint32_t emitparticles = 0; | |
| 9243 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 164 times.
|
248 | if (fftResult[j] > threshold) |
| 9244 | 84 | emitparticles = 1; | |
| 9245 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 10 times.
|
164 | else if (fftResult[j] > 0) { // band has low value |
| 9246 | 154 | uint32_t restvolume = ((threshold - fftResult[j]) >> 2) + 2; | |
| 9247 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 146 times.
|
154 | if (hw_random16() % restvolume == 0) |
| 9248 | 8 | emitparticles = 1; | |
| 9249 | } | ||
| 9250 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 156 times.
|
248 | if (emitparticles) |
| 9251 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | PartSys->angleEmit(PartSys->sources[j], emitangle, emitspeed); |
| 9252 | |||
| 9253 | 248 | j = (j + 1) % numSprays; | |
| 9254 | } | ||
| 9255 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9256 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9257 | } | ||
| 9258 | static const char _data_FX_MODE_PARTICLECIRCULARGEQ[] PROGMEM = "PS GEQ Nova@Speed,Intensity,Rotation Speed,Color Change,Nozzle,,Direction;;!;2f;pal=13,ix=180,c1=0,c2=0,c3=8"; | ||
| 9259 | |||
| 9260 | /* | ||
| 9261 | Particle replacement of Ghost Rider by DedeHai (Damian Schneider), original FX by stepko adapted by Blaz Kristan (AKA blazoncek) | ||
| 9262 | */ | ||
| 9263 | #define MAXANGLESTEP 2200 //32767 means 180° | ||
| 9264 | 23 | uint16_t mode_particleghostrider(void) { | |
| 9265 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 9266 | PSsettings2D ghostsettings; | ||
| 9267 | 23 | ghostsettings.asByte = 0b0000011; //enable wrapX and wrapY | |
| 9268 | |||
| 9269 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9270 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1)) // init, no additional data needed |
| 9271 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 9272 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return (except on top, taken care of by gravity setting) |
| 9273 | 4 | PartSys->sources[0].maxLife = 260; // lifetime in frames | |
| 9274 | 4 | PartSys->sources[0].minLife = 250; | |
| 9275 | 4 | PartSys->sources[0].source.x = hw_random16(PartSys->maxX); | |
| 9276 | 4 | PartSys->sources[0].source.y = hw_random16(PartSys->maxY); | |
| 9277 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.step = hw_random16(MAXANGLESTEP) - (MAXANGLESTEP>>1); // angle increment |
| 9278 | } | ||
| 9279 | else { | ||
| 9280 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9281 | } | ||
| 9282 | |||
| 9283 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 9284 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 9285 | |||
| 9286 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.intensity > 0) { // spiraling |
| 9287 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if (SEGENV.aux1) { |
| 9288 | ✗ | SEGENV.step += SEGMENT.intensity>>3; | |
| 9289 | ✗ | if ((int32_t)SEGENV.step > MAXANGLESTEP) | |
| 9290 | ✗ | SEGENV.aux1 = 0; | |
| 9291 | } | ||
| 9292 | else { | ||
| 9293 |
4/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
4 | SEGENV.step -= SEGMENT.intensity>>3; |
| 9294 |
3/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | if ((int32_t)SEGENV.step < -MAXANGLESTEP) |
| 9295 | ✗ | SEGENV.aux1 = 1; | |
| 9296 | } | ||
| 9297 | } | ||
| 9298 | // Particle System settings | ||
| 9299 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9300 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setMotionBlur(SEGMENT.custom1); |
| 9301 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys->sources[0].var = SEGMENT.custom3 >> 1; |
| 9302 | |||
| 9303 | // color by age (PS 'color by age' always starts with hue = 255, don't want that here) | ||
| 9304 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | if (SEGMENT.check1) { |
| 9305 |
2/2✓ Branch 0 taken 6776 times.
✓ Branch 1 taken 18 times.
|
6794 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 9306 | 6776 | PartSys->particles[i].hue = PartSys->sources[0].source.hue + (PartSys->particles[i].ttl<<2); | |
| 9307 | } | ||
| 9308 | } | ||
| 9309 | |||
| 9310 | // enable/disable walls | ||
| 9311 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | ghostsettings.bounceX = SEGMENT.check2; |
| 9312 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | ghostsettings.bounceY = SEGMENT.check2; |
| 9313 | |||
| 9314 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | SEGENV.aux0 += (int32_t)SEGENV.step; // step is angle increment |
| 9315 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint16_t emitangle = SEGENV.aux0 + 32767; // +180° |
| 9316 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | int32_t speed = map(SEGMENT.speed, 0, 255, 12, 64); |
| 9317 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->sources[0].source.vx = ((int32_t)cos16_t(SEGENV.aux0) * speed) / (int32_t)32767; |
| 9318 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->sources[0].source.vy = ((int32_t)sin16_t(SEGENV.aux0) * speed) / (int32_t)32767; |
| 9319 | 18 | PartSys->sources[0].source.ttl = 500; // source never dies (note: setting 'perpetual' is not needed if replenished each frame) | |
| 9320 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags, &ghostsettings); |
| 9321 | // set head (steal one of the particles) | ||
| 9322 | 18 | PartSys->particles[PartSys->usedParticles-1].x = PartSys->sources[0].source.x; | |
| 9323 | 18 | PartSys->particles[PartSys->usedParticles-1].y = PartSys->sources[0].source.y; | |
| 9324 | 18 | PartSys->particles[PartSys->usedParticles-1].ttl = 255; | |
| 9325 | 18 | PartSys->particles[PartSys->usedParticles-1].sat = 0; //white | |
| 9326 | // emit two particles | ||
| 9327 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->angleEmit(PartSys->sources[0], emitangle, speed); |
| 9328 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->angleEmit(PartSys->sources[0], emitangle, speed); |
| 9329 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 11 times.
|
18 | if (SEGMENT.call % (11 - (SEGMENT.custom2 / 25)) == 0) { // every nth frame, cycle color and emit particles |
| 9330 | 7 | PartSys->sources[0].source.hue++; | |
| 9331 | } | ||
| 9332 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 14 times.
|
18 | if (SEGMENT.custom2 > 190) //fast color change |
| 9333 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | PartSys->sources[0].source.hue += (SEGMENT.custom2 - 190) >> 2; |
| 9334 | |||
| 9335 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9336 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9337 | } | ||
| 9338 | static const char _data_FX_MODE_PARTICLEGHOSTRIDER[] PROGMEM = "PS Ghost Rider@Speed,Spiral,Blur,Color Cycle,Spread,AgeColor,Walls;;!;2;pal=1,sx=70,ix=0,c1=220,c2=30,c3=21,o1=1"; | ||
| 9339 | |||
| 9340 | /* | ||
| 9341 | PS Blobs: large particles bouncing around, changing size and form | ||
| 9342 | Uses palette for particle color | ||
| 9343 | by DedeHai (Damian Schneider) | ||
| 9344 | */ | ||
| 9345 | 23 | uint16_t mode_particleblobs(void) { | |
| 9346 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 9347 | |||
| 9348 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { |
| 9349 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 0, 0, true, true)) //init, no additional bytes, advanced size & size control |
| 9350 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 9351 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceX(true); |
| 9352 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setBounceY(true); |
| 9353 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallHardness(255); |
| 9354 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallRoughness(255); |
| 9355 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setCollisionHardness(255); |
| 9356 | } | ||
| 9357 | else | ||
| 9358 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9359 | |||
| 9360 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 9361 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 9362 | |||
| 9363 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9364 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setUsedParticles(map(SEGMENT.intensity, 0, 255, 25, 128)); // minimum 10%, maximum 50% of available particles (note: PS ensures at least 1) |
| 9365 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->enableParticleCollisions(SEGMENT.check2); |
| 9366 | |||
| 9367 |
2/2✓ Branch 0 taken 187 times.
✓ Branch 1 taken 18 times.
|
205 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { // update particles |
| 9368 |
10/14✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 187 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 187 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 148 times.
✓ Branch 9 taken 39 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 143 times.
✓ Branch 12 taken 44 times.
✓ Branch 13 taken 143 times.
|
187 | if (SEGENV.aux0 != SEGMENT.speed || PartSys->particles[i].ttl == 0) { // speed changed or dead |
| 9369 |
4/8✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
|
44 | PartSys->particles[i].vx = (int8_t)hw_random16(SEGMENT.speed >> 1) - (SEGMENT.speed >> 2); // +/- speed/4 |
| 9370 |
4/8✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
|
44 | PartSys->particles[i].vy = (int8_t)hw_random16(SEGMENT.speed >> 1) - (SEGMENT.speed >> 2); |
| 9371 | } | ||
| 9372 |
10/14✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 187 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 187 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 148 times.
✓ Branch 9 taken 39 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 143 times.
✓ Branch 12 taken 44 times.
✓ Branch 13 taken 143 times.
|
187 | if (SEGENV.aux1 != SEGMENT.custom1 || PartSys->particles[i].ttl == 0) // size changed or dead |
| 9373 |
4/8✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
|
44 | PartSys->advPartSize[i].maxsize = 60 + (SEGMENT.custom1 >> 1) + hw_random16((SEGMENT.custom1 >> 2)); // set each particle to slightly randomized size |
| 9374 | |||
| 9375 | //PartSys->particles[i].perpetual = SEGMENT.check2; //infinite life if set | ||
| 9376 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 143 times.
|
187 | if (PartSys->particles[i].ttl == 0) { // find dead particle, renitialize |
| 9377 |
2/4✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
|
44 | PartSys->particles[i].ttl = 300 + hw_random16(((uint16_t)SEGMENT.custom2 << 3) + 100); |
| 9378 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | PartSys->particles[i].x = hw_random(PartSys->maxX); |
| 9379 | 44 | PartSys->particles[i].y = hw_random16(PartSys->maxY); | |
| 9380 | 44 | PartSys->particles[i].hue = hw_random16(); // set random color | |
| 9381 | 44 | PartSys->particleFlags[i].collide = true; // enable collision for particle | |
| 9382 | 44 | PartSys->advPartProps[i].size = 0; // start out small | |
| 9383 | 44 | PartSys->advPartSize[i].asymmetry = hw_random16(220); | |
| 9384 | 44 | PartSys->advPartSize[i].asymdir = hw_random16(255); | |
| 9385 | // set advanced size control properties | ||
| 9386 | 44 | PartSys->advPartSize[i].grow = true; | |
| 9387 | 44 | PartSys->advPartSize[i].growspeed = 1 + hw_random16(9); | |
| 9388 | 44 | PartSys->advPartSize[i].shrinkspeed = 1 + hw_random16(9); | |
| 9389 | 44 | PartSys->advPartSize[i].wobblespeed = 1 + hw_random16(3); | |
| 9390 | } | ||
| 9391 | //PartSys->advPartSize[i].asymmetry++; | ||
| 9392 |
2/4✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
|
187 | PartSys->advPartSize[i].pulsate = SEGMENT.check3; |
| 9393 |
2/4✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
|
187 | PartSys->advPartSize[i].wobble = SEGMENT.check1; |
| 9394 | } | ||
| 9395 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | SEGENV.aux0 = SEGMENT.speed; //write state back |
| 9396 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | SEGENV.aux1 = SEGMENT.custom1; |
| 9397 | |||
| 9398 | #ifdef USERMOD_AUDIOREACTIVE | ||
| 9399 | um_data_t *um_data; | ||
| 9400 | if (UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // get AR data, do not use simulated data | ||
| 9401 | uint8_t volumeSmth = (uint8_t)(*(float*)um_data->u_data[0]); | ||
| 9402 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { // update particles | ||
| 9403 | if (SEGMENT.check3) //pulsate selected | ||
| 9404 | PartSys->advPartProps[i].size = volumeSmth; | ||
| 9405 | } | ||
| 9406 | } | ||
| 9407 | #endif | ||
| 9408 | |||
| 9409 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setMotionBlur(((SEGMENT.custom3) << 3) + 7); |
| 9410 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9411 | |||
| 9412 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9413 | } | ||
| 9414 | static const char _data_FX_MODE_PARTICLEBLOBS[] PROGMEM = "PS Blobs@Speed,Blobs,Size,Life,Blur,Wobble,Collide,Pulsate;;!;2v;sx=30,ix=64,c1=200,c2=130,c3=0,o3=1"; | ||
| 9415 | |||
| 9416 | ///////////////////////// | ||
| 9417 | // PS Galaxy // | ||
| 9418 | ///////////////////////// | ||
| 9419 | // Spiral galaxy with an emitter moving around, particles spiral into the center. | ||
| 9420 | // Also has a starfield mode where particles fly outwards from the center. | ||
| 9421 | // Ported from upstream WLED. By DedeHai (Damian Schneider) | ||
| 9422 | 23 | uint16_t mode_particlegalaxy(void) { | |
| 9423 | 23 | ParticleSystem2D *PartSys = nullptr; | |
| 9424 | PSsettings2D sourcesettings; | ||
| 9425 | 23 | sourcesettings.asByte = 0b00001100; // PS settings for bounceY, bounceY used for source movement (it always bounces whereas particles do not) | |
| 9426 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9427 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
5 | if (!initParticleSystem2D(PartSys, 1, 0, true)) // init using 1 source and advanced particle settings |
| 9428 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return mode_static(); // allocation failed or not 2D |
| 9429 | 4 | PartSys->sources[0].source.vx = -4; // will collide with wall and get random bounce direction | |
| 9430 | 4 | PartSys->sources[0].source.x = PartSys->maxX >> 1; // start in the center | |
| 9431 | 4 | PartSys->sources[0].source.y = PartSys->maxY >> 1; | |
| 9432 | 4 | PartSys->sources[0].sourceFlags.perpetual = true; //source does not age | |
| 9433 | 4 | PartSys->sources[0].maxLife = 4000; // lifetime in frames | |
| 9434 | 4 | PartSys->sources[0].minLife = 800; | |
| 9435 | 4 | PartSys->sources[0].source.hue = hw_random16(); // start with random color | |
| 9436 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallHardness(255); //bounce forever |
| 9437 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | PartSys->setWallRoughness(200); //randomize wall bounce |
| 9438 | } | ||
| 9439 | else { | ||
| 9440 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9441 | } | ||
| 9442 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
|
22 | if (PartSys == nullptr) |
| 9443 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return mode_static(); // something went wrong, no data! |
| 9444 | // Particle System settings | ||
| 9445 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9446 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | uint8_t particlesize = SEGMENT.custom1; |
| 9447 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->setParticleSize(particlesize); // set size globally |
| 9448 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | PartSys->setMotionBlur(250 * SEGMENT.check3); // adds trails to single/quad pixel particles, no effect if size > 1 |
| 9449 | |||
| 9450 |
6/10✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 11 times.
|
18 | if ((SEGMENT.call % ((33 - SEGMENT.custom3) >> 1)) == 0) // change hue of emitted particles |
| 9451 | 7 | PartSys->sources[0].source.hue+=2; | |
| 9452 | |||
| 9453 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12 times.
|
18 | if (hw_random8() < (10 + (SEGMENT.intensity >> 1))) // 5%-55% chance to emit a particle in this frame |
| 9454 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | PartSys->sprayEmit(PartSys->sources[0]); |
| 9455 | |||
| 9456 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12 times.
|
18 | if ((SEGMENT.call & 0x3) == 0) // every 4th frame, move the emitter |
| 9457 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags, &sourcesettings); |
| 9458 | |||
| 9459 | // move alive particles in a spiral motion (or almost straight in fast starfield mode) | ||
| 9460 | 18 | int32_t centerx = PartSys->maxX >> 1; // center of matrix in subpixel coordinates | |
| 9461 | 18 | int32_t centery = PartSys->maxY >> 1; | |
| 9462 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (SEGMENT.check2) { // starfield mode |
| 9463 | ✗ | PartSys->setKillOutOfBounds(true); | |
| 9464 | ✗ | PartSys->sources[0].var = 7; // emiting variation | |
| 9465 | ✗ | PartSys->sources[0].source.x = centerx; // set emitter to center | |
| 9466 | ✗ | PartSys->sources[0].source.y = centery; | |
| 9467 | } | ||
| 9468 | else { | ||
| 9469 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->setKillOutOfBounds(false); |
| 9470 | 18 | PartSys->sources[0].var = 1; // emiting variation | |
| 9471 | } | ||
| 9472 |
2/2✓ Branch 0 taken 5664 times.
✓ Branch 1 taken 18 times.
|
5682 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { //check all particles |
| 9473 |
2/2✓ Branch 0 taken 5649 times.
✓ Branch 1 taken 15 times.
|
5664 | if (PartSys->particles[i].ttl == 0) continue; //skip dead particles |
| 9474 | // (dx/dy): vector pointing from particle to center | ||
| 9475 | 15 | int32_t dx = centerx - PartSys->particles[i].x; | |
| 9476 | 15 | int32_t dy = centery - PartSys->particles[i].y; | |
| 9477 | //speed towards center: | ||
| 9478 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | int32_t distance = sqrt32_bw(dx * dx + dy * dy); // absolute distance to center |
| 9479 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (distance < 20) distance = 20; // avoid division by zero, keep a minimum |
| 9480 | int32_t speedfactor; | ||
| 9481 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
|
15 | if (SEGMENT.check2) { // starfield mode |
| 9482 | ✗ | speedfactor = 1 + (1 + (SEGMENT.speed >> 1)) * distance; // speed increases towards edge | |
| 9483 | //apply velocity | ||
| 9484 | ✗ | PartSys->particles[i].x += (-speedfactor * dx) / 400000 - (dy >> 6); | |
| 9485 | ✗ | PartSys->particles[i].y += (-speedfactor * dy) / 400000 + (dx >> 6); | |
| 9486 | } | ||
| 9487 | else { | ||
| 9488 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | speedfactor = 2 + (((50 + SEGMENT.speed) << 6) / distance); // speed increases towards center |
| 9489 | // rotate clockwise | ||
| 9490 | 15 | int32_t tempVx = (-speedfactor * dy); // speed is orthogonal to center vector | |
| 9491 | 15 | int32_t tempVy = (speedfactor * dx); | |
| 9492 | //add speed towards center to make particles spiral in | ||
| 9493 | 15 | int vxc = (dx << 9) / (distance - 19); // subtract value from distance to make the pull-in force a bit stronger (helps on faster speeds) | |
| 9494 | 15 | int vyc = (dy << 9) / (distance - 19); | |
| 9495 | //apply velocity | ||
| 9496 | 15 | PartSys->particles[i].x += (tempVx + vxc) / 1024; // note: cannot use bit shift as that causes asymmetric rounding | |
| 9497 | 15 | PartSys->particles[i].y += (tempVy + vyc) / 1024; | |
| 9498 | |||
| 9499 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (distance < 128) { // close to center |
| 9500 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (PartSys->particles[i].ttl > 3) |
| 9501 | 15 | PartSys->particles[i].ttl -= 4; //age fast | |
| 9502 | 15 | PartSys->particles[i].sat = distance << 1; // turn white towards center | |
| 9503 | } | ||
| 9504 | } | ||
| 9505 |
4/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 8 times.
|
15 | if(SEGMENT.custom3 == 31) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors |
| 9506 | 7 | PartSys->particles[i].hue = PartSys->particles[i].ttl >> 2; | |
| 9507 |
3/6✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
|
8 | else if(SEGMENT.custom3 == 0) // color by distance |
| 9508 | ✗ | PartSys->particles[i].hue = map(distance, 20, (PartSys->maxX + PartSys->maxY) >> 2, 0, 180); // color by distance to center | |
| 9509 | } | ||
| 9510 | |||
| 9511 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->update(); // update and render |
| 9512 | |||
| 9513 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | return FRAMETIME; |
| 9514 | } | ||
| 9515 | static const char _data_FX_MODE_PARTICLEGALAXY[] PROGMEM = "PS Galaxy@!,!,Size,,Color,,Starfield,Trace;;!;2;pal=59,sx=80,c1=1,c3=4"; | ||
| 9516 | |||
| 9517 | #endif //WLED_DISABLE_PARTICLESYSTEM2D | ||
| 9518 | #endif // WLED_DISABLE_2D | ||
| 9519 | |||
| 9520 | /////////////////////////// | ||
| 9521 | // 1D Particle System FX // | ||
| 9522 | /////////////////////////// | ||
| 9523 | |||
| 9524 | #ifndef WLED_DISABLE_PARTICLESYSTEM1D | ||
| 9525 | /* | ||
| 9526 | Particle version of Drip and Rain | ||
| 9527 | Uses palette for particle color | ||
| 9528 | by DedeHai (Damian Schneider) | ||
| 9529 | */ | ||
| 9530 | 23 | uint16_t mode_particleDrip(void) { | |
| 9531 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 9532 | //uint8_t numSprays; | ||
| 9533 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9534 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 4)) // init |
| 9535 | ✗ | return mode_static(); // allocation failed or single pixel | |
| 9536 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return (except on top, taken care of by gravity setting) |
| 9537 | 5 | PartSys->sources[0].source.hue = hw_random16(); | |
| 9538 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux1 = 0xFFFF; // invalidate |
| 9539 | } | ||
| 9540 | else | ||
| 9541 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9542 | |||
| 9543 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 9544 | ✗ | return mode_static(); // something went wrong, no data! | |
| 9545 | |||
| 9546 | // Particle System settings | ||
| 9547 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9548 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setBounce(true); |
| 9549 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setWallHardness(50); |
| 9550 | |||
| 9551 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 9552 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setGravity(SEGMENT.custom3 >> 1); // set gravity (8 is default strength) |
| 9553 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setParticleSize(SEGMENT.check3); // 1 or 2 pixel rendering |
| 9554 | |||
| 9555 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check2) { //collisions enabled |
| 9556 | ✗ | PartSys->enableParticleCollisions(true); //enable, full hardness | |
| 9557 | } | ||
| 9558 | else | ||
| 9559 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->enableParticleCollisions(false); |
| 9560 | |||
| 9561 | 23 | PartSys->sources[0].sourceFlags.collide = false; //drops do not collide | |
| 9562 | |||
| 9563 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check1) { //rain mode, emit at random position, short life (3-8 seconds at 50fps) |
| 9564 | ✗ | if (SEGMENT.custom1 == 0) //splash disabled, do not bounce raindrops | |
| 9565 | ✗ | PartSys->setBounce(false); | |
| 9566 | ✗ | PartSys->sources[0].var = 5; | |
| 9567 | ✗ | PartSys->sources[0].v = -(8 + (SEGMENT.speed >> 2)); //speed + var must be < 128, inverted speed (=down) | |
| 9568 | // lifetime in frames | ||
| 9569 | ✗ | PartSys->sources[0].minLife = 30; | |
| 9570 | ✗ | PartSys->sources[0].maxLife = 200; | |
| 9571 | ✗ | PartSys->sources[0].source.x = hw_random(PartSys->maxX); //random emit position | |
| 9572 | } | ||
| 9573 | else { //drip | ||
| 9574 | 23 | PartSys->sources[0].var = 0; | |
| 9575 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].v = -(SEGMENT.speed >> 1); //speed + var must be < 128, inverted speed (=down) |
| 9576 | 23 | PartSys->sources[0].minLife = 3000; | |
| 9577 | 23 | PartSys->sources[0].maxLife = 3000; | |
| 9578 | 23 | PartSys->sources[0].source.x = PartSys->maxX - PS_P_RADIUS_1D; | |
| 9579 | } | ||
| 9580 | |||
| 9581 |
6/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 18 times.
|
23 | if (SEGENV.aux1 != SEGMENT.intensity) //slider changed |
| 9582 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = 1; //must not be zero or "% 0" happens below which crashes on ESP32 |
| 9583 | |||
| 9584 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | SEGENV.aux1 = SEGMENT.intensity; // save state |
| 9585 | |||
| 9586 | // every nth frame emit a particle | ||
| 9587 |
6/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 17 times.
|
23 | if (SEGMENT.call % SEGENV.aux0 == 0) { |
| 9588 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | int32_t interval = 300 / ((SEGMENT.intensity) + 1); |
| 9589 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | SEGENV.aux0 = interval + hw_random(interval + 5); |
| 9590 | // if (SEGMENT.check1) // rain mode | ||
| 9591 | // PartSys->sources[0].source.hue = 0; | ||
| 9592 | // else | ||
| 9593 | 6 | PartSys->sources[0].source.hue = hw_random8(); //set random color TODO: maybe also not random but color cycling? need another slider or checkmark for this. | |
| 9594 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | PartSys->sprayEmit(PartSys->sources[0]); |
| 9595 | } | ||
| 9596 | |||
| 9597 |
2/2✓ Branch 0 taken 7536 times.
✓ Branch 1 taken 23 times.
|
7559 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { //check all particles |
| 9598 |
3/4✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7511 times.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
7536 | if (PartSys->particles[i].ttl && PartSys->particleFlags[i].collide == false) { // use collision flag to identify splash particles |
| 9599 |
6/10✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 25 times.
|
25 | if (SEGMENT.custom1 > 0 && PartSys->particles[i].x < (PS_P_RADIUS_1D << 1)) { //splash enabled and reached bottom |
| 9600 | ✗ | PartSys->particles[i].ttl = 0; //kill origin particle | |
| 9601 | ✗ | PartSys->sources[0].maxLife = 80; | |
| 9602 | ✗ | PartSys->sources[0].minLife = 20; | |
| 9603 | ✗ | PartSys->sources[0].var = 10 + (SEGMENT.custom1 >> 3); | |
| 9604 | ✗ | PartSys->sources[0].v = 0; | |
| 9605 | ✗ | PartSys->sources[0].source.hue = PartSys->particles[i].hue; | |
| 9606 | ✗ | PartSys->sources[0].source.x = PS_P_RADIUS_1D; | |
| 9607 | ✗ | PartSys->sources[0].sourceFlags.collide = true; //splashes do collide if enabled | |
| 9608 | ✗ | for (int j = 0; j < 2 + (SEGMENT.custom1 >> 2); j++) { | |
| 9609 | ✗ | PartSys->sprayEmit(PartSys->sources[0]); | |
| 9610 | } | ||
| 9611 | } | ||
| 9612 | } | ||
| 9613 | |||
| 9614 |
3/6✓ Branch 0 taken 7536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7536 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7536 times.
|
7536 | if (SEGMENT.check1) { //rain mode, fade hue to max |
| 9615 | ✗ | if (PartSys->particles[i].hue < 245) | |
| 9616 | ✗ | PartSys->particles[i].hue += 8; | |
| 9617 | } | ||
| 9618 | //increase speed on high settings by calling the move function twice | ||
| 9619 |
4/6✓ Branch 0 taken 7536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7536 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2048 times.
✓ Branch 5 taken 5488 times.
|
7536 | if (SEGMENT.speed > 200) |
| 9620 |
1/2✓ Branch 0 taken 2048 times.
✗ Branch 1 not taken.
|
2048 | PartSys->particleMoveUpdate(PartSys->particles[i], PartSys->particleFlags[i]); |
| 9621 | } | ||
| 9622 | |||
| 9623 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 9624 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 9625 | } | ||
| 9626 | static const char _data_FX_MODE_PARTICLEDRIP[] PROGMEM = "PS DripDrop@Speed,!,Splash,Blur,Gravity,Rain,PushSplash,Smooth;,!;!;1;pal=0,sx=150,ix=25,c1=220,c2=30,c3=21"; | ||
| 9627 | |||
| 9628 | |||
| 9629 | /* | ||
| 9630 | Particle Replacement for "Bbouncing Balls by Aircoookie" | ||
| 9631 | Also replaces rolling balls and juggle (and maybe popcorn) | ||
| 9632 | Uses palette for particle color | ||
| 9633 | by DedeHai (Damian Schneider) | ||
| 9634 | */ | ||
| 9635 | 23 | uint16_t mode_particlePinball(void) { | |
| 9636 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 9637 | |||
| 9638 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9639 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 128, 0, true)) // init |
| 9640 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 9641 | 5 | PartSys->sources[0].sourceFlags.collide = true; // seeded particles will collide (if enabled) | |
| 9642 | 5 | PartSys->sources[0].source.x = PS_P_RADIUS_1D; //emit at bottom | |
| 9643 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); // out of bounds particles dont return |
| 9644 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = 1; |
| 9645 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux1 = 5000; //set out of range to ensure uptate on first call |
| 9646 | } | ||
| 9647 | else | ||
| 9648 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9649 | |||
| 9650 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 9651 | ✗ | return mode_static(); // something went wrong, no data! | |
| 9652 | |||
| 9653 | // Particle System settings | ||
| 9654 | //uint32_t hardness = 240 + (SEGMENT.custom1>>4); | ||
| 9655 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9656 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setGravity(map(SEGMENT.custom3, 0 , 31, 0 , 16)); // set gravity (8 is default strength) |
| 9657 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setBounce(SEGMENT.custom3); // disables bounce if no gravity is used |
| 9658 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 9659 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->enableParticleCollisions(SEGMENT.check1, 255); // enable collisions and set particle collision to high hardness |
| 9660 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setUsedParticles(SEGMENT.intensity); |
| 9661 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setColorByPosition(SEGMENT.check3); |
| 9662 | |||
| 9663 | 23 | bool updateballs = false; | |
| 9664 |
12/22✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 23 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 23 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 23 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 5 times.
✓ Branch 21 taken 18 times.
|
23 | if (SEGENV.aux1 != SEGMENT.speed + SEGMENT.intensity + SEGMENT.check2 + SEGMENT.custom1 + PartSys->usedParticles) { // user settings change or more particles are available |
| 9665 |
4/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | SEGENV.step = SEGMENT.call; // reset delay |
| 9666 | 5 | updateballs = true; | |
| 9667 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
|
5 | PartSys->sources[0].maxLife = SEGMENT.custom3 ? 5000 : 0xFFFF; // maximum lifetime in frames/2 (very long if not using gravity, this is enough to travel 4000 pixels at min speed) |
| 9668 | 5 | PartSys->sources[0].minLife = PartSys->sources[0].maxLife >> 1; | |
| 9669 | } | ||
| 9670 | |||
| 9671 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check2) { //rolling balls |
| 9672 | ✗ | PartSys->setGravity(0); | |
| 9673 | ✗ | PartSys->setWallHardness(255); | |
| 9674 | ✗ | int speedsum = 0; | |
| 9675 | ✗ | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { | |
| 9676 | ✗ | PartSys->particles[i].ttl = 260; // keep particles alive | |
| 9677 | ✗ | if (updateballs) { //speed changed or particle is dead, set particle properties | |
| 9678 | ✗ | PartSys->particleFlags[i].collide = true; | |
| 9679 | ✗ | if (PartSys->particles[i].x == 0) { // still at initial position (when not switching from a PS) | |
| 9680 | ✗ | PartSys->particles[i].x = hw_random16(PartSys->maxX); // random initial position for all particles | |
| 9681 | ✗ | PartSys->particles[i].vx = (hw_random16() & 0x01) ? 1 : -1; // random initial direction | |
| 9682 | } | ||
| 9683 | ✗ | PartSys->particles[i].hue = hw_random8(); //set ball colors to random | |
| 9684 | ✗ | PartSys->advPartProps[i].sat = 255; | |
| 9685 | ✗ | PartSys->advPartProps[i].size = SEGMENT.custom1; | |
| 9686 | } | ||
| 9687 | ✗ | speedsum += abs(PartSys->particles[i].vx); | |
| 9688 | } | ||
| 9689 | ✗ | int32_t avgSpeed = speedsum / PartSys->usedParticles; | |
| 9690 | ✗ | int32_t setSpeed = 2 + (SEGMENT.speed >> 3); | |
| 9691 | ✗ | if (avgSpeed < setSpeed) { // if balls are slow, speed up some of them at random to keep the animation going | |
| 9692 | ✗ | for (int i = 0; i < setSpeed - avgSpeed; i++) { | |
| 9693 | ✗ | int idx = hw_random16(PartSys->usedParticles); | |
| 9694 | ✗ | PartSys->particles[idx].vx += PartSys->particles[idx].vx >= 0 ? 1 : -1; // add 1, keep direction | |
| 9695 | } | ||
| 9696 | } | ||
| 9697 | ✗ | else if (avgSpeed > setSpeed + 8) // if avg speed is too high, apply friction to slow them down | |
| 9698 | ✗ | PartSys->applyFriction(1); | |
| 9699 | } | ||
| 9700 | else { //bouncing balls | ||
| 9701 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setWallHardness(220); |
| 9702 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].var = SEGMENT.speed >> 3; |
| 9703 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | int32_t newspeed = 2 + (SEGMENT.speed >> 1) - (SEGMENT.speed >> 3); |
| 9704 | 23 | PartSys->sources[0].v = newspeed; | |
| 9705 | //check for balls that are 'laying on the ground' and remove them | ||
| 9706 |
2/2✓ Branch 0 taken 1887 times.
✓ Branch 1 taken 23 times.
|
1910 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 9707 |
7/10✓ Branch 0 taken 1090 times.
✓ Branch 1 taken 797 times.
✓ Branch 2 taken 1090 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1090 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1090 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1090 times.
✓ Branch 9 taken 797 times.
|
1887 | if (PartSys->particles[i].vx == 0 && PartSys->particles[i].x < (PS_P_RADIUS_1D + SEGMENT.custom1)) |
| 9708 | 1090 | PartSys->particles[i].ttl = 0; | |
| 9709 |
2/2✓ Branch 0 taken 415 times.
✓ Branch 1 taken 1472 times.
|
1887 | if (updateballs) { |
| 9710 |
2/4✓ Branch 0 taken 415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 415 times.
✗ Branch 3 not taken.
|
415 | PartSys->advPartProps[i].size = SEGMENT.custom1; |
| 9711 |
3/6✓ Branch 0 taken 415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 415 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 415 times.
|
415 | if (SEGMENT.custom3 == 0) //gravity off, update speed |
| 9712 | ✗ | PartSys->particles[i].vx = PartSys->particles[i].vx > 0 ? newspeed : -newspeed; //keep the direction | |
| 9713 | } | ||
| 9714 | } | ||
| 9715 | |||
| 9716 | // every nth frame emit a ball | ||
| 9717 |
6/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 18 times.
|
23 | if (SEGMENT.call > SEGENV.step) { |
| 9718 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | int interval = 260 - ((int)SEGMENT.intensity); |
| 9719 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.step += interval + hw_random16(interval); |
| 9720 | 5 | PartSys->sources[0].source.hue = hw_random16(); //set ball color | |
| 9721 | 5 | PartSys->sources[0].sat = 255; | |
| 9722 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->sources[0].size = SEGMENT.custom1; |
| 9723 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->sprayEmit(PartSys->sources[0]); |
| 9724 | } | ||
| 9725 | } | ||
| 9726 |
10/20✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 23 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 23 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 23 times.
✗ Branch 19 not taken.
|
23 | SEGENV.aux1 = SEGMENT.speed + SEGMENT.intensity + SEGMENT.check2 + SEGMENT.custom1 + PartSys->usedParticles; |
| 9727 |
2/2✓ Branch 0 taken 1887 times.
✓ Branch 1 taken 23 times.
|
1910 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 9728 |
1/2✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
|
1887 | PartSys->particleMoveUpdate(PartSys->particles[i], PartSys->particleFlags[i]); // double the speed |
| 9729 | } | ||
| 9730 | |||
| 9731 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 9732 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 9733 | } | ||
| 9734 | static const char _data_FX_MODE_PSPINBALL[] PROGMEM = "PS Pinball@Speed,!,Size,Blur,Gravity,Collide,Rolling,Position Color;,!;!;1;pal=0,ix=220,c2=0,c3=8,o1=1"; | ||
| 9735 | |||
| 9736 | /* | ||
| 9737 | Particle Replacement for original Dancing Shadows: | ||
| 9738 | "Spotlights moving back and forth that cast dancing shadows. | ||
| 9739 | Shine this through tree branches/leaves or other close-up objects that cast | ||
| 9740 | interesting shadows onto a ceiling or tarp. | ||
| 9741 | By Steve Pomeroy @xxv" | ||
| 9742 | Uses palette for particle color | ||
| 9743 | by DedeHai (Damian Schneider) | ||
| 9744 | */ | ||
| 9745 | 1283 | uint16_t mode_particleDancingShadows(void) { | |
| 9746 | 1283 | ParticleSystem1D *PartSys = nullptr; | |
| 9747 | |||
| 9748 |
4/6✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1275 times.
|
1283 | if (SEGMENT.call == 0) { // initialization |
| 9749 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
8 | if (!initParticleSystem1D(PartSys, 1)) // init, one source |
| 9750 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 9751 | 8 | PartSys->sources[0].maxLife = 1000; //set long life (kill out of bounds is done in custom way) | |
| 9752 | 8 | PartSys->sources[0].minLife = PartSys->sources[0].maxLife; | |
| 9753 | } | ||
| 9754 | else { | ||
| 9755 |
2/4✓ Branch 0 taken 1275 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1275 times.
✗ Branch 3 not taken.
|
1275 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9756 | } | ||
| 9757 | |||
| 9758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1283 times.
|
1283 | if (PartSys == nullptr) |
| 9759 | ✗ | return mode_static(); // something went wrong, no data! | |
| 9760 | |||
| 9761 | // Particle System settings | ||
| 9762 |
1/2✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
|
1283 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9763 |
3/6✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1283 times.
✗ Branch 5 not taken.
|
1283 | PartSys->setMotionBlur(SEGMENT.custom1); |
| 9764 |
3/6✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1283 times.
|
1283 | if (SEGMENT.check1) |
| 9765 | ✗ | PartSys->setSmearBlur(120); // enable smear blur | |
| 9766 | else | ||
| 9767 |
1/2✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
|
1283 | PartSys->setSmearBlur(0); // disable smear blur |
| 9768 |
3/6✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1283 times.
✗ Branch 5 not taken.
|
1283 | PartSys->setParticleSize(SEGMENT.check3); // 1 or 2 pixel rendering |
| 9769 |
3/6✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1283 times.
✗ Branch 5 not taken.
|
1283 | PartSys->setColorByPosition(SEGMENT.check2); // color fixed by position |
| 9770 |
3/6✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1283 times.
✗ Branch 5 not taken.
|
1283 | PartSys->setUsedParticles(map(SEGMENT.intensity, 0, 255, 10, 255)); // set percentage of particles to use |
| 9771 | |||
| 9772 | 1283 | uint32_t deadparticles = 0; | |
| 9773 | //kill out of bounds and moving away plus change color | ||
| 9774 |
2/2✓ Branch 0 taken 35251 times.
✓ Branch 1 taken 1283 times.
|
36534 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 9775 |
8/10✓ Branch 0 taken 35251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35251 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4894 times.
✓ Branch 5 taken 30357 times.
✓ Branch 6 taken 863 times.
✓ Branch 7 taken 4031 times.
✓ Branch 8 taken 863 times.
✓ Branch 9 taken 34388 times.
|
35251 | if (((SEGMENT.call & 0x07) == 0) && PartSys->particleFlags[i].outofbounds) { //check if out of bounds particle move away from strip, only update every 8th frame |
| 9776 |
2/2✓ Branch 0 taken 525 times.
✓ Branch 1 taken 338 times.
|
863 | if ((int32_t)PartSys->particles[i].vx * PartSys->particles[i].x > 0) PartSys->particles[i].ttl = 0; //particle is moving away, kill it |
| 9777 | } | ||
| 9778 | 35251 | PartSys->particleFlags[i].perpetual = true; //particles do not age | |
| 9779 |
6/10✓ Branch 0 taken 35251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35251 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 35251 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 35251 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3583 times.
✓ Branch 9 taken 31668 times.
|
35251 | if (SEGMENT.call % (32 / (1 + (SEGMENT.custom2 >> 3))) == 0) |
| 9780 |
2/4✓ Branch 0 taken 3583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3583 times.
✗ Branch 3 not taken.
|
3583 | PartSys->particles[i].hue += 2 + (SEGMENT.custom2 >> 5); |
| 9781 | //note: updating speed on the fly is not accurately possible, since it is unknown which particles are assigned to which spot | ||
| 9782 |
6/10✓ Branch 0 taken 35251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35251 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 35251 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 35251 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1076 times.
✓ Branch 9 taken 34175 times.
|
35251 | if (SEGENV.aux0 != SEGMENT.speed) { //speed changed |
| 9783 | //update all particle speed by setting them to current value | ||
| 9784 |
3/10✗ Branch 0 not taken.
✓ Branch 1 taken 1076 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1076 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1076 times.
✗ Branch 9 not taken.
|
1076 | PartSys->particles[i].vx = PartSys->particles[i].vx > 0 ? SEGMENT.speed >> 3 : -SEGMENT.speed >> 3; |
| 9785 | } | ||
| 9786 |
2/2✓ Branch 0 taken 10057 times.
✓ Branch 1 taken 25194 times.
|
35251 | if (PartSys->particles[i].ttl == 0) deadparticles++; // count dead particles |
| 9787 | } | ||
| 9788 |
4/8✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1283 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1283 times.
✗ Branch 7 not taken.
|
1283 | SEGENV.aux0 = SEGMENT.speed; |
| 9789 | |||
| 9790 | //generate a spotlight: generates particles just outside of view | ||
| 9791 |
8/10✓ Branch 0 taken 264 times.
✓ Branch 1 taken 1019 times.
✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 264 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 99 times.
✓ Branch 7 taken 165 times.
✓ Branch 8 taken 99 times.
✓ Branch 9 taken 1184 times.
|
1283 | if (deadparticles > 5 && (SEGMENT.call & 0x03) == 0) { |
| 9792 | //random color, random type | ||
| 9793 | 99 | uint32_t type = hw_random16(SPOT_TYPES_COUNT); | |
| 9794 |
4/8✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 99 times.
✗ Branch 7 not taken.
|
99 | int8_t speed = 2 + hw_random16(2 + (SEGMENT.speed >> 1)) + (SEGMENT.speed >> 4); |
| 9795 | 99 | int32_t width = hw_random16(1, 10); | |
| 9796 | 99 | uint32_t ttl = 300; //ttl is particle brightness (below perpetual is set so it does not age, i.e. ttl stays at this value) | |
| 9797 | int32_t position; | ||
| 9798 | //choose random start position, left and right from the segment | ||
| 9799 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 44 times.
|
99 | if (hw_random() & 0x01) { |
| 9800 | 55 | position = PartSys->maxXpixel; | |
| 9801 | 55 | speed = -speed; | |
| 9802 | } | ||
| 9803 | else | ||
| 9804 | 44 | position = -width; | |
| 9805 | |||
| 9806 | 99 | PartSys->sources[0].v = speed; //emitted particle speed | |
| 9807 | 99 | PartSys->sources[0].source.hue = hw_random8(); //random spotlight color | |
| 9808 |
2/2✓ Branch 0 taken 376 times.
✓ Branch 1 taken 99 times.
|
475 | for (int32_t i = 0; i < width; i++) { |
| 9809 |
2/2✓ Branch 0 taken 355 times.
✓ Branch 1 taken 21 times.
|
376 | if (width > 1) { |
| 9810 |
6/7✓ Branch 0 taken 99 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
|
355 | switch (type) { |
| 9811 | 99 | case SPOT_TYPE_SOLID: | |
| 9812 | //nothing to do | ||
| 9813 | 99 | break; | |
| 9814 | |||
| 9815 | 85 | case SPOT_TYPE_GRADIENT: | |
| 9816 | 85 | ttl = cubicwave8(map(i, 0, width - 1, 0, 255)); | |
| 9817 | 85 | ttl = ttl*ttl >> 8; //make gradient more pronounced | |
| 9818 | 85 | break; | |
| 9819 | |||
| 9820 | 90 | case SPOT_TYPE_2X_GRADIENT: | |
| 9821 | 90 | ttl = cubicwave8(2 * map(i, 0, width - 1, 0, 255)); | |
| 9822 | 90 | ttl = ttl*ttl >> 8; | |
| 9823 | 90 | break; | |
| 9824 | |||
| 9825 | 34 | case SPOT_TYPE_2X_DOT: | |
| 9826 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 11 times.
|
34 | if (i > 0) position++; //skip one pixel |
| 9827 | 34 | i++; | |
| 9828 | 34 | break; | |
| 9829 | |||
| 9830 | 22 | case SPOT_TYPE_3X_DOT: | |
| 9831 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 10 times.
|
22 | if (i > 0) position += 2; //skip two pixels |
| 9832 | 22 | i+=2; | |
| 9833 | 22 | break; | |
| 9834 | |||
| 9835 | 25 | case SPOT_TYPE_4X_DOT: | |
| 9836 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 14 times.
|
25 | if (i > 0) position += 3; //skip three pixels |
| 9837 | 25 | i+=3; | |
| 9838 | 25 | break; | |
| 9839 | } | ||
| 9840 | } | ||
| 9841 | //emit particle | ||
| 9842 | //set the particle source position: | ||
| 9843 | 376 | PartSys->sources[0].source.x = position * PS_P_RADIUS_1D; | |
| 9844 |
1/2✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
|
376 | int32_t partidx = PartSys->sprayEmit(PartSys->sources[0]); |
| 9845 |
2/2✓ Branch 0 taken 365 times.
✓ Branch 1 taken 11 times.
|
376 | if (partidx >= 0) PartSys->particles[partidx].ttl = ttl; // -1 = no free particle |
| 9846 | 376 | position++; //do the next pixel | |
| 9847 | } | ||
| 9848 | } | ||
| 9849 | |||
| 9850 |
1/2✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
|
1283 | PartSys->update(); // update and render |
| 9851 | |||
| 9852 |
1/2✓ Branch 0 taken 1283 times.
✗ Branch 1 not taken.
|
1283 | return FRAMETIME; |
| 9853 | } | ||
| 9854 | static const char _data_FX_MODE_PARTICLEDANCINGSHADOWS[] PROGMEM = "PS Dancing Shadows@Speed,!,Blur,Color Cycle,,Smear,Position Color,Smooth;,!;!;1;sx=100,ix=180,c1=0,c2=0"; | ||
| 9855 | |||
| 9856 | /* | ||
| 9857 | Particle Fireworks 1D replacement | ||
| 9858 | Uses palette for particle color | ||
| 9859 | by DedeHai (Damian Schneider) | ||
| 9860 | */ | ||
| 9861 | 23 | uint16_t mode_particleFireworks1D(void) { | |
| 9862 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 9863 | uint8_t *forcecounter; | ||
| 9864 | |||
| 9865 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9866 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 4, 150, 4, true)) // init advanced particle system |
| 9867 | ✗ | if (!initParticleSystem1D(PartSys, 4, 150, 4, true)) // init advanced particle system | |
| 9868 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 9869 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); |
| 9870 | 5 | PartSys->sources[0].sourceFlags.custom1 = 1; // set rocket state to standby | |
| 9871 | } | ||
| 9872 | else | ||
| 9873 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9874 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 9875 | ✗ | return mode_static(); // something went wrong, no data! | |
| 9876 | |||
| 9877 | // Particle System settings | ||
| 9878 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9879 | 23 | forcecounter = PartSys->PSdataEnd; | |
| 9880 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 9881 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | int32_t gravity = (1 + (SEGMENT.speed >> 3)); // gravity value used for rocket speed calculation |
| 9882 |
5/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | PartSys->setGravity(SEGMENT.speed ? gravity : 0); // set gravity |
| 9883 | |||
| 9884 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (PartSys->sources[0].sourceFlags.custom1 == 1) { // rocket is on standby |
| 9885 | 5 | PartSys->sources[0].source.ttl--; | |
| 9886 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (PartSys->sources[0].source.ttl == 0) { // time is up, relaunch |
| 9887 | |||
| 9888 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 3 times.
|
5 | if (hw_random8() < SEGMENT.custom1) // randomly choose direction according to slider, fire at start of segment if true |
| 9889 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | SEGENV.aux0 = 1; |
| 9890 | else | ||
| 9891 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | SEGENV.aux0 = 0; |
| 9892 | |||
| 9893 | 5 | PartSys->sources[0].sourceFlags.custom1 = 0; //flag used for rocket state | |
| 9894 | 5 | PartSys->sources[0].source.hue = hw_random16(); // different color for each launch | |
| 9895 | 5 | PartSys->sources[0].var = 10; // emit variation | |
| 9896 | 5 | PartSys->sources[0].v = -10; // emit speed | |
| 9897 | 5 | PartSys->sources[0].minLife = 30; | |
| 9898 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
|
5 | PartSys->sources[0].maxLife = SEGMENT.check2 ? 400 : 60; |
| 9899 | 5 | PartSys->sources[0].source.x = 0; // start from bottom | |
| 9900 | 5 | uint32_t speed = sqrt((gravity * ((PartSys->maxX >> 2) + hw_random16(PartSys->maxX >> 1))) >> 4); // set speed such that rocket explods in frame | |
| 9901 | 5 | PartSys->sources[0].source.vx = min(speed, (uint32_t)127); | |
| 9902 | 5 | PartSys->sources[0].source.ttl = 4000; | |
| 9903 | 5 | PartSys->sources[0].sat = 30; // low saturation exhaust | |
| 9904 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->sources[0].size = SEGMENT.check3; // single or double pixel rendering |
| 9905 | 5 | PartSys->sources[0].sourceFlags.reversegrav = false ; // normal gravity | |
| 9906 | |||
| 9907 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 3 times.
|
5 | if (SEGENV.aux0) { // inverted rockets launch from end |
| 9908 | 2 | PartSys->sources[0].sourceFlags.reversegrav = true; | |
| 9909 | 2 | PartSys->sources[0].source.x = PartSys->maxX; // start from top | |
| 9910 | 2 | PartSys->sources[0].source.vx = -PartSys->sources[0].source.vx; // revert direction | |
| 9911 | 2 | PartSys->sources[0].v = -PartSys->sources[0].v; // invert exhaust emit speed | |
| 9912 | } | ||
| 9913 | } | ||
| 9914 | } | ||
| 9915 | else { // rocket is launched | ||
| 9916 | 18 | int32_t rocketgravity = -gravity; | |
| 9917 | 18 | int32_t currentspeed = PartSys->sources[0].source.vx; | |
| 9918 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 11 times.
|
18 | if (SEGENV.aux0) { // negative speed rocket |
| 9919 | 7 | rocketgravity = -rocketgravity; | |
| 9920 | 7 | currentspeed = -currentspeed; | |
| 9921 | } | ||
| 9922 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->applyForce(PartSys->sources[0].source, rocketgravity, forcecounter[0]); |
| 9923 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags); |
| 9924 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags); // increase rocket speed by calling the move function twice, also ages twice |
| 9925 |
4/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 11 times.
|
18 | uint32_t rocketheight = SEGENV.aux0 ? PartSys->maxX - PartSys->sources[0].source.x : PartSys->sources[0].source.x; |
| 9926 | |||
| 9927 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
18 | if (currentspeed < 0 && PartSys->sources[0].source.ttl > 50) // reached apogee |
| 9928 | ✗ | PartSys->sources[0].source.ttl = min((uint32_t)50, rocketheight >> (PS_P_RADIUS_SHIFT_1D + 3)); // alive for a few more frames | |
| 9929 | |||
| 9930 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (PartSys->sources[0].source.ttl < 2) { // explode |
| 9931 | ✗ | PartSys->sources[0].sourceFlags.custom1 = 1; // set standby state | |
| 9932 | ✗ | PartSys->sources[0].var = 5 + ((((PartSys->maxX >> 1) + rocketheight) * (200 + SEGMENT.intensity)) / (PartSys->maxX << 2)); // set explosion particle speed | |
| 9933 | ✗ | PartSys->sources[0].minLife = 600; | |
| 9934 | ✗ | PartSys->sources[0].maxLife = 1300; | |
| 9935 | ✗ | PartSys->sources[0].source.ttl = 100 + hw_random16(64 - (SEGMENT.speed >> 2)); // standby time til next launch | |
| 9936 | ✗ | PartSys->sources[0].sat = SEGMENT.custom3 < 16 ? 10 + (SEGMENT.custom3 << 4) : 255; //color saturation | |
| 9937 | ✗ | PartSys->sources[0].size = SEGMENT.check3 ? hw_random16(SEGMENT.intensity) : 0; // random particle size in explosion | |
| 9938 | ✗ | uint32_t explosionsize = 8 + (PartSys->maxXpixel >> 2) + (PartSys->sources[0].source.x >> (PS_P_RADIUS_SHIFT_1D - 1)); | |
| 9939 | ✗ | explosionsize += hw_random16((explosionsize * SEGMENT.intensity) >> 8); | |
| 9940 | ✗ | for (uint32_t e = 0; e < explosionsize; e++) { // emit explosion particles | |
| 9941 | ✗ | int idx = PartSys->sprayEmit(PartSys->sources[0]); // emit a particle | |
| 9942 | ✗ | if(SEGMENT.custom3 > 23) { | |
| 9943 | ✗ | if(SEGMENT.custom3 == 31) { // highest slider value | |
| 9944 | ✗ | PartSys->setColorByAge(SEGMENT.check1); // color by age if colorful mode is enabled | |
| 9945 | ✗ | PartSys->setColorByPosition(!SEGMENT.check1); // color by position otherwise | |
| 9946 | } | ||
| 9947 | else { // if custom3 is set to high value (but not highest), set particle color by initial speed | ||
| 9948 | ✗ | PartSys->particles[idx].hue = map(abs(PartSys->particles[idx].vx), 0, PartSys->sources[0].var, 0, 16 + hw_random16(200)); // set hue according to speed, use random amount of palette width | |
| 9949 | ✗ | PartSys->particles[idx].hue += PartSys->sources[0].source.hue; // add hue offset of the rocket (random starting color) | |
| 9950 | } | ||
| 9951 | } | ||
| 9952 | else { | ||
| 9953 | ✗ | if (SEGMENT.check1) // colorful mode | |
| 9954 | ✗ | PartSys->sources[0].source.hue = hw_random16(); //random color for each particle | |
| 9955 | } | ||
| 9956 | } | ||
| 9957 | } | ||
| 9958 | } | ||
| 9959 |
8/12✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✓ Branch 11 taken 10 times.
|
23 | if ((SEGMENT.call & 0x01) == 0 && PartSys->sources[0].sourceFlags.custom1 == false && PartSys->sources[0].source.ttl > 50) // every second frame and not in standby and not about to explode |
| 9960 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | PartSys->sprayEmit(PartSys->sources[0]); // emit exhaust particle |
| 9961 | |||
| 9962 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 15 times.
|
23 | if ((SEGMENT.call & 0x03) == 0) // every fourth frame |
| 9963 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | PartSys->applyFriction(1); // apply friction to all particles |
| 9964 | |||
| 9965 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 9966 | |||
| 9967 |
2/2✓ Branch 0 taken 3280 times.
✓ Branch 1 taken 23 times.
|
3303 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 9968 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3258 times.
|
3280 | if (PartSys->particles[i].ttl > 10) PartSys->particles[i].ttl -= 10; //ttl is linked to brightness, this allows to use higher brightness but still a short spark lifespan |
| 9969 | 3258 | else PartSys->particles[i].ttl = 0; | |
| 9970 | } | ||
| 9971 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 9972 | } | ||
| 9973 | static const char _data_FX_MODE_PS_FIREWORKS1D[] PROGMEM = "PS Fireworks 1D@Gravity,Explosion,Firing side,Blur,Color,Colorful,Trail,Smooth;,!;!;1;c2=30,o1=1"; | ||
| 9974 | |||
| 9975 | /* | ||
| 9976 | Particle based Sparkle effect | ||
| 9977 | Uses palette for particle color | ||
| 9978 | by DedeHai (Damian Schneider) | ||
| 9979 | */ | ||
| 9980 | 23 | uint16_t mode_particleSparkler(void) { | |
| 9981 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 9982 | uint32_t numSparklers; | ||
| 9983 | PSsettings1D sparklersettings; | ||
| 9984 | 23 | sparklersettings.asByte = 0; // PS settings for sparkler (set below) | |
| 9985 | |||
| 9986 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 9987 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 16, 128 ,0, true)) // init, no additional data needed |
| 9988 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 9989 | } else | ||
| 9990 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 9991 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 9992 | ✗ | return mode_static(); // something went wrong, no data! | |
| 9993 | |||
| 9994 | // Particle System settings | ||
| 9995 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 9996 | |||
| 9997 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | sparklersettings.wrap = !SEGMENT.check2; |
| 9998 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | sparklersettings.bounce = SEGMENT.check2; // note: bounce always takes priority over wrap |
| 9999 | |||
| 10000 | 23 | numSparklers = PartSys->numSources; | |
| 10001 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur/overlay |
| 10002 | //PartSys->setSmearBlur(SEGMENT.custom2); // anable smearing blur | ||
| 10003 | |||
| 10004 |
2/2✓ Branch 0 taken 368 times.
✓ Branch 1 taken 23 times.
|
391 | for (uint32_t i = 0; i < numSparklers; i++) { |
| 10005 | 368 | PartSys->sources[i].source.hue = hw_random16(); | |
| 10006 | 368 | PartSys->sources[i].var = 0; // sparks stationary | |
| 10007 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].minLife = 150 + SEGMENT.intensity; |
| 10008 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].maxLife = 250 + (SEGMENT.intensity << 1); |
| 10009 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | uint32_t speed = SEGMENT.speed >> 1; |
| 10010 |
3/6✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 368 times.
|
368 | if (SEGMENT.check1) // sparks move (slide option) |
| 10011 | ✗ | PartSys->sources[i].var = SEGMENT.intensity >> 3; | |
| 10012 | 368 | PartSys->sources[i].source.vx = speed; // update speed, do not change direction | |
| 10013 | 368 | PartSys->sources[i].source.ttl = 400; // replenish its life (setting it perpetual uses more code) | |
| 10014 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].sat = SEGMENT.custom1; // color saturation |
| 10015 |
3/6✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 368 times.
|
368 | PartSys->sources[i].size = SEGMENT.check3 ? 120 : 0; |
| 10016 |
4/6✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 304 times.
✓ Branch 5 taken 64 times.
|
368 | if (SEGMENT.speed == 255) // random position at highest speed setting |
| 10017 | 304 | PartSys->sources[i].source.x = hw_random16(PartSys->maxX); | |
| 10018 | else | ||
| 10019 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | PartSys->particleMoveUpdate(PartSys->sources[i].source, PartSys->sources[i].sourceFlags, &sparklersettings); //move sparkler |
| 10020 | } | ||
| 10021 | |||
| 10022 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | numSparklers = min(1 + (SEGMENT.custom3 >> 1), (int)numSparklers); // set used sparklers, 1 to 16 |
| 10023 | |||
| 10024 |
6/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 19 times.
|
23 | if (SEGENV.aux0 != SEGMENT.custom3) { //number of used sparklers changed, redistribute |
| 10025 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 4 times.
|
28 | for (uint32_t i = 1; i < numSparklers; i++) { |
| 10026 | 24 | PartSys->sources[i].source.x = (PartSys->sources[0].source.x + (PartSys->maxX / numSparklers) * i ) % PartSys->maxX; //distribute evenly | |
| 10027 | } | ||
| 10028 | } | ||
| 10029 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | SEGENV.aux0 = SEGMENT.custom3; |
| 10030 | |||
| 10031 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 23 times.
|
151 | for (uint32_t i = 0; i < numSparklers; i++) { |
| 10032 |
4/6✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 71 times.
✓ Branch 5 taken 57 times.
|
128 | if (hw_random() % (((271 - SEGMENT.intensity) >> 4)) == 0) |
| 10033 |
1/2✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
|
71 | PartSys->sprayEmit(PartSys->sources[i]); //emit a particle |
| 10034 | } | ||
| 10035 | |||
| 10036 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10037 | |||
| 10038 |
2/2✓ Branch 0 taken 2824 times.
✓ Branch 1 taken 23 times.
|
2847 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10039 |
6/10✓ Branch 0 taken 2824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2824 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 187 times.
✓ Branch 5 taken 2637 times.
✓ Branch 6 taken 187 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 187 times.
✗ Branch 9 not taken.
|
2824 | if (PartSys->particles[i].ttl > (64 - (SEGMENT.intensity >> 2))) PartSys->particles[i].ttl -= (64 - (SEGMENT.intensity >> 2)); //ttl is linked to brightness, this allows to use higher brightness but still a short spark lifespan |
| 10040 | 2637 | else PartSys->particles[i].ttl = 0; | |
| 10041 | } | ||
| 10042 | |||
| 10043 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10044 | } | ||
| 10045 | static const char _data_FX_MODE_PS_SPARKLER[] PROGMEM = "PS Sparkler@Move,!,Saturation,Blur,Sparklers,Slide,Bounce,Large;,!;!;1;pal=0,sx=255,c1=0,c2=0,c3=6"; | ||
| 10046 | |||
| 10047 | /* | ||
| 10048 | Particle based Hourglass, particles falling at defined intervals | ||
| 10049 | Uses palette for particle color | ||
| 10050 | by DedeHai (Damian Schneider) | ||
| 10051 | */ | ||
| 10052 | 23 | uint16_t mode_particleHourglass(void) { | |
| 10053 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10054 | 23 | constexpr int positionOffset = PS_P_RADIUS_1D / 2;; // resting position offset | |
| 10055 | bool* direction; | ||
| 10056 | uint32_t* settingTracker; | ||
| 10057 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10058 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 0, 255, 8, false)) // init |
| 10059 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10060 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setBounce(true); |
| 10061 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setWallHardness(100); |
| 10062 | } | ||
| 10063 | else | ||
| 10064 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10065 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10066 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10067 | |||
| 10068 | // Particle System settings | ||
| 10069 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10070 | 23 | settingTracker = reinterpret_cast<uint32_t *>(PartSys->PSdataEnd); //assign data pointer | |
| 10071 | 23 | direction = reinterpret_cast<bool *>(PartSys->PSdataEnd + 4); //assign data pointer | |
| 10072 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setUsedParticles(1 + ((SEGMENT.intensity * 255) >> 8)); |
| 10073 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 10074 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setGravity(map(SEGMENT.custom3, 0, 31, 1, 30)); |
| 10075 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->enableParticleCollisions(true, 32); // hardness value found by experimentation on different settings |
| 10076 | |||
| 10077 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t colormode = SEGMENT.custom1 >> 5; // 0-7 |
| 10078 | |||
| 10079 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
|
23 | if (SEGMENT.intensity != *settingTracker) { // initialize |
| 10080 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | *settingTracker = SEGMENT.intensity; |
| 10081 |
2/2✓ Branch 0 taken 1051 times.
✓ Branch 1 taken 4 times.
|
1055 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10082 | 1051 | PartSys->particleFlags[i].reversegrav = true; // resting particles dont fall | |
| 10083 | 1051 | *direction = 0; // down | |
| 10084 |
2/4✓ Branch 0 taken 1051 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1051 times.
✗ Branch 3 not taken.
|
1051 | SEGENV.aux1 = 1; // initialize below |
| 10085 | } | ||
| 10086 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | SEGENV.aux0 = PartSys->usedParticles - 1; // initial state, start with highest number particle |
| 10087 | } | ||
| 10088 | |||
| 10089 | // calculate target position depending on direction | ||
| 10090 | 2117 | auto calcTargetPos = [&](size_t i) { | |
| 10091 |
2/2✓ Branch 0 taken 2102 times.
✓ Branch 1 taken 15 times.
|
2117 | return PartSys->particleFlags[i].reversegrav ? |
| 10092 | 2102 | PartSys->maxX - i * PS_P_RADIUS_1D - positionOffset | |
| 10093 | 2117 | : (PartSys->usedParticles - i) * PS_P_RADIUS_1D - positionOffset; | |
| 10094 | 23 | }; | |
| 10095 | |||
| 10096 | |||
| 10097 |
2/2✓ Branch 0 taken 4759 times.
✓ Branch 1 taken 23 times.
|
4782 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { // check if particle reached target position after falling |
| 10098 |
3/4✓ Branch 0 taken 1066 times.
✓ Branch 1 taken 3693 times.
✓ Branch 2 taken 1066 times.
✗ Branch 3 not taken.
|
4759 | if (PartSys->particleFlags[i].fixed == false && abs(PartSys->particles[i].vx) < 5) { |
| 10099 | 1066 | int32_t targetposition = calcTargetPos(i); | |
| 10100 | 1066 | bool closeToTarget = abs(targetposition - PartSys->particles[i].x) < 3 * PS_P_RADIUS_1D; | |
| 10101 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1058 times.
|
1066 | if (closeToTarget) { // close to target and slow speed |
| 10102 | 8 | PartSys->particles[i].x = targetposition; // set exact position | |
| 10103 | 8 | PartSys->particleFlags[i].fixed = true; // pin particle | |
| 10104 | } | ||
| 10105 | } | ||
| 10106 |
2/2✓ Branch 0 taken 2048 times.
✓ Branch 1 taken 2711 times.
|
4759 | if (colormode == 7) |
| 10107 |
1/2✓ Branch 0 taken 2048 times.
✗ Branch 1 not taken.
|
2048 | PartSys->setColorByPosition(true); // color fixed by position |
| 10108 | else { | ||
| 10109 |
1/2✓ Branch 0 taken 2711 times.
✗ Branch 1 not taken.
|
2711 | PartSys->setColorByPosition(false); |
| 10110 |
2/4✓ Branch 0 taken 2711 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2711 times.
✗ Branch 3 not taken.
|
2711 | uint8_t basehue = ((SEGMENT.custom1 & 0x1F) << 3); // use 5 LSBs to select color |
| 10111 |
2/7✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2695 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
2711 | switch(colormode) { |
| 10112 | 16 | case 0: PartSys->particles[i].hue = 120; break; // fixed at 120, if flip is activated, this can make red and green (use palette 34) | |
| 10113 | ✗ | case 1: PartSys->particles[i].hue = basehue; break; // fixed selectable color | |
| 10114 | ✗ | case 2: // 2 colors inverleaved (same code as 3) | |
| 10115 | ✗ | case 3: PartSys->particles[i].hue = ((SEGMENT.custom1 & 0x1F) << 1) + (i % colormode)*74; break; // interleved colors (every 2 or 3 particles) | |
| 10116 | 2695 | case 4: PartSys->particles[i].hue = basehue + (i * 255) / PartSys->usedParticles; break; // gradient palette colors | |
| 10117 | ✗ | case 5: PartSys->particles[i].hue = basehue + (i * 1024) / PartSys->usedParticles; break; // multi gradient palette colors | |
| 10118 | ✗ | case 6: PartSys->particles[i].hue = i + (strip().now >> 3); break; // disco! moving color gradient | |
| 10119 | ✗ | default: break; | |
| 10120 | } | ||
| 10121 | } | ||
| 10122 |
7/10✓ Branch 0 taken 4759 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4759 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4759 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✓ Branch 7 taken 4732 times.
✓ Branch 8 taken 27 times.
✓ Branch 9 taken 4732 times.
|
4759 | if (SEGMENT.check1 && !PartSys->particleFlags[i].reversegrav) // flip color when fallen |
| 10123 | 27 | PartSys->particles[i].hue += 120; | |
| 10124 | } | ||
| 10125 | |||
| 10126 | // re-order particles in case collisions flipped particles (highest number index particle is on the "bottom") | ||
| 10127 |
2/2✓ Branch 0 taken 4736 times.
✓ Branch 1 taken 23 times.
|
4759 | for (uint32_t i = 0; i < PartSys->usedParticles - 1; i++) { |
| 10128 |
4/6✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4731 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
|
4736 | if (PartSys->particles[i].x < PartSys->particles[i+1].x && PartSys->particleFlags[i].fixed == false && PartSys->particleFlags[i+1].fixed == false) { |
| 10129 | ✗ | std::swap(PartSys->particles[i].x, PartSys->particles[i+1].x); | |
| 10130 | } | ||
| 10131 | } | ||
| 10132 | |||
| 10133 | |||
| 10134 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
|
23 | if (SEGENV.aux1 == 1) { // last countdown call before dropping starts, reset all particles |
| 10135 |
2/2✓ Branch 0 taken 1051 times.
✓ Branch 1 taken 4 times.
|
1055 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10136 | 1051 | PartSys->particleFlags[i].collide = true; | |
| 10137 | 1051 | PartSys->particleFlags[i].perpetual = true; | |
| 10138 | 1051 | PartSys->particles[i].ttl = 260; | |
| 10139 | 1051 | PartSys->particles[i].x = calcTargetPos(i); | |
| 10140 | 1051 | PartSys->particleFlags[i].fixed = true; | |
| 10141 | } | ||
| 10142 | } | ||
| 10143 | |||
| 10144 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 6 times.
|
23 | if (SEGENV.aux1 == 0) { // countdown passed, run |
| 10145 |
5/8✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 11 times.
|
17 | if (strip().now >= SEGENV.step) { // drop a particle, do not drop more often than every second frame or particles tangle up quite badly |
| 10146 | // set next drop time | ||
| 10147 |
5/10✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
|
6 | if (SEGMENT.check3 && *direction) // fast reset |
| 10148 | ✗ | SEGENV.step = strip().now + 100; // drop one particle every 100ms | |
| 10149 | else // normal interval | ||
| 10150 |
5/10✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
|
6 | SEGENV.step = strip().now + max(20, SEGMENT.speed * 20); // map speed slider from 0.1s to 5s |
| 10151 |
4/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
|
6 | if (SEGENV.aux0 < PartSys->usedParticles) { |
| 10152 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->particleFlags[SEGENV.aux0].reversegrav = *direction; // let this particle fall or rise |
| 10153 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->particleFlags[SEGENV.aux0].fixed = false; // unpin |
| 10154 | } | ||
| 10155 | else { // overflow | ||
| 10156 | 1 | *direction = !(*direction); // flip direction | |
| 10157 |
5/10✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | SEGENV.aux1 = SEGMENT.virtualLength() + 100; // set countdown |
| 10158 | } | ||
| 10159 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | if (*direction == 0) // down, start dropping the highest number particle |
| 10160 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0--; // next particle |
| 10161 | else | ||
| 10162 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | SEGENV.aux0++; |
| 10163 | } | ||
| 10164 | } | ||
| 10165 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | else if (SEGMENT.check2) // auto reset |
| 10166 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | SEGENV.aux1--; // countdown |
| 10167 | |||
| 10168 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10169 | |||
| 10170 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10171 | } | ||
| 10172 | static const char _data_FX_MODE_PS_HOURGLASS[] PROGMEM = "PS Hourglass@Interval,!,Color,Blur,Gravity,Colorflip,Start,Fast Reset;,!;!;1;pal=34,sx=50,ix=200,c1=140,c2=80,c3=4,o1=1,o2=1,o3=1"; | ||
| 10173 | |||
| 10174 | /* | ||
| 10175 | Particle based Spray effect (like a volcano, possible replacement for popcorn) | ||
| 10176 | Uses palette for particle color | ||
| 10177 | by DedeHai (Damian Schneider) | ||
| 10178 | */ | ||
| 10179 | 23 | uint16_t mode_particle1Dspray(void) { | |
| 10180 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10181 | |||
| 10182 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10183 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1)) |
| 10184 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10185 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); |
| 10186 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setWallHardness(150); |
| 10187 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setParticleSize(1); |
| 10188 | } | ||
| 10189 | else | ||
| 10190 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10192 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10193 | |||
| 10194 | // Particle System settings | ||
| 10195 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10196 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setBounce(SEGMENT.check2); |
| 10197 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 10198 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | int32_t gravity = -((int32_t)SEGMENT.custom3 - 16); // gravity setting, 0-15 is positive (down), 17 - 31 is negative (up) |
| 10199 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setGravity(abs(gravity)); // use reversgrav setting to invert gravity (for proper 'floor' and out of bounce handling) |
| 10200 | |||
| 10201 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].source.hue = SEGMENT.aux0; // hw_random16(); |
| 10202 | 23 | PartSys->sources[0].var = 20; | |
| 10203 | 23 | PartSys->sources[0].minLife = 200; | |
| 10204 | 23 | PartSys->sources[0].maxLife = 400; | |
| 10205 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].source.x = map(SEGMENT.custom1, 0 , 255, 0, PartSys->maxX); // spray position |
| 10206 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].v = map(SEGMENT.speed, 0 , 255, -127 + PartSys->sources[0].var, 127 - PartSys->sources[0].var); // particle emit speed |
| 10207 | 23 | PartSys->sources[0].sourceFlags.reversegrav = gravity < 0 ? true : false; | |
| 10208 | |||
| 10209 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 15 times.
|
23 | if (hw_random() % (1 + ((255 - SEGMENT.intensity) >> 3)) == 0) { |
| 10210 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | PartSys->sprayEmit(PartSys->sources[0]); // emit a particle |
| 10211 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | SEGMENT.aux0++; // increment hue |
| 10212 | } | ||
| 10213 | |||
| 10214 | //update color settings | ||
| 10215 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setColorByAge(SEGMENT.check1); // overruled by 'color by position' |
| 10216 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setColorByPosition(SEGMENT.check3); |
| 10217 |
2/2✓ Branch 0 taken 7536 times.
✓ Branch 1 taken 23 times.
|
7559 | for (uint i = 0; i < PartSys->usedParticles; i++) { |
| 10218 | 7536 | PartSys->particleFlags[i].reversegrav = PartSys->sources[0].sourceFlags.reversegrav; // update gravity direction | |
| 10219 | } | ||
| 10220 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10221 | |||
| 10222 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10223 | } | ||
| 10224 | static const char _data_FX_MODE_PS_1DSPRAY[] PROGMEM = "PS Spray 1D@Speed(+/-),!,Position,Blur,Gravity(+/-),AgeColor,Bounce,Position Color;,!;!;1;sx=200,ix=220,c1=0,c2=0"; | ||
| 10225 | |||
| 10226 | /* | ||
| 10227 | Particle based balance: particles move back and forth (1D pendent to 2D particle box) | ||
| 10228 | Uses palette for particle color | ||
| 10229 | by DedeHai (Damian Schneider) | ||
| 10230 | */ | ||
| 10231 | 23 | uint16_t mode_particleBalance(void) { | |
| 10232 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10233 | uint32_t i; | ||
| 10234 | |||
| 10235 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10236 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 128)) // init, no additional data needed, use half of max particles |
| 10237 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10238 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setParticleSize(1); |
| 10239 | } | ||
| 10240 | else | ||
| 10241 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10243 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10244 | |||
| 10245 | // Particle System settings | ||
| 10246 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10247 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // enable motion blur |
| 10248 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setBounce(!SEGMENT.check2); |
| 10249 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setWrap(SEGMENT.check2); |
| 10250 |
6/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
|
23 | uint8_t hardness = SEGMENT.custom1 > 0 ? map(SEGMENT.custom1, 0, 255, 50, 250) : 200; // set hardness, make the walls hard if collisions are disabled |
| 10251 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->enableParticleCollisions(SEGMENT.custom1, hardness); // enable collisions if custom1 > 0 |
| 10252 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setWallHardness(200); |
| 10253 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setUsedParticles(map(SEGMENT.intensity, 0, 255, 10, 255)); |
| 10254 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (PartSys->usedParticles > SEGENV.aux1) { // more particles, reinitialize |
| 10255 |
2/2✓ Branch 0 taken 455 times.
✓ Branch 1 taken 5 times.
|
460 | for (i = 0; i < PartSys->usedParticles; i++) { |
| 10256 | 455 | PartSys->particles[i].x = i * PS_P_RADIUS_1D; | |
| 10257 | 455 | PartSys->particles[i].ttl = 300; | |
| 10258 | 455 | PartSys->particleFlags[i].perpetual = true; | |
| 10259 | 455 | PartSys->particleFlags[i].collide = true; | |
| 10260 | } | ||
| 10261 | } | ||
| 10262 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | SEGENV.aux1 = PartSys->usedParticles; |
| 10263 | |||
| 10264 | // re-order particles in case collisions flipped particles | ||
| 10265 |
2/2✓ Branch 0 taken 1981 times.
✓ Branch 1 taken 23 times.
|
2004 | for (i = 0; i < PartSys->usedParticles - 1; i++) { |
| 10266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1981 times.
|
1981 | if (PartSys->particles[i].x > PartSys->particles[i+1].x) { |
| 10267 | ✗ | if (SEGMENT.check2) { // check for wrap around | |
| 10268 | ✗ | if (PartSys->particles[i].x - PartSys->particles[i+1].x > 3 * PS_P_RADIUS_1D) | |
| 10269 | ✗ | continue; | |
| 10270 | } | ||
| 10271 | ✗ | std::swap(PartSys->particles[i].x, PartSys->particles[i+1].x); | |
| 10272 | } | ||
| 10273 | } | ||
| 10274 | |||
| 10275 |
6/10✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✓ Branch 9 taken 9 times.
|
23 | if (SEGMENT.call % (((255 - SEGMENT.speed) >> 6) + 1) == 0) { // how often the force is applied depends on speed setting |
| 10276 | int32_t xgravity; | ||
| 10277 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | int32_t increment = (SEGMENT.speed >> 6) + 1; |
| 10278 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | SEGENV.aux0 += increment; |
| 10279 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
|
14 | if (SEGMENT.check3) // random, use perlin noise |
| 10280 | ✗ | xgravity = ((int16_t)perlin8(SEGENV.aux0) - 128); | |
| 10281 | else // sinusoidal | ||
| 10282 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | xgravity = (int16_t)cos8(SEGENV.aux0) - 128;//((int32_t)(SEGMENT.custom3 << 2) * cos8(SEGENV.aux0) |
| 10283 | // scale the force | ||
| 10284 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | xgravity = (xgravity * ((SEGMENT.custom3+1) << 2)) / 128; // xgravity: -127 to +127 |
| 10285 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | PartSys->applyForce(xgravity); |
| 10286 | } | ||
| 10287 | |||
| 10288 | 23 | uint32_t randomindex = hw_random16(PartSys->usedParticles); | |
| 10289 | 23 | PartSys->particles[randomindex].vx = ((int32_t)PartSys->particles[randomindex].vx * 200) / 255; // apply friction to random particle to reduce clumping (without collisions) | |
| 10290 | |||
| 10291 | //if (SEGMENT.check2 && (SEGMENT.call & 0x07) == 0) // no walls, apply friction to smooth things out | ||
| 10292 |
10/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 22 times.
|
23 | if ((SEGMENT.call & 0x0F) == 0 && SEGMENT.custom3 > 4) // apply friction every 16th frame to smooth things out (except for low tilt) |
| 10293 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | PartSys->applyFriction(1); // apply friction to all particles |
| 10294 | |||
| 10295 | //update colors | ||
| 10296 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setColorByPosition(SEGMENT.check1); |
| 10297 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (!SEGMENT.check1) { |
| 10298 | ✗ | for (i = 0; i < PartSys->usedParticles; i++) { | |
| 10299 | ✗ | PartSys->particles[i].hue = (1024 * i) / PartSys->usedParticles; // color by particle index | |
| 10300 | } | ||
| 10301 | } | ||
| 10302 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10303 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10304 | } | ||
| 10305 | static const char _data_FX_MODE_PS_BALANCE[] PROGMEM = "PS 1D Balance@!,!,Hardness,Blur,Tilt,Position Color,Wrap,Random;,!;!;1;pal=18,c2=0,c3=4,o1=1"; | ||
| 10306 | |||
| 10307 | /* | ||
| 10308 | Particle based Chase effect | ||
| 10309 | Uses palette for particle color | ||
| 10310 | by DedeHai (Damian Schneider) | ||
| 10311 | */ | ||
| 10312 | 23 | uint16_t mode_particleChase(void) { | |
| 10313 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10314 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10315 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 255, 2, true)) // init |
| 10316 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10317 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = 0xFFFF; // invalidate |
| 10318 | 5 | *PartSys->PSdataEnd = 1; // huedir | |
| 10319 | 5 | *(PartSys->PSdataEnd + 1) = 1; // sizedir | |
| 10320 | } | ||
| 10321 | else | ||
| 10322 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10323 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10324 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10325 | // Particle System settings | ||
| 10326 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10327 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setColorByPosition(SEGMENT.check3); |
| 10328 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(7 + ((SEGMENT.custom3) << 3)); // anable motion blur |
| 10329 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | uint32_t numParticles = 1 + map(SEGMENT.intensity, 0, 255, 2, 255 / (1 + (SEGMENT.custom1 >> 6))); // depends on intensity and particle size (custom1), minimum 1 |
| 10330 | 23 | numParticles = min(numParticles, PartSys->usedParticles); // limit to available particles | |
| 10331 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | int32_t huestep = 1 + ((((uint32_t)SEGMENT.custom2 << 19) / numParticles) >> 16); // hue increment |
| 10332 |
14/28✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 23 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 23 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 23 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 23 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 23 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 23 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 23 times.
✗ Branch 27 not taken.
|
23 | uint32_t settingssum = SEGMENT.speed + SEGMENT.intensity + SEGMENT.custom1 + SEGMENT.custom2 + SEGMENT.check1 + SEGMENT.check2 + SEGMENT.check3; |
| 10333 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGENV.aux0 != settingssum) { // settings changed changed, update |
| 10334 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
|
5 | if (SEGMENT.check1) |
| 10335 | ✗ | SEGENV.step = PartSys->advPartProps[0].size / 2 + (PartSys->maxX / numParticles); | |
| 10336 | else | ||
| 10337 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.step = (PartSys->maxX + (PS_P_RADIUS_1D << 5)) / numParticles; // spacing between particles |
| 10338 |
2/2✓ Branch 0 taken 1248 times.
✓ Branch 1 taken 5 times.
|
1253 | for (int32_t i = 0; i < (int32_t)PartSys->usedParticles; i++) { |
| 10339 | 1248 | PartSys->advPartProps[i].sat = 255; | |
| 10340 |
2/4✓ Branch 0 taken 1248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1248 times.
✗ Branch 3 not taken.
|
1248 | PartSys->particles[i].x = (i - 1) * SEGENV.step; // distribute evenly (starts out of frame for i=0) |
| 10341 |
2/4✓ Branch 0 taken 1248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1248 times.
✗ Branch 3 not taken.
|
1248 | PartSys->particles[i].vx = SEGMENT.speed >> 2; |
| 10342 |
2/4✓ Branch 0 taken 1248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1248 times.
✗ Branch 3 not taken.
|
1248 | PartSys->advPartProps[i].size = SEGMENT.custom1; |
| 10343 |
4/6✓ Branch 0 taken 1248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1248 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 876 times.
✓ Branch 5 taken 372 times.
|
1248 | if (SEGMENT.custom2 < 255) |
| 10344 | 876 | PartSys->particles[i].hue = i * huestep; // gradient distribution | |
| 10345 | else | ||
| 10346 | 372 | PartSys->particles[i].hue = hw_random16(); | |
| 10347 | } | ||
| 10348 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = settingssum; |
| 10349 | } | ||
| 10350 | |||
| 10351 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if(SEGMENT.check1) { |
| 10352 | ✗ | huestep = 1 + (max((int)huestep, 3) * ((int(sin16_t(strip().now * 3) + 32767))) >> 15); // changes gradient spread (scale hue step) | |
| 10353 | } | ||
| 10354 | |||
| 10355 | // wrap around (cannot use particle system wrap if distributing colors manually, it also wraps rendering which does not look good) | ||
| 10356 |
2/2✓ Branch 0 taken 5496 times.
✓ Branch 1 taken 23 times.
|
5519 | for (int32_t i = (int32_t)PartSys->usedParticles - 1; i >= 0; i--) { // check from the back, last particle wraps first, multiple particles can overrun per frame |
| 10357 |
2/2✓ Branch 0 taken 1089 times.
✓ Branch 1 taken 4407 times.
|
5496 | if (PartSys->particles[i].x > PartSys->maxX + PS_P_RADIUS_1D + PartSys->advPartProps[i].size) { // wrap it around |
| 10358 | 1089 | uint32_t nextindex = (i + 1) % PartSys->usedParticles; | |
| 10359 |
2/4✓ Branch 0 taken 1089 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1089 times.
✗ Branch 3 not taken.
|
1089 | PartSys->particles[i].x = PartSys->particles[nextindex].x - (int)SEGENV.step; |
| 10360 |
3/6✓ Branch 0 taken 1089 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1089 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1089 times.
|
1089 | if(SEGMENT.check1) // playful mode, vary size |
| 10361 | ✗ | PartSys->advPartProps[i].size = max(1 + (SEGMENT.custom1 >> 1), ((int(sin16_t(strip().now << 1) + 32767)) >> 8)); // cycle size | |
| 10362 |
4/6✓ Branch 0 taken 1089 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1089 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 779 times.
✓ Branch 5 taken 310 times.
|
1089 | if (SEGMENT.custom2 < 255) |
| 10363 | 779 | PartSys->particles[i].hue = PartSys->particles[nextindex].hue - huestep; | |
| 10364 | else | ||
| 10365 | 310 | PartSys->particles[i].hue = hw_random16(); | |
| 10366 | } | ||
| 10367 | 5496 | PartSys->particles[i].ttl = 300; // reset ttl, cannot use perpetual because memmanager can change pointer at any time | |
| 10368 | } | ||
| 10369 | |||
| 10370 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check1) { // playful mode, changes hue, size, speed, density dynamically |
| 10371 | ✗ | int8_t* huedir = reinterpret_cast<int8_t *>(PartSys->PSdataEnd); //assign data pointer | |
| 10372 | ✗ | int8_t* stepdir = reinterpret_cast<int8_t *>(PartSys->PSdataEnd + 1); | |
| 10373 | ✗ | if(*stepdir == 0) *stepdir = 1; // initialize directions | |
| 10374 | ✗ | if(*huedir == 0) *huedir = 1; | |
| 10375 | ✗ | if (SEGENV.step >= (PartSys->advPartProps[0].size + PS_P_RADIUS_1D * 4) + PartSys->maxX / numParticles) | |
| 10376 | ✗ | *stepdir = -1; // increase density (decrease space between particles) | |
| 10377 | ✗ | else if (SEGENV.step <= (PartSys->advPartProps[0].size >> 1) + ((PartSys->maxX / numParticles))) | |
| 10378 | ✗ | *stepdir = 1; // decrease density | |
| 10379 | ✗ | if (SEGENV.aux1 > 512) | |
| 10380 | ✗ | *huedir = -1; | |
| 10381 | ✗ | else if (SEGENV.aux1 < 50) | |
| 10382 | ✗ | *huedir = 1; | |
| 10383 | ✗ | if (SEGMENT.call % (1024 / (1 + (SEGMENT.speed >> 2))) == 0) | |
| 10384 | ✗ | SEGENV.aux1 += *huedir; | |
| 10385 | ✗ | int8_t globalhuestep = 0; // global hue increment | |
| 10386 | ✗ | if (SEGMENT.call % (1 + (int(sin16_t(strip().now) + 32767) >> 12)) == 0) | |
| 10387 | ✗ | globalhuestep = 2; // global hue change to add some color variation | |
| 10388 | ✗ | if ((SEGMENT.call & 0x1F) == 0) | |
| 10389 | ✗ | SEGENV.step += *stepdir; // change density | |
| 10390 | ✗ | for(uint32_t i = 0; i < PartSys->usedParticles; i++) { | |
| 10391 | ✗ | PartSys->particles[i].hue -= globalhuestep; // shift global hue (both directions) | |
| 10392 | ✗ | PartSys->particles[i].vx = 1 + (SEGMENT.speed >> 2) + ((int32_t(sin16_t(strip().now >> 1) + 32767) * (SEGMENT.speed >> 2)) >> 16); | |
| 10393 | } | ||
| 10394 | } | ||
| 10395 | |||
| 10396 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setParticleSize(SEGMENT.custom1); // if custom1 == 0 this sets rendering size to one pixel |
| 10397 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10398 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10399 | } | ||
| 10400 | static const char _data_FX_MODE_PS_CHASE[] PROGMEM = "PS Chase@!,Density,Size,Hue,Blur,Playful,,Position Color;,!;!;1;pal=11,sx=50,c2=5,c3=0"; | ||
| 10401 | |||
| 10402 | /* | ||
| 10403 | Particle Fireworks Starburst replacement (smoother rendering, more settings) | ||
| 10404 | Uses palette for particle color | ||
| 10405 | by DedeHai (Damian Schneider) | ||
| 10406 | */ | ||
| 10407 | 23 | uint16_t mode_particleStarburst(void) { | |
| 10408 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10409 | |||
| 10410 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10411 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 200, 0, true)) // init |
| 10412 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10413 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); |
| 10414 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->enableParticleCollisions(true, 200); |
| 10415 | 5 | PartSys->sources[0].source.ttl = 1; // set initial stanby time | |
| 10416 | 5 | PartSys->sources[0].sat = 0; // emitted particles start out white | |
| 10417 | } | ||
| 10418 | else | ||
| 10419 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10421 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10422 | |||
| 10423 | // Particle System settings | ||
| 10424 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10425 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 10426 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setGravity(SEGMENT.check1 * 8); // enable gravity |
| 10427 | |||
| 10428 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (PartSys->sources[0].source.ttl-- == 0) { // stanby time elapsed TODO: make it a timer? |
| 10429 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | uint32_t explosionsize = 4 + hw_random16(SEGMENT.intensity >> 2); |
| 10430 | 5 | PartSys->sources[0].source.hue = hw_random16(); | |
| 10431 | 5 | PartSys->sources[0].var = 10 + (explosionsize << 1); | |
| 10432 | 5 | PartSys->sources[0].minLife = 250; | |
| 10433 | 5 | PartSys->sources[0].maxLife = 300; | |
| 10434 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->sources[0].source.x = hw_random(PartSys->maxX); //random explosion position |
| 10435 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->sources[0].source.ttl = 10 + hw_random16(255 - SEGMENT.speed); |
| 10436 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->sources[0].size = SEGMENT.custom1; // Fragment size |
| 10437 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | PartSys->setParticleSize(SEGMENT.custom1); // enable advanced size rendering |
| 10438 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | PartSys->sources[0].sourceFlags.collide = SEGMENT.check3; |
| 10439 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 5 times.
|
105 | for (uint32_t e = 0; e < explosionsize; e++) { // emit particles |
| 10440 |
3/6✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100 times.
|
100 | if (SEGMENT.check2) |
| 10441 | ✗ | PartSys->sources[0].source.hue = hw_random16(); //random color for each particle | |
| 10442 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | PartSys->sprayEmit(PartSys->sources[0]); //emit a particle |
| 10443 | } | ||
| 10444 | } | ||
| 10445 | //shrink all particles | ||
| 10446 |
2/2✓ Branch 0 taken 4336 times.
✓ Branch 1 taken 23 times.
|
4359 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10447 |
2/2✓ Branch 0 taken 328 times.
✓ Branch 1 taken 4008 times.
|
4336 | if (PartSys->advPartProps[i].size) |
| 10448 | 328 | PartSys->advPartProps[i].size--; | |
| 10449 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 3996 times.
|
4336 | if (PartSys->advPartProps[i].sat < 251) |
| 10450 |
2/4✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
|
340 | PartSys->advPartProps[i].sat += 1 + (SEGMENT.custom3 >> 2); //note: it should be >> 3, the >> 2 creates overflows resulting in blinking if custom3 > 27, which is a bonus feature |
| 10451 | } | ||
| 10452 | |||
| 10453 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call % 5 == 0) { |
| 10454 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->applyFriction(1); //slow down particles |
| 10455 | } | ||
| 10456 | |||
| 10457 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10458 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10459 | } | ||
| 10460 | static const char _data_FX_MODE_PS_STARBURST[] PROGMEM = "PS Starburst@Chance,Fragments,Size,Blur,Cooling,Gravity,Colorful,Push;,!;!;1;pal=52,sx=150,ix=150,c1=120,c2=0,c3=21"; | ||
| 10461 | |||
| 10462 | /* | ||
| 10463 | Particle based 1D GEQ effect, each frequency bin gets an emitter, distributed over the strip | ||
| 10464 | Uses palette for particle color | ||
| 10465 | by DedeHai (Damian Schneider) | ||
| 10466 | */ | ||
| 10467 | 23 | uint16_t mode_particle1DGEQ(void) { | |
| 10468 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10469 | uint32_t numSources; | ||
| 10470 | uint32_t i; | ||
| 10471 | |||
| 10472 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10473 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 16, 255, 0, true)) // init, no additional data needed |
| 10474 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10475 | } | ||
| 10476 | else | ||
| 10477 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10479 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10480 | |||
| 10481 | // Particle System settings | ||
| 10482 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10483 | 23 | numSources = PartSys->numSources; | |
| 10484 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur |
| 10485 | |||
| 10486 | 23 | uint32_t spacing = PartSys->maxX / numSources; | |
| 10487 |
2/2✓ Branch 0 taken 368 times.
✓ Branch 1 taken 23 times.
|
391 | for (i = 0; i < numSources; i++) { |
| 10488 | 368 | PartSys->sources[i].source.hue = i * 16; // hw_random16(); //TODO: make adjustable, maybe even colorcycle? | |
| 10489 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].var = SEGMENT.speed >> 2; |
| 10490 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].minLife = 180 + (SEGMENT.intensity >> 1); |
| 10491 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].maxLife = 240 + SEGMENT.intensity; |
| 10492 | 368 | PartSys->sources[i].sat = 255; | |
| 10493 |
2/4✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✗ Branch 3 not taken.
|
368 | PartSys->sources[i].size = SEGMENT.custom1; |
| 10494 | 368 | PartSys->sources[i].source.x = (spacing >> 1) + spacing * i; //distribute evenly | |
| 10495 | } | ||
| 10496 | |||
| 10497 |
2/2✓ Branch 0 taken 5496 times.
✓ Branch 1 taken 23 times.
|
5519 | for (i = 0; i < PartSys->usedParticles; i++) { |
| 10498 |
2/2✓ Branch 0 taken 319 times.
✓ Branch 1 taken 5177 times.
|
5496 | if (PartSys->particles[i].ttl > 20) PartSys->particles[i].ttl -= 20; //ttl is linked to brightness, this allows to use higher brightness but still a short lifespan |
| 10499 | 5177 | else PartSys->particles[i].ttl = 0; | |
| 10500 | } | ||
| 10501 | |||
| 10502 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | um_data_t *um_data = getAudioData(); |
| 10503 | 23 | uint8_t *fftResult = (uint8_t *)um_data->u_data[2]; // 16 bins with FFT data, log mapped already, each band contains frequency amplitude 0-255 | |
| 10504 | |||
| 10505 | //map the bands into 16 positions on x axis, emit some particles according to frequency loudness | ||
| 10506 | 23 | i = 0; | |
| 10507 | 23 | uint32_t bin = hw_random16(numSources); //current bin , start with random one to distribute available particles fairly | |
| 10508 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t threshold = 300 - SEGMENT.intensity; |
| 10509 | |||
| 10510 |
2/2✓ Branch 0 taken 368 times.
✓ Branch 1 taken 23 times.
|
391 | for (i = 0; i < numSources; i++) { |
| 10511 | 368 | bin++; | |
| 10512 | 368 | bin = bin % numSources; | |
| 10513 | 368 | uint32_t emitparticle = 0; | |
| 10514 | // uint8_t emitspeed = ((uint32_t)fftResult[bin] * (uint32_t)SEGMENT.speed) >> 10; // emit speed according to loudness of band (127 max!) | ||
| 10515 |
2/2✓ Branch 0 taken 156 times.
✓ Branch 1 taken 212 times.
|
368 | if (fftResult[bin] > threshold) { |
| 10516 | 156 | emitparticle = 1; | |
| 10517 | } | ||
| 10518 |
2/2✓ Branch 0 taken 194 times.
✓ Branch 1 taken 18 times.
|
212 | else if (fftResult[bin] > 0) { // band has low volue |
| 10519 | 194 | uint32_t restvolume = ((threshold - fftResult[bin]) >> 2) + 2; | |
| 10520 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 175 times.
|
194 | if (hw_random() % restvolume == 0) { |
| 10521 | 19 | emitparticle = 1; | |
| 10522 | } | ||
| 10523 | } | ||
| 10524 | |||
| 10525 |
2/2✓ Branch 0 taken 175 times.
✓ Branch 1 taken 193 times.
|
368 | if (emitparticle) |
| 10526 |
1/2✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
|
175 | PartSys->sprayEmit(PartSys->sources[bin]); |
| 10527 | } | ||
| 10528 | //TODO: add color control? | ||
| 10529 | |||
| 10530 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10531 | |||
| 10532 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10533 | } | ||
| 10534 | static const char _data_FX_MODE_PS_1D_GEQ[] PROGMEM = "PS GEQ 1D@Speed,!,Size,Blur,,,,;,!;!;1f;pal=0,sx=50,ix=200,c1=0,c2=0,c3=0,o1=1,o2=1"; | ||
| 10535 | |||
| 10536 | /* | ||
| 10537 | Particle based Fire effect | ||
| 10538 | Uses palette for particle color | ||
| 10539 | by DedeHai (Damian Schneider) | ||
| 10540 | */ | ||
| 10541 | 23 | uint16_t mode_particleFire1D(void) { | |
| 10542 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10543 | |||
| 10544 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10545 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 5)) // init |
| 10546 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10547 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); |
| 10548 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setParticleSize(1); |
| 10549 | } | ||
| 10550 | else | ||
| 10551 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10553 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10554 | |||
| 10555 | // Particle System settings | ||
| 10556 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10557 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(128 + (SEGMENT.custom2 >> 1)); // enable motion blur |
| 10558 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setColorByAge(true); |
| 10559 | 23 | uint32_t emitparticles = 1; | |
| 10560 | 23 | uint32_t j = hw_random16(); | |
| 10561 |
2/2✓ Branch 0 taken 69 times.
✓ Branch 1 taken 23 times.
|
92 | for (uint i = 0; i < 3; i++) { // 3 base flames |
| 10562 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 15 times.
|
69 | if (PartSys->sources[i].source.ttl > 50) |
| 10563 | 54 | PartSys->sources[i].source.ttl -= 10; // TODO: in 2D making the source fade out slow results in much smoother flames, need to check if it can be done the same | |
| 10564 | else | ||
| 10565 | 15 | PartSys->sources[i].source.ttl = 100 + hw_random16(200); | |
| 10566 | } | ||
| 10567 |
2/2✓ Branch 0 taken 184 times.
✓ Branch 1 taken 23 times.
|
207 | for (uint i = 0; i < PartSys->numSources; i++) { |
| 10568 | 184 | j = (j + 1) % PartSys->numSources; | |
| 10569 | 184 | PartSys->sources[j].source.x = 0; | |
| 10570 |
2/4✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
184 | PartSys->sources[j].var = 2 + (SEGMENT.speed >> 4); |
| 10571 | // base flames | ||
| 10572 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 69 times.
|
184 | if (j > 2) { |
| 10573 |
2/4✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
|
115 | PartSys->sources[j].minLife = 150 + SEGMENT.intensity + (j << 2); // TODO: in 2D, min life is maxlife/2 and that looks very nice |
| 10574 |
2/4✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
|
115 | PartSys->sources[j].maxLife = 200 + SEGMENT.intensity + (j << 3); |
| 10575 |
2/4✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
|
115 | PartSys->sources[j].v = (SEGMENT.speed >> (2 + (j << 1))); |
| 10576 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 92 times.
|
115 | if (emitparticles) { |
| 10577 | 23 | emitparticles--; | |
| 10578 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->sprayEmit(PartSys->sources[j]); // emit a particle |
| 10579 | } | ||
| 10580 | } | ||
| 10581 | else { | ||
| 10582 |
2/4✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
|
69 | PartSys->sources[j].minLife = PartSys->sources[j].source.ttl + SEGMENT.intensity; |
| 10583 | 69 | PartSys->sources[j].maxLife = PartSys->sources[j].minLife + 50; | |
| 10584 |
2/4✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
|
69 | PartSys->sources[j].v = SEGMENT.speed >> 2; |
| 10585 |
4/6✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 39 times.
|
69 | if (SEGENV.call & 0x01) // every second frame |
| 10586 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | PartSys->sprayEmit(PartSys->sources[j]); // emit a particle |
| 10587 | } | ||
| 10588 | } | ||
| 10589 | |||
| 10590 |
2/2✓ Branch 0 taken 7536 times.
✓ Branch 1 taken 23 times.
|
7559 | for (uint i = 0; i < PartSys->usedParticles; i++) { |
| 10591 | 7536 | PartSys->particles[i].x += PartSys->particles[i].ttl >> 7; // 'hot' particles are faster, apply some extra velocity | |
| 10592 |
4/6✓ Branch 0 taken 7536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7536 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 139 times.
✓ Branch 5 taken 7397 times.
|
7536 | if (PartSys->particles[i].ttl > 3 + ((255 - SEGMENT.custom1) >> 1)) |
| 10593 |
2/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
✗ Branch 3 not taken.
|
139 | PartSys->particles[i].ttl -= map(SEGMENT.custom1, 0, 255, 1, 3); // age faster |
| 10594 | } | ||
| 10595 | |||
| 10596 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10597 | |||
| 10598 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10599 | } | ||
| 10600 | static const char _data_FX_MODE_PS_FIRE1D[] PROGMEM = "PS Fire 1D@!,!,Cooling,Blur;,!;!;1;pal=35,sx=100,ix=50,c1=80,c2=100,c3=28,o1=1,o2=1"; | ||
| 10601 | |||
| 10602 | /* | ||
| 10603 | Particle based AR effect, swoop particles along the strip with selected frequency loudness | ||
| 10604 | by DedeHai (Damian Schneider) | ||
| 10605 | */ | ||
| 10606 | 23 | uint16_t mode_particle1DsonicStream(void) { | |
| 10607 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10608 | |||
| 10609 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10610 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 255, 0, true)) // init, no additional data needed |
| 10611 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10612 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); |
| 10613 | 5 | PartSys->sources[0].source.x = 0; // at start | |
| 10614 | //PartSys->sources[1].source.x = PartSys->maxX; // at end | ||
| 10615 | 5 | PartSys->sources[0].var = 0;//SEGMENT.custom1 >> 3; | |
| 10616 | } | ||
| 10617 | else | ||
| 10618 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10620 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10621 | |||
| 10622 | // Particle System settings | ||
| 10623 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10624 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(20 + (SEGMENT.custom2 >> 1)); // anable motion blur |
| 10625 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setSmearBlur(200); // smooth out the edges |
| 10626 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].v = 5 + (SEGMENT.speed >> 2); |
| 10627 | |||
| 10628 | // FFT processing | ||
| 10629 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | um_data_t *um_data = getAudioData(); |
| 10630 | 23 | uint8_t *fftResult = (uint8_t *)um_data->u_data[2]; // 16 bins with FFT data, log mapped already, each band contains frequency amplitude 0-255 | |
| 10631 | uint32_t loudness; | ||
| 10632 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t baseBin = SEGMENT.custom3 >> 1; // 0 - 15 map(SEGMENT.custom3, 0, 31, 0, 14); |
| 10633 | |||
| 10634 | 23 | loudness = fftResult[baseBin];// + fftResult[baseBin + 1]; | |
| 10635 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
|
23 | if (baseBin > 12) |
| 10636 | 4 | loudness = loudness << 2; // double loudness for high frequencies (better detecion) | |
| 10637 | |||
| 10638 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t threshold = 140 - (SEGMENT.intensity >> 1); |
| 10639 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | if (SEGMENT.check2) { // enable low pass filter for dynamic threshold |
| 10640 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | SEGMENT.step = (SEGMENT.step * 31500 + loudness * (32768 - 31500)) >> 15; // low pass filter for simple beat detection: add average to base threshold |
| 10641 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | threshold = 20 + (threshold >> 1) + SEGMENT.step; // add average to threshold |
| 10642 | } | ||
| 10643 | |||
| 10644 | // color | ||
| 10645 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t hueincrement = (SEGMENT.custom1 >> 3); // 0-31 |
| 10646 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 4 times.
|
23 | PartSys->sources[0].sat = SEGMENT.custom1 > 0 ? 255 : 0; // color slider at zero: set to white |
| 10647 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setColorByPosition(SEGMENT.custom1 == 255); |
| 10648 | |||
| 10649 | // particle manipulation | ||
| 10650 |
2/2✓ Branch 0 taken 5496 times.
✓ Branch 1 taken 23 times.
|
5519 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10651 |
1/2✓ Branch 0 taken 5496 times.
✗ Branch 1 not taken.
|
5496 | if (PartSys->sources[0].sourceFlags.perpetual == false) { // age faster if not perpetual |
| 10652 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5476 times.
|
5496 | if (PartSys->particles[i].ttl > 2) { |
| 10653 | 20 | PartSys->particles[i].ttl -= 2; //ttl is linked to brightness, this allows to use higher brightness but still a short lifespan | |
| 10654 | } | ||
| 10655 | 5476 | else PartSys->particles[i].ttl = 0; | |
| 10656 | } | ||
| 10657 |
3/6✓ Branch 0 taken 5496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5496 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5496 times.
|
5496 | if (SEGMENT.check1) { // modulate colors by mid frequencies |
| 10658 | ✗ | int mids = sqrt32_bw((int)fftResult[5] + (int)fftResult[6] + (int)fftResult[7] + (int)fftResult[8] + (int)fftResult[9] + (int)fftResult[10]); // average the mids, bin 5 is ~500Hz, bin 10 is ~2kHz (see audio_reactive.h) | |
| 10659 | ✗ | PartSys->particles[i].hue += (mids * perlin8(PartSys->particles[i].x << 2, SEGMENT.step << 2)) >> 9; // color by perlin noise from mid frequencies | |
| 10660 | } | ||
| 10661 | } | ||
| 10662 | |||
| 10663 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 5 times.
|
23 | if (loudness > threshold) { |
| 10664 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | SEGMENT.aux0 += hueincrement; // change color |
| 10665 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys->sources[0].minLife = 100 + (((unsigned)SEGMENT.intensity * loudness * loudness) >> 13); |
| 10666 | 18 | PartSys->sources[0].maxLife = PartSys->sources[0].minLife; | |
| 10667 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys->sources[0].source.hue = SEGMENT.aux0; |
| 10668 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys->sources[0].size = SEGMENT.speed; |
| 10669 |
10/14✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 8 times.
✓ Branch 12 taken 10 times.
✓ Branch 13 taken 8 times.
|
18 | if (PartSys->particles[SEGMENT.aux1].x > 3 * PS_P_RADIUS_1D || PartSys->particles[SEGMENT.aux1].ttl == 0) { // only emit if last particle is far enough away or dead |
| 10670 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | int partindex = PartSys->sprayEmit(PartSys->sources[0]); // emit a particle |
| 10671 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | if (partindex >= 0) SEGMENT.aux1 = partindex; // track last emitted particle |
| 10672 | } | ||
| 10673 | } | ||
| 10674 | 5 | else loudness = 0; // required for push mode | |
| 10675 | |||
| 10676 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render (needs to be done before manipulation for initial particle spacing to be right) |
| 10677 | |||
| 10678 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check3) { // push mode |
| 10679 | ✗ | PartSys->sources[0].sourceFlags.perpetual = true; // emitted particles dont age | |
| 10680 | ✗ | PartSys->applyFriction(1); //slow down particles | |
| 10681 | ✗ | int32_t movestep = (((int)SEGMENT.speed + 2) * loudness) >> 10; | |
| 10682 | ✗ | if (movestep) { | |
| 10683 | ✗ | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { | |
| 10684 | ✗ | if (PartSys->particles[i].ttl) { | |
| 10685 | ✗ | PartSys->particles[i].x += movestep; // push particles | |
| 10686 | ✗ | PartSys->particles[i].vx = 10 + (SEGMENT.speed >> 4) ; // give particles some speed for smooth movement (friction will slow them down) | |
| 10687 | } | ||
| 10688 | } | ||
| 10689 | } | ||
| 10690 | } | ||
| 10691 | else { | ||
| 10692 | 23 | PartSys->sources[0].sourceFlags.perpetual = false; // emitted particles age | |
| 10693 | // move all particles (again) to allow faster speeds | ||
| 10694 |
2/2✓ Branch 0 taken 5496 times.
✓ Branch 1 taken 23 times.
|
5519 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10695 |
2/2✓ Branch 0 taken 1245 times.
✓ Branch 1 taken 4251 times.
|
5496 | if (PartSys->particles[i].vx == 0) |
| 10696 | 1245 | PartSys->particles[i].vx = PartSys->sources[0].v; // move static particles (after disabling push mode) | |
| 10697 |
1/2✓ Branch 0 taken 5496 times.
✗ Branch 1 not taken.
|
5496 | PartSys->particleMoveUpdate(PartSys->particles[i], PartSys->particleFlags[i], nullptr, &PartSys->advPartProps[i]); |
| 10698 | } | ||
| 10699 | } | ||
| 10700 | |||
| 10701 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10702 | } | ||
| 10703 | static const char _data_FX_MODE_PS_SONICSTREAM[] PROGMEM = "PS Sonic Stream@!,!,Color,Blur,Bin,Mod,Filter,Push;,!;!;1f;c3=0,o2=1"; | ||
| 10704 | |||
| 10705 | |||
| 10706 | /* | ||
| 10707 | Particle based AR effect, creates exploding particles on beats | ||
| 10708 | by DedeHai (Damian Schneider) | ||
| 10709 | */ | ||
| 10710 | 23 | uint16_t mode_particle1DsonicBoom(void) { | |
| 10711 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10712 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10713 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 255, 0, true)) // init, no additional data needed |
| 10714 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10715 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | PartSys->setKillOutOfBounds(true); |
| 10716 | } | ||
| 10717 | else | ||
| 10718 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10719 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10720 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10721 | |||
| 10722 | // Particle System settings | ||
| 10723 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10724 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(180 * SEGMENT.check3); |
| 10725 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setSmearBlur(64 * SEGMENT.check3); |
| 10726 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | PartSys->sources[0].var = map(SEGMENT.speed, 0, 255, 10, 127); |
| 10727 | |||
| 10728 | // FFT processing | ||
| 10729 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | um_data_t *um_data = getAudioData(); |
| 10730 | 23 | uint8_t *fftResult = (uint8_t *)um_data->u_data[2]; // 16 bins with FFT data, log mapped already, each band contains frequency amplitude 0-255 | |
| 10731 | uint32_t loudness; | ||
| 10732 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t baseBin = SEGMENT.custom3 >> 1; // 0 - 15 map(SEGMENT.custom3, 0, 31, 0, 14); |
| 10733 | 23 | loudness = fftResult[baseBin];// + fftResult[baseBin + 1]; | |
| 10734 | |||
| 10735 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
|
23 | if (baseBin > 12) |
| 10736 | 4 | loudness = loudness << 2; // double loudness for high frequencies (better detecion) | |
| 10737 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | uint32_t threshold = 150 - (SEGMENT.intensity >> 1); |
| 10738 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | if (SEGMENT.check2) { // enable low pass filter for dynamic threshold |
| 10739 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | SEGMENT.step = (SEGMENT.step * 31500 + loudness * (32768 - 31500)) >> 15; // low pass filter for simple beat detection: add average to base threshold |
| 10740 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | threshold = 20 + (threshold >> 1) + SEGMENT.step; // add average to threshold |
| 10741 | } | ||
| 10742 | |||
| 10743 | // particle manipulation | ||
| 10744 |
2/2✓ Branch 0 taken 5496 times.
✓ Branch 1 taken 23 times.
|
5519 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10745 |
3/6✓ Branch 0 taken 5496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5496 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5496 times.
|
5496 | if (SEGMENT.check1) { // modulate colors by mid frequencies |
| 10746 | ✗ | int mids = sqrt32_bw((int)fftResult[5] + (int)fftResult[6] + (int)fftResult[7] + (int)fftResult[8] + (int)fftResult[9] + (int)fftResult[10]); // average the mids, bin 5 is ~500Hz, bin 10 is ~2kHz (see audio_reactive.h) | |
| 10747 | ✗ | PartSys->particles[i].hue += (mids * perlin8(PartSys->particles[i].x << 2, SEGMENT.step << 2)) >> 9; // color by perlin noise from mid frequencies | |
| 10748 | } | ||
| 10749 |
2/2✓ Branch 0 taken 374 times.
✓ Branch 1 taken 5122 times.
|
5496 | if (PartSys->particles[i].ttl > 16) { |
| 10750 | 374 | PartSys->particles[i].ttl -= 16; //ttl is linked to brightness, this allows to use higher brightness but still a (very) short lifespan | |
| 10751 | } | ||
| 10752 | } | ||
| 10753 | |||
| 10754 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 7 times.
|
23 | if (loudness > threshold) { |
| 10755 |
4/6✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 11 times.
|
16 | if (SEGMENT.aux1 == 0) { // edge detected, code only runs once per "beat" |
| 10756 | // update position | ||
| 10757 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
|
5 | if (SEGMENT.custom2 < 128) // fixed position |
| 10758 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | PartSys->sources[0].source.x = map(SEGMENT.custom2, 0, 127, 0, PartSys->maxX); |
| 10759 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | else if (SEGMENT.custom2 < 255) { // advances on each "beat" |
| 10760 | ✗ | int32_t step = PartSys->maxX / (((270 - SEGMENT.custom2) >> 3)); // step: 2 - 33 steps for full segment width | |
| 10761 | ✗ | PartSys->sources[0].source.x = (PartSys->sources[0].source.x + step) % PartSys->maxX; | |
| 10762 | ✗ | if (PartSys->sources[0].source.x < step) // align to be symmetrical by making the first position half a step from start | |
| 10763 | ✗ | PartSys->sources[0].source.x = step >> 1; | |
| 10764 | } | ||
| 10765 | else // position set to max, use random postion per beat | ||
| 10766 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | PartSys->sources[0].source.x = hw_random(PartSys->maxX); |
| 10767 | |||
| 10768 | // update color | ||
| 10769 | //PartSys->setColorByPosition(SEGMENT.custom1 == 255); // color slider at max: particle color by position | ||
| 10770 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
|
5 | PartSys->sources[0].sat = SEGMENT.custom1 > 0 ? 255 : 0; // color slider at zero: set to white |
| 10771 |
4/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
|
5 | if (SEGMENT.custom1 == 255) // emit color by position |
| 10772 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | SEGMENT.aux0 = map(PartSys->sources[0].source.x , 0, PartSys->maxX, 0, 255); |
| 10773 |
4/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 times.
|
4 | else if (SEGMENT.custom1 > 0) |
| 10774 |
4/8✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
3 | SEGMENT.aux0 += (SEGMENT.custom1 >> 1); // change emit color per "beat" |
| 10775 | } | ||
| 10776 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | SEGMENT.aux1 = 1; // track edge detection |
| 10777 | |||
| 10778 | 16 | PartSys->sources[0].minLife = 200; | |
| 10779 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | PartSys->sources[0].maxLife = PartSys->sources[0].minLife + (((unsigned)SEGMENT.intensity * loudness * loudness) >> 13); |
| 10780 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | PartSys->sources[0].source.hue = SEGMENT.aux0; |
| 10781 | 16 | PartSys->sources[0].size = 1; //SEGMENT.speed>>3; | |
| 10782 | 16 | uint32_t explosionsize = 4 + (PartSys->maxXpixel >> 2); | |
| 10783 | 16 | explosionsize = hw_random16((explosionsize * loudness) >> 10); | |
| 10784 |
2/2✓ Branch 0 taken 213 times.
✓ Branch 1 taken 16 times.
|
229 | for (uint32_t e = 0; e < explosionsize; e++) { // emit explosion particles |
| 10785 |
1/2✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
|
213 | PartSys->sprayEmit(PartSys->sources[0]); // emit a particle |
| 10786 | } | ||
| 10787 | } | ||
| 10788 | else | ||
| 10789 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | SEGMENT.aux1 = 0; // reset edge detection |
| 10790 | |||
| 10791 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render (needs to be done before manipulation for initial particle spacing to be right) |
| 10792 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10793 | } | ||
| 10794 | static const char _data_FX_MODE_PS_SONICBOOM[] PROGMEM = "PS Sonic Boom@!,!,Color,Position,Bin,Mod,Filter,Blur;,!;!;1f;c2=63,c3=0,o2=1"; | ||
| 10795 | |||
| 10796 | /* | ||
| 10797 | Particles bound by springs | ||
| 10798 | by DedeHai (Damian Schneider) | ||
| 10799 | */ | ||
| 10800 | 23 | uint16_t mode_particleSpringy(void) { | |
| 10801 | 23 | ParticleSystem1D *PartSys = nullptr; | |
| 10802 |
3/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 18 times.
|
23 | if (SEGMENT.call == 0) { // initialization |
| 10803 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (!initParticleSystem1D(PartSys, 1, 128, 0, true)) // init |
| 10804 | ✗ | return mode_static(); // allocation failed or is single pixel | |
| 10805 |
4/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | SEGENV.aux0 = SEGENV.aux1 = 0xFFFF; // invalidate settings |
| 10806 | } | ||
| 10807 | else | ||
| 10808 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS |
| 10809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys == nullptr) |
| 10810 | ✗ | return mode_static(); // something went wrong, no data! | |
| 10811 | // Particle System settings | ||
| 10812 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->updateSystem(); // update system properties (dimensions and data pointers) |
| 10813 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
|
23 | PartSys->setMotionBlur(220 * SEGMENT.check1); // anable motion blur |
| 10814 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->setSmearBlur(50); // smear a little |
| 10815 |
7/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 23 times.
✗ Branch 13 not taken.
|
23 | PartSys->setUsedParticles(map(SEGMENT.custom1, 0, 255, 30 >> SEGMENT.check2, 255 >> (SEGMENT.check2*2))); // depends on density and particle size |
| 10816 | // PartSys->enableParticleCollisions(true, 140); // enable particle collisions, can not be set too hard or impulses will not strech the springs if soft. | ||
| 10817 | 23 | int32_t springlength = PartSys->maxX / (PartSys->usedParticles); // spring length (spacing between particles) | |
| 10818 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | int32_t springK = map(SEGMENT.speed, 0, 255, 5, 35); // spring constant (stiffness) |
| 10819 | |||
| 10820 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | uint32_t settingssum = SEGMENT.custom1 + SEGMENT.check2; |
| 10821 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18 times.
|
23 | if (SEGENV.aux0 != settingssum) { // number of particles changed, update distribution |
| 10822 |
2/2✓ Branch 0 taken 357 times.
✓ Branch 1 taken 5 times.
|
362 | for (int32_t i = 0; i < (int32_t)PartSys->usedParticles; i++) { |
| 10823 | 357 | PartSys->advPartProps[i].sat = 255; // full saturation | |
| 10824 | //PartSys->particleFlags[i].collide = true; // enable collision for particles | ||
| 10825 | 357 | PartSys->particles[i].x = (i+1) * ((PartSys->maxX) / (PartSys->usedParticles)); // distribute | |
| 10826 | //PartSys->particles[i].vx = 0; //reset speed | ||
| 10827 |
3/6✓ Branch 0 taken 357 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 357 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 357 times.
|
357 | PartSys->advPartProps[i].size = SEGMENT.check2 ? 190 : 2; // set size, small or big |
| 10828 | } | ||
| 10829 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | SEGENV.aux0 = settingssum; |
| 10830 | } | ||
| 10831 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | int dxlimit = (2 + ((255 - SEGMENT.speed) >> 5)) * springlength; // limit for spring length to avoid overstretching |
| 10832 | |||
| 10833 | 23 | int springforce[PartSys->usedParticles]; // spring forces | |
| 10834 | 23 | memset(springforce, 0, PartSys->usedParticles * sizeof(int32_t)); // reset spring forces | |
| 10835 | |||
| 10836 | // calculate spring forces and limit particle positions | ||
| 10837 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys->particles[0].x < -springlength) |
| 10838 | ✗ | PartSys->particles[0].x = -springlength; // limit the spring length | |
| 10839 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | else if (PartSys->particles[0].x > dxlimit) |
| 10840 | ✗ | PartSys->particles[0].x = dxlimit; // limit the spring length | |
| 10841 | 23 | springforce[0] += ((springlength >> 1) - (PartSys->particles[0].x)) * springK; // first particle anchors to x=0 | |
| 10842 | |||
| 10843 |
2/2✓ Branch 0 taken 1552 times.
✓ Branch 1 taken 23 times.
|
1575 | for (uint32_t i = 1; i < PartSys->usedParticles; i++) { |
| 10844 | // reorder particles if they are out of order to prevent chaos | ||
| 10845 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1537 times.
|
1552 | if (PartSys->particles[i].x < PartSys->particles[i-1].x) |
| 10846 | 15 | std::swap(PartSys->particles[i].x, PartSys->particles[i-1].x); // swap particle positions to maintain order | |
| 10847 | 1552 | int dx = PartSys->particles[i].x - PartSys->particles[i-1].x; // distance, always positive | |
| 10848 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1552 times.
|
1552 | if (dx > dxlimit) { // limit the spring length |
| 10849 | ✗ | PartSys->particles[i].x = PartSys->particles[i-1].x + dxlimit; | |
| 10850 | ✗ | dx = dxlimit; | |
| 10851 | } | ||
| 10852 | 1552 | int dxleft = (springlength - dx); // offset from spring resting position | |
| 10853 | 1552 | springforce[i] += dxleft * springK; | |
| 10854 | 1552 | springforce[i-1] -= dxleft * springK; | |
| 10855 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1529 times.
|
1552 | if (i == (PartSys->usedParticles - 1)) { |
| 10856 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (PartSys->particles[i].x >= PartSys->maxX + springlength) |
| 10857 | ✗ | PartSys->particles[i].x = PartSys->maxX + springlength; | |
| 10858 | 23 | int dxright = (springlength >> 1) - (PartSys->maxX - PartSys->particles[i].x); // last particle anchors to x=maxX | |
| 10859 | 23 | springforce[i] -= dxright * springK; | |
| 10860 | } | ||
| 10861 | } | ||
| 10862 | // apply spring forces to particles | ||
| 10863 |
4/8✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
23 | bool dampenoscillations = (SEGMENT.call % (9 - (SEGMENT.speed >> 5))) == 0; // dampen oscillation if particles are slow, more damping on stiffer springs |
| 10864 |
2/2✓ Branch 0 taken 1575 times.
✓ Branch 1 taken 23 times.
|
1598 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10865 | 1575 | springforce[i] = springforce[i] / 64; // scale spring force (cannot use shifts because of negative values) | |
| 10866 | 1575 | int maxforce = 120; // limit spring force | |
| 10867 |
2/2✓ Branch 0 taken 1572 times.
✓ Branch 1 taken 3 times.
|
1575 | springforce[i] = springforce[i] > maxforce ? maxforce : springforce[i] < -maxforce ? -maxforce : springforce[i]; // limit spring force |
| 10868 |
1/2✓ Branch 0 taken 1575 times.
✗ Branch 1 not taken.
|
1575 | PartSys->applyForce(PartSys->particles[i], springforce[i], PartSys->advPartProps[i].forcecounter); |
| 10869 | //dampen slow particles to avoid persisting oscillations on higher stiffness | ||
| 10870 |
2/2✓ Branch 0 taken 545 times.
✓ Branch 1 taken 1030 times.
|
1575 | if (dampenoscillations) { |
| 10871 |
3/4✓ Branch 0 taken 545 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 534 times.
✓ Branch 3 taken 11 times.
|
545 | if (abs(PartSys->particles[i].vx) < 3 && abs(springforce[i]) < (springK >> 2)) |
| 10872 | 534 | PartSys->particles[i].vx = (PartSys->particles[i].vx * 254) / 256; // take out some energy | |
| 10873 | } | ||
| 10874 | 1575 | PartSys->particles[i].ttl = 300; // reset ttl, cannot use perpetual | |
| 10875 | } | ||
| 10876 | |||
| 10877 |
8/14✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 17 times.
|
23 | if (SEGMENT.call % ((65 - ((SEGMENT.intensity * (1 + (SEGMENT.speed>>3))) >> 7))) == 0) // more damping for higher stiffness |
| 10878 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | PartSys->applyFriction((SEGMENT.intensity >> 2)); |
| 10879 | |||
| 10880 | // add a small resetting force so particles return to resting position even under high damping | ||
| 10881 |
2/2✓ Branch 0 taken 1529 times.
✓ Branch 1 taken 23 times.
|
1552 | for (uint32_t i = 1; i < PartSys->usedParticles - 1; i++) { |
| 10882 | 1529 | int restposition = (springlength >> 1) + i * springlength; // resting position | |
| 10883 | 1529 | int dx = restposition - PartSys->particles[i].x; // distance, always positive | |
| 10884 |
4/6✓ Branch 0 taken 1521 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1521 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1529 times.
✗ Branch 5 not taken.
|
1529 | PartSys->applyForce(PartSys->particles[i], dx > 0 ? 1 : (dx < 0 ? -1 : 0), PartSys->advPartProps[i].forcecounter); |
| 10885 | } | ||
| 10886 | |||
| 10887 | // Modes | ||
| 10888 |
3/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
|
23 | if (SEGMENT.check3) { // use AR, custom 3 becomes frequency band to use, applies velocity to center particle according to loudness |
| 10889 | ✗ | um_data_t *um_data = getAudioData(); | |
| 10890 | ✗ | uint8_t *fftResult = (uint8_t *)um_data->u_data[2]; // 16 bins with FFT data, log mapped already, each band contains frequency amplitude 0-255 | |
| 10891 | ✗ | uint32_t baseBin = map(SEGMENT.custom3, 0, 31, 0, 14); | |
| 10892 | ✗ | uint32_t loudness = fftResult[baseBin] + fftResult[baseBin+1]; | |
| 10893 | ✗ | uint32_t threshold = 80; //150 - (SEGMENT.intensity >> 1); | |
| 10894 | ✗ | if (loudness > threshold) { | |
| 10895 | ✗ | int offset = (PartSys->maxX >> 1) - PartSys->particles[PartSys->usedParticles>>1].x; // offset from center | |
| 10896 | ✗ | if (abs(offset) < PartSys->maxX >> 5) // push particle around in center sector | |
| 10897 | ✗ | PartSys->particles[PartSys->usedParticles>>1].vx = ((PartSys->particles[PartSys->usedParticles>>1].vx > 0 ? 1 : -1)) * (loudness >> 3); | |
| 10898 | } | ||
| 10899 | } | ||
| 10900 | else{ | ||
| 10901 |
4/6✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
|
23 | if (SEGMENT.custom3 <= 10) { // periodic pulse: 0-5 apply at start, 6-10 apply at center |
| 10902 |
5/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3 times.
|
4 | if (strip().now > SEGMENT.step) { |
| 10903 |
5/14✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
|
1 | int speed = (SEGMENT.custom3 > 5) ? (SEGMENT.custom3 - 6) : SEGMENT.custom3; |
| 10904 |
5/10✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | SEGMENT.step = strip().now + 7500 - ((SEGMENT.speed << 3) + (speed << 10)); |
| 10905 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | int amplitude = 40 + (SEGMENT.custom1 >> 2); |
| 10906 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | int index = (SEGMENT.custom3 > 5) ? (PartSys->usedParticles / 2) : 0; // center or start particle |
| 10907 | 1 | PartSys->particles[index].vx += amplitude; | |
| 10908 | } | ||
| 10909 | } | ||
| 10910 |
4/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 4 times.
|
19 | else if (SEGMENT.custom3 <= 30) { // sinusoidal wave: 11-20 apply at start, 21-30 apply at center |
| 10911 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | int index = (SEGMENT.custom3 > 20) ? (PartSys->usedParticles / 2) : 0; // center or start particle |
| 10912 | 15 | int restposition = 0; | |
| 10913 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if (index > 0) restposition = PartSys->maxX >> 1; // center |
| 10914 | //int amplitude = 5 + (SEGMENT.speed >> 3) + (SEGMENT.custom1 >> 2); // amplitude depends on density | ||
| 10915 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | int amplitude = 5 + (SEGMENT.custom1 >> 2); // amplitude depends on density |
| 10916 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | int speed = SEGMENT.custom3 - 10 - (index ? 10 : 0); // map 11-20 and 21-30 to 1-10 |
| 10917 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | int phase = strip().now * ((1 + (SEGMENT.speed >> 4)) * speed); |
| 10918 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
|
15 | if (SEGMENT.check2) amplitude <<= 1; // double amplitude for XL particles |
| 10919 | //PartSys->applyForce(PartSys->particles[index], (sin16_t(phase) * amplitude) >> 15, PartSys->advPartProps[index].forcecounter); // apply acceleration | ||
| 10920 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | PartSys->particles[index].x = restposition + ((sin16_t(phase) * amplitude) >> 12); // apply position |
| 10921 | } | ||
| 10922 | else { | ||
| 10923 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (hw_random16() < 656) { // ~1% chance to add a pulse |
| 10924 | ✗ | int amplitude = 60; | |
| 10925 | ✗ | if (SEGMENT.check2) amplitude <<= 1; // double amplitude for XL particles | |
| 10926 | ✗ | PartSys->particles[PartSys->usedParticles >> 1].vx += hw_random16(amplitude << 1) - amplitude; // apply acceleration | |
| 10927 | } | ||
| 10928 | } | ||
| 10929 | } | ||
| 10930 | |||
| 10931 |
2/2✓ Branch 0 taken 1575 times.
✓ Branch 1 taken 23 times.
|
1598 | for (uint32_t i = 0; i < PartSys->usedParticles; i++) { |
| 10932 |
4/6✓ Branch 0 taken 1575 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1575 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 752 times.
✓ Branch 5 taken 823 times.
|
1575 | if (SEGMENT.custom2 == 255) { // map speed to hue |
| 10933 | 752 | int speedclr = ((int8_t(abs(PartSys->particles[i].vx))) >> 2) << 4; // scale for greater color variation, dump small values to avoid flickering | |
| 10934 | //int speed = PartSys->particles[i].vx << 2; // +/- 512 | ||
| 10935 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 752 times.
|
752 | if (speedclr > 240) speedclr = 240; // limit color to non-wrapping part of palette |
| 10936 | 752 | PartSys->particles[i].hue = speedclr; | |
| 10937 | } | ||
| 10938 |
3/6✓ Branch 0 taken 823 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 823 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 823 times.
|
823 | else if (SEGMENT.custom2 > 0) |
| 10939 | ✗ | PartSys->particles[i].hue = i * (SEGMENT.custom2 >> 2); // gradient distribution | |
| 10940 | else { | ||
| 10941 | // map hue to particle density | ||
| 10942 | int deviation; | ||
| 10943 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 804 times.
|
823 | if (i == 0) // First particle: measure density based on distance to anchor point |
| 10944 | 19 | deviation = springlength/2 - PartSys->particles[i].x; | |
| 10945 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 785 times.
|
804 | else if (i == PartSys->usedParticles - 1) // Last particle: measure density based on distance to right boundary |
| 10946 | 19 | deviation = springlength/2 - (PartSys->maxX - PartSys->particles[i].x); | |
| 10947 | else { | ||
| 10948 | // Middle particles: average of compression/expansion from both sides | ||
| 10949 | 785 | int leftDx = PartSys->particles[i].x - PartSys->particles[i-1].x; | |
| 10950 | 785 | int rightDx = PartSys->particles[i+1].x - PartSys->particles[i].x; | |
| 10951 | 785 | int avgDistance = (leftDx + rightDx) >> 1; | |
| 10952 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 776 times.
|
785 | if (avgDistance < 0) avgDistance = 0; // avoid negative distances (not sure why this happens) |
| 10953 | 785 | deviation = (springlength - avgDistance); | |
| 10954 | } | ||
| 10955 | 823 | deviation = constrain(deviation, -127, 112); // limit deviation to -127..112 (do not go intwo wrapping part of palette) | |
| 10956 | 823 | PartSys->particles[i].hue = 127 + deviation; // map density to hue | |
| 10957 | } | ||
| 10958 | } | ||
| 10959 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | PartSys->update(); // update and render |
| 10960 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | return FRAMETIME; |
| 10961 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | } |
| 10962 | static const char _data_FX_MODE_PS_SPRINGY[] PROGMEM = "PS Springy@Stiffness,Damping,Density,Hue,Mode,Smear,XL,AR;,!;!;1f;pal=54,c2=0,c3=23"; | ||
| 10963 | |||
| 10964 | #endif // WLED_DISABLE_PARTICLESYSTEM1D | ||
| 10965 | |||
| 10966 | ////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10967 | // mode data | ||
| 10968 | static const char _data_RESERVED[] PROGMEM = "RSVD"; | ||
| 10969 | |||
| 10970 | // add (or replace reserved) effect mode and data into vector | ||
| 10971 | // use id==255 to find unallocated gaps (with "Reserved" data string) | ||
| 10972 | // if vector size() is smaller than id (single) data is appended at the end (regardless of id) | ||
| 10973 | // return the actual id used for the effect or 255 if the add failed. | ||
| 10974 | 757988 | uint8_t WS2812FX::addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name) { | |
| 10975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 757988 times.
|
757988 | if (id == 255) { // find empty slot |
| 10976 | ✗ | for (size_t i=1; i<_mode.size(); i++) if (_modeData[i] == _data_RESERVED) { id = i; break; } | |
| 10977 | } | ||
| 10978 |
1/2✓ Branch 0 taken 757988 times.
✗ Branch 1 not taken.
|
757988 | if (id < _mode.size()) { |
| 10979 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 757988 times.
|
757988 | if (_modeData[id] != _data_RESERVED) return 255; // do not overwrite an already added effect |
| 10980 | 757988 | _mode[id] = mode_fn; | |
| 10981 | 757988 | _modeData[id] = mode_name; | |
| 10982 | 757988 | return id; | |
| 10983 | ✗ | } else if (_mode.size() < 255) { // 255 is reserved for indicating the effect wasn't added | |
| 10984 | ✗ | _mode.push_back(mode_fn); | |
| 10985 | ✗ | _modeData.push_back(mode_name); | |
| 10986 | ✗ | if (_modeCount < _mode.size()) _modeCount++; | |
| 10987 | ✗ | return _mode.size() - 1; | |
| 10988 | } else { | ||
| 10989 | ✗ | return 255; // The vector is full so return 255 | |
| 10990 | } | ||
| 10991 | } | ||
| 10992 | |||
| 10993 | 3542 | void WS2812FX::setupEffectData() { | |
| 10994 | // Solid must be first! (assuming vector is empty upon call to setup) | ||
| 10995 |
1/2✓ Branch 0 taken 3542 times.
✗ Branch 1 not taken.
|
3542 | _mode.push_back(&mode_static); |
| 10996 |
1/2✓ Branch 0 taken 3542 times.
✗ Branch 1 not taken.
|
3542 | _modeData.push_back(_data_FX_MODE_STATIC); |
| 10997 | // fill reserved word in case there will be any gaps in the array | ||
| 10998 |
2/2✓ Branch 0 taken 775698 times.
✓ Branch 1 taken 3542 times.
|
779240 | for (size_t i=1; i<_modeCount; i++) { |
| 10999 |
1/2✓ Branch 0 taken 775698 times.
✗ Branch 1 not taken.
|
775698 | _mode.push_back(&mode_static); |
| 11000 |
1/2✓ Branch 0 taken 775698 times.
✗ Branch 1 not taken.
|
775698 | _modeData.push_back(_data_RESERVED); |
| 11001 | } | ||
| 11002 | // now replace all pre-allocated effects | ||
| 11003 | // --- 1D non-audio effects --- | ||
| 11004 | 3542 | addEffect(FX_MODE_BLINK, &mode_blink, _data_FX_MODE_BLINK); | |
| 11005 | 3542 | addEffect(FX_MODE_BREATH, &mode_breath, _data_FX_MODE_BREATH); | |
| 11006 | 3542 | addEffect(FX_MODE_COLOR_WIPE, &mode_color_wipe, _data_FX_MODE_COLOR_WIPE); | |
| 11007 | 3542 | addEffect(FX_MODE_COLOR_WIPE_RANDOM, &mode_color_wipe_random, _data_FX_MODE_COLOR_WIPE_RANDOM); | |
| 11008 | 3542 | addEffect(FX_MODE_RANDOM_COLOR, &mode_random_color, _data_FX_MODE_RANDOM_COLOR); | |
| 11009 | 3542 | addEffect(FX_MODE_COLOR_SWEEP, &mode_color_sweep, _data_FX_MODE_COLOR_SWEEP); | |
| 11010 | 3542 | addEffect(FX_MODE_DYNAMIC, &mode_dynamic, _data_FX_MODE_DYNAMIC); | |
| 11011 | 3542 | addEffect(FX_MODE_RAINBOW, &mode_rainbow, _data_FX_MODE_RAINBOW); | |
| 11012 | 3542 | addEffect(FX_MODE_RAINBOW_CYCLE, &mode_rainbow_cycle, _data_FX_MODE_RAINBOW_CYCLE); | |
| 11013 | 3542 | addEffect(FX_MODE_SCAN, &mode_scan, _data_FX_MODE_SCAN); | |
| 11014 | 3542 | addEffect(FX_MODE_DUAL_SCAN, &mode_dual_scan, _data_FX_MODE_DUAL_SCAN); | |
| 11015 | 3542 | addEffect(FX_MODE_FADE, &mode_fade, _data_FX_MODE_FADE); | |
| 11016 | 3542 | addEffect(FX_MODE_THEATER_CHASE, &mode_theater_chase, _data_FX_MODE_THEATER_CHASE); | |
| 11017 | 3542 | addEffect(FX_MODE_THEATER_CHASE_RAINBOW, &mode_theater_chase_rainbow, _data_FX_MODE_THEATER_CHASE_RAINBOW); | |
| 11018 | 3542 | addEffect(FX_MODE_RUNNING_LIGHTS, &mode_running_lights, _data_FX_MODE_RUNNING_LIGHTS); | |
| 11019 | 3542 | addEffect(FX_MODE_SAW, &mode_saw, _data_FX_MODE_SAW); | |
| 11020 | 3542 | addEffect(FX_MODE_TWINKLE, &mode_twinkle, _data_FX_MODE_TWINKLE); | |
| 11021 | 3542 | addEffect(FX_MODE_DISSOLVE, &mode_dissolve, _data_FX_MODE_DISSOLVE); | |
| 11022 | 3542 | addEffect(FX_MODE_DISSOLVE_RANDOM, &mode_dissolve_random, _data_FX_MODE_DISSOLVE_RANDOM); | |
| 11023 | 3542 | addEffect(FX_MODE_FLASH_SPARKLE, &mode_flash_sparkle, _data_FX_MODE_FLASH_SPARKLE); | |
| 11024 | 3542 | addEffect(FX_MODE_HYPER_SPARKLE, &mode_hyper_sparkle, _data_FX_MODE_HYPER_SPARKLE); | |
| 11025 | 3542 | addEffect(FX_MODE_STROBE, &mode_strobe, _data_FX_MODE_STROBE); | |
| 11026 | 3542 | addEffect(FX_MODE_STROBE_RAINBOW, &mode_strobe_rainbow, _data_FX_MODE_STROBE_RAINBOW); | |
| 11027 | 3542 | addEffect(FX_MODE_MULTI_STROBE, &mode_multi_strobe, _data_FX_MODE_MULTI_STROBE); | |
| 11028 | 3542 | addEffect(FX_MODE_BLINK_RAINBOW, &mode_blink_rainbow, _data_FX_MODE_BLINK_RAINBOW); | |
| 11029 | 3542 | addEffect(FX_MODE_ANDROID, &mode_android, _data_FX_MODE_ANDROID); | |
| 11030 | 3542 | addEffect(FX_MODE_CHASE_COLOR, &mode_chase_color, _data_FX_MODE_CHASE_COLOR); | |
| 11031 | 3542 | addEffect(FX_MODE_CHASE_RANDOM, &mode_chase_random, _data_FX_MODE_CHASE_RANDOM); | |
| 11032 | 3542 | addEffect(FX_MODE_CHASE_RAINBOW, &mode_chase_rainbow, _data_FX_MODE_CHASE_RAINBOW); | |
| 11033 | 3542 | addEffect(FX_MODE_CHASE_FLASH, &mode_chase_flash, _data_FX_MODE_CHASE_FLASH); | |
| 11034 | 3542 | addEffect(FX_MODE_CHASE_FLASH_RANDOM, &mode_chase_flash_random, _data_FX_MODE_CHASE_FLASH_RANDOM); | |
| 11035 | 3542 | addEffect(FX_MODE_CHASE_RAINBOW_WHITE, &mode_chase_rainbow_white, _data_FX_MODE_CHASE_RAINBOW_WHITE); | |
| 11036 | 3542 | addEffect(FX_MODE_COLORFUL, &mode_colorful, _data_FX_MODE_COLORFUL); | |
| 11037 | 3542 | addEffect(FX_MODE_TRAFFIC_LIGHT, &mode_traffic_light, _data_FX_MODE_TRAFFIC_LIGHT); | |
| 11038 | 3542 | addEffect(FX_MODE_COLOR_SWEEP_RANDOM, &mode_color_sweep_random, _data_FX_MODE_COLOR_SWEEP_RANDOM); | |
| 11039 | 3542 | addEffect(FX_MODE_RUNNING_COLOR, &mode_running_color, _data_FX_MODE_RUNNING_COLOR); | |
| 11040 | 3542 | addEffect(FX_MODE_AURORA, &mode_aurora, _data_FX_MODE_AURORA); | |
| 11041 | 3542 | addEffect(FX_MODE_RUNNING_RANDOM, &mode_running_random, _data_FX_MODE_RUNNING_RANDOM); | |
| 11042 | 3542 | addEffect(FX_MODE_LARSON_SCANNER, &mode_larson_scanner, _data_FX_MODE_LARSON_SCANNER); | |
| 11043 | 3542 | addEffect(FX_MODE_RAIN, &mode_rain, _data_FX_MODE_RAIN); | |
| 11044 | 3542 | addEffect(FX_MODE_PRIDE_2015, &mode_pride_2015, _data_FX_MODE_PRIDE_2015); | |
| 11045 | 3542 | addEffect(FX_MODE_COLORWAVES, &mode_colorwaves, _data_FX_MODE_COLORWAVES); | |
| 11046 | 3542 | addEffect(FX_MODE_FIREWORKS, &mode_fireworks, _data_FX_MODE_FIREWORKS); | |
| 11047 | 3542 | addEffect(FX_MODE_TETRIX, &mode_tetrix, _data_FX_MODE_TETRIX); | |
| 11048 | 3542 | addEffect(FX_MODE_FIRE_FLICKER, &mode_fire_flicker, _data_FX_MODE_FIRE_FLICKER); | |
| 11049 | 3542 | addEffect(FX_MODE_GRADIENT, &mode_gradient, _data_FX_MODE_GRADIENT); | |
| 11050 | 3542 | addEffect(FX_MODE_LOADING, &mode_loading, _data_FX_MODE_LOADING); | |
| 11051 | 3542 | addEffect(FX_MODE_FAIRY, &mode_fairy, _data_FX_MODE_FAIRY); | |
| 11052 | 3542 | addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); | |
| 11053 | 3542 | addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE); | |
| 11054 | 3542 | addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL); | |
| 11055 | #ifdef WLED_ENABLE_GIF | ||
| 11056 | addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE); | ||
| 11057 | #endif | ||
| 11058 | 3542 | addEffect(FX_MODE_TRICOLOR_CHASE, &mode_tricolor_chase, _data_FX_MODE_TRICOLOR_CHASE); | |
| 11059 | 3542 | addEffect(FX_MODE_TRICOLOR_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE); | |
| 11060 | 3542 | addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE); | |
| 11061 | 3542 | addEffect(FX_MODE_LIGHTNING, &mode_lightning, _data_FX_MODE_LIGHTNING); | |
| 11062 | 3542 | addEffect(FX_MODE_ICU, &mode_icu, _data_FX_MODE_ICU); | |
| 11063 | 3542 | addEffect(FX_MODE_DUAL_LARSON_SCANNER, &mode_dual_larson_scanner, _data_FX_MODE_DUAL_LARSON_SCANNER); | |
| 11064 | 3542 | addEffect(FX_MODE_RANDOM_CHASE, &mode_random_chase, _data_FX_MODE_RANDOM_CHASE); | |
| 11065 | 3542 | addEffect(FX_MODE_OSCILLATE, &mode_oscillate, _data_FX_MODE_OSCILLATE); | |
| 11066 | 3542 | addEffect(FX_MODE_JUGGLE, &mode_juggle, _data_FX_MODE_JUGGLE); | |
| 11067 | 3542 | addEffect(FX_MODE_PALETTE, &mode_palette, _data_FX_MODE_PALETTE); | |
| 11068 | 3542 | addEffect(FX_MODE_BPM, &mode_bpm, _data_FX_MODE_BPM); | |
| 11069 | 3542 | addEffect(FX_MODE_FILLNOISE8, &mode_fillnoise8, _data_FX_MODE_FILLNOISE8); | |
| 11070 | 3542 | addEffect(FX_MODE_NOISE16_1, &mode_noise16_1, _data_FX_MODE_NOISE16_1); | |
| 11071 | 3542 | addEffect(FX_MODE_NOISE16_2, &mode_noise16_2, _data_FX_MODE_NOISE16_2); | |
| 11072 | 3542 | addEffect(FX_MODE_NOISE16_3, &mode_noise16_3, _data_FX_MODE_NOISE16_3); | |
| 11073 | 3542 | addEffect(FX_MODE_NOISE16_4, &mode_noise16_4, _data_FX_MODE_NOISE16_4); | |
| 11074 | 3542 | addEffect(FX_MODE_COLORTWINKLE, &mode_colortwinkle, _data_FX_MODE_COLORTWINKLE); | |
| 11075 | 3542 | addEffect(FX_MODE_LAKE, &mode_lake, _data_FX_MODE_LAKE); | |
| 11076 | 3542 | addEffect(FX_MODE_METEOR, &mode_meteor, _data_FX_MODE_METEOR); | |
| 11077 | //addEffect(FX_MODE_METEOR_SMOOTH, &mode_meteor_smooth, _data_FX_MODE_METEOR_SMOOTH); // merged with mode_meteor | ||
| 11078 | 3542 | addEffect(FX_MODE_RAILWAY, &mode_railway, _data_FX_MODE_RAILWAY); | |
| 11079 | 3542 | addEffect(FX_MODE_RIPPLE, &mode_ripple, _data_FX_MODE_RIPPLE); | |
| 11080 | 3542 | addEffect(FX_MODE_TWINKLEFOX, &mode_twinklefox, _data_FX_MODE_TWINKLEFOX); | |
| 11081 | 3542 | addEffect(FX_MODE_TWINKLECAT, &mode_twinklecat, _data_FX_MODE_TWINKLECAT); | |
| 11082 | 3542 | addEffect(FX_MODE_HALLOWEEN_EYES, &mode_halloween_eyes, _data_FX_MODE_HALLOWEEN_EYES); | |
| 11083 | 3542 | addEffect(FX_MODE_STATIC_PATTERN, &mode_static_pattern, _data_FX_MODE_STATIC_PATTERN); | |
| 11084 | 3542 | addEffect(FX_MODE_TRI_STATIC_PATTERN, &mode_tri_static_pattern, _data_FX_MODE_TRI_STATIC_PATTERN); | |
| 11085 | 3542 | addEffect(FX_MODE_SPOTS, &mode_spots, _data_FX_MODE_SPOTS); | |
| 11086 | 3542 | addEffect(FX_MODE_SPOTS_FADE, &mode_spots_fade, _data_FX_MODE_SPOTS_FADE); | |
| 11087 | 3542 | addEffect(FX_MODE_COMET, &mode_comet, _data_FX_MODE_COMET); | |
| 11088 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 11089 | 3542 | addEffect(FX_MODE_MULTI_COMET, &mode_multi_comet, _data_FX_MODE_MULTI_COMET); | |
| 11090 | 3542 | addEffect(FX_MODE_ROLLINGBALLS, &rolling_balls, _data_FX_MODE_ROLLINGBALLS); | |
| 11091 | 3542 | addEffect(FX_MODE_SHIMMER, &mode_shimmer, _data_FX_MODE_SHIMMER); | |
| 11092 | 3542 | addEffect(FX_MODE_COPY, &mode_copy_segment, _data_FX_MODE_COPY); | |
| 11093 | 3542 | addEffect(FX_MODE_COLORCLOUDS, &mode_ColorClouds, _data_FX_MODE_COLORCLOUDS); | |
| 11094 | 3542 | addEffect(FX_MODE_PACMAN, &mode_pacman, _data_FX_MODE_PACMAN); | |
| 11095 | 3542 | addEffect(FX_MODE_SLOW_TRANSITION, &mode_slow_transition, _data_FX_MODE_SLOW_TRANSITION); | |
| 11096 | 3542 | addEffect(FX_MODE_SPARKLE, &mode_sparkle, _data_FX_MODE_SPARKLE); | |
| 11097 | 3542 | addEffect(FX_MODE_GLITTER, &mode_glitter, _data_FX_MODE_GLITTER); | |
| 11098 | 3542 | addEffect(FX_MODE_SOLID_GLITTER, &mode_solid_glitter, _data_FX_MODE_SOLID_GLITTER); | |
| 11099 | 3542 | addEffect(FX_MODE_STARBURST, &mode_starburst, _data_FX_MODE_STARBURST); | |
| 11100 | 3542 | addEffect(FX_MODE_DANCING_SHADOWS, &mode_dancing_shadows, _data_FX_MODE_DANCING_SHADOWS); | |
| 11101 | 3542 | addEffect(FX_MODE_FIRE_2012, &mode_fire_2012, _data_FX_MODE_FIRE_2012); | |
| 11102 | 3542 | addEffect(FX_MODE_EXPLODING_FIREWORKS, &mode_exploding_fireworks, _data_FX_MODE_EXPLODING_FIREWORKS); | |
| 11103 | #endif | ||
| 11104 | 3542 | addEffect(FX_MODE_CANDLE, &mode_candle, _data_FX_MODE_CANDLE); | |
| 11105 | 3542 | addEffect(FX_MODE_BOUNCINGBALLS, &mode_bouncing_balls, _data_FX_MODE_BOUNCINGBALLS); | |
| 11106 | 3542 | addEffect(FX_MODE_POPCORN, &mode_popcorn, _data_FX_MODE_POPCORN); | |
| 11107 | 3542 | addEffect(FX_MODE_DRIP, &mode_drip, _data_FX_MODE_DRIP); | |
| 11108 | 3542 | addEffect(FX_MODE_SINELON, &mode_sinelon, _data_FX_MODE_SINELON); | |
| 11109 | 3542 | addEffect(FX_MODE_SINELON_DUAL, &mode_sinelon_dual, _data_FX_MODE_SINELON_DUAL); | |
| 11110 | 3542 | addEffect(FX_MODE_SINELON_RAINBOW, &mode_sinelon_rainbow, _data_FX_MODE_SINELON_RAINBOW); | |
| 11111 | 3542 | addEffect(FX_MODE_PLASMA, &mode_plasma, _data_FX_MODE_PLASMA); | |
| 11112 | 3542 | addEffect(FX_MODE_PERCENT, &mode_percent, _data_FX_MODE_PERCENT); | |
| 11113 | 3542 | addEffect(FX_MODE_RIPPLE_RAINBOW, &mode_ripple_rainbow, _data_FX_MODE_RIPPLE_RAINBOW); | |
| 11114 | 3542 | addEffect(FX_MODE_HEARTBEAT, &mode_heartbeat, _data_FX_MODE_HEARTBEAT); | |
| 11115 | 3542 | addEffect(FX_MODE_PACIFICA, &mode_pacifica, _data_FX_MODE_PACIFICA); | |
| 11116 | 3542 | addEffect(FX_MODE_CANDLE_MULTI, &mode_candle_multi, _data_FX_MODE_CANDLE_MULTI); | |
| 11117 | 3542 | addEffect(FX_MODE_SUNRISE, &mode_sunrise, _data_FX_MODE_SUNRISE); | |
| 11118 | 3542 | addEffect(FX_MODE_PHASED, &mode_phased, _data_FX_MODE_PHASED); | |
| 11119 | 3542 | addEffect(FX_MODE_TWINKLEUP, &mode_twinkleup, _data_FX_MODE_TWINKLEUP); | |
| 11120 | 3542 | addEffect(FX_MODE_NOISEPAL, &mode_noisepal, _data_FX_MODE_NOISEPAL); | |
| 11121 | 3542 | addEffect(FX_MODE_SINEWAVE, &mode_sinewave, _data_FX_MODE_SINEWAVE); | |
| 11122 | 3542 | addEffect(FX_MODE_PHASEDNOISE, &mode_phased_noise, _data_FX_MODE_PHASEDNOISE); | |
| 11123 | 3542 | addEffect(FX_MODE_FLOW, &mode_flow, _data_FX_MODE_FLOW); | |
| 11124 | 3542 | addEffect(FX_MODE_CHUNCHUN, &mode_chunchun, _data_FX_MODE_CHUNCHUN); | |
| 11125 | 3542 | addEffect(FX_MODE_WASHING_MACHINE, &mode_washing_machine, _data_FX_MODE_WASHING_MACHINE); | |
| 11126 | 3542 | addEffect(FX_MODE_BLENDS, &mode_blends, _data_FX_MODE_BLENDS); | |
| 11127 | 3542 | addEffect(FX_MODE_TV_SIMULATOR, &mode_tv_simulator, _data_FX_MODE_TV_SIMULATOR); | |
| 11128 | 3542 | addEffect(FX_MODE_DYNAMIC_SMOOTH, &mode_dynamic_smooth, _data_FX_MODE_DYNAMIC_SMOOTH); | |
| 11129 | |||
| 11130 | // --- 1D audio effects --- | ||
| 11131 | 3542 | addEffect(FX_MODE_PIXELS, &mode_pixels, _data_FX_MODE_PIXELS); | |
| 11132 | 3542 | addEffect(FX_MODE_PIXELWAVE, &mode_pixelwave, _data_FX_MODE_PIXELWAVE); | |
| 11133 | 3542 | addEffect(FX_MODE_JUGGLES, &mode_juggles, _data_FX_MODE_JUGGLES); | |
| 11134 | 3542 | addEffect(FX_MODE_MATRIPIX, &mode_matripix, _data_FX_MODE_MATRIPIX); | |
| 11135 | 3542 | addEffect(FX_MODE_GRAVIMETER, &mode_gravimeter, _data_FX_MODE_GRAVIMETER); | |
| 11136 | 3542 | addEffect(FX_MODE_PLASMOID, &mode_plasmoid, _data_FX_MODE_PLASMOID); | |
| 11137 | 3542 | addEffect(FX_MODE_PUDDLES, &mode_puddles, _data_FX_MODE_PUDDLES); | |
| 11138 | 3542 | addEffect(FX_MODE_MIDNOISE, &mode_midnoise, _data_FX_MODE_MIDNOISE); | |
| 11139 | 3542 | addEffect(FX_MODE_NOISEMETER, &mode_noisemeter, _data_FX_MODE_NOISEMETER); | |
| 11140 | 3542 | addEffect(FX_MODE_FREQWAVE, &mode_freqwave, _data_FX_MODE_FREQWAVE); | |
| 11141 | 3542 | addEffect(FX_MODE_FREQMATRIX, &mode_freqmatrix, _data_FX_MODE_FREQMATRIX); | |
| 11142 | 3542 | addEffect(FX_MODE_WATERFALL, &mode_waterfall, _data_FX_MODE_WATERFALL); | |
| 11143 | 3542 | addEffect(FX_MODE_FREQPIXELS, &mode_freqpixels, _data_FX_MODE_FREQPIXELS); | |
| 11144 | 3542 | addEffect(FX_MODE_NOISEFIRE, &mode_noisefire, _data_FX_MODE_NOISEFIRE); | |
| 11145 | 3542 | addEffect(FX_MODE_PUDDLEPEAK, &mode_puddlepeak, _data_FX_MODE_PUDDLEPEAK); | |
| 11146 | 3542 | addEffect(FX_MODE_NOISEMOVE, &mode_noisemove, _data_FX_MODE_NOISEMOVE); | |
| 11147 | 3542 | addEffect(FX_MODE_PERLINMOVE, &mode_perlinmove, _data_FX_MODE_PERLINMOVE); | |
| 11148 | 3542 | addEffect(FX_MODE_RIPPLEPEAK, &mode_ripplepeak, _data_FX_MODE_RIPPLEPEAK); | |
| 11149 | 3542 | addEffect(FX_MODE_FREQMAP, &mode_freqmap, _data_FX_MODE_FREQMAP); | |
| 11150 | 3542 | addEffect(FX_MODE_GRAVCENTER, &mode_gravcenter, _data_FX_MODE_GRAVCENTER); | |
| 11151 | 3542 | addEffect(FX_MODE_GRAVCENTRIC, &mode_gravcentric, _data_FX_MODE_GRAVCENTRIC); | |
| 11152 | 3542 | addEffect(FX_MODE_GRAVFREQ, &mode_gravfreq, _data_FX_MODE_GRAVFREQ); | |
| 11153 | 3542 | addEffect(FX_MODE_DJLIGHT, &mode_DJLight, _data_FX_MODE_DJLIGHT); | |
| 11154 | 3542 | addEffect(FX_MODE_BLURZ, &mode_blurz, _data_FX_MODE_BLURZ); | |
| 11155 | 3542 | addEffect(FX_MODE_FLOWSTRIPE, &mode_FlowStripe, _data_FX_MODE_FLOWSTRIPE); | |
| 11156 | 3542 | addEffect(FX_MODE_WAVESINS, &mode_wavesins, _data_FX_MODE_WAVESINS); | |
| 11157 | 3542 | addEffect(FX_MODE_ROCKTAVES, &mode_rocktaves, _data_FX_MODE_ROCKTAVES); | |
| 11158 | |||
| 11159 | // --- 2D effects --- | ||
| 11160 | #ifndef WLED_DISABLE_2D | ||
| 11161 | 3542 | addEffect(FX_MODE_2DPLASMAROTOZOOM, &mode_2Dplasmarotozoom, _data_FX_MODE_2DPLASMAROTOZOOM); | |
| 11162 | 3542 | addEffect(FX_MODE_2DSPACESHIPS, &mode_2Dspaceships, _data_FX_MODE_2DSPACESHIPS); | |
| 11163 | 3542 | addEffect(FX_MODE_2DCRAZYBEES, &mode_2Dcrazybees, _data_FX_MODE_2DCRAZYBEES); | |
| 11164 | |||
| 11165 | #ifdef WLED_PS_DONT_REPLACE_FX | ||
| 11166 | 3542 | addEffect(FX_MODE_2DGHOSTRIDER, &mode_2Dghostrider, _data_FX_MODE_2DGHOSTRIDER); | |
| 11167 | 3542 | addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS); | |
| 11168 | #endif | ||
| 11169 | |||
| 11170 | 3542 | addEffect(FX_MODE_2DSCROLLTEXT, &mode_2Dscrollingtext, _data_FX_MODE_2DSCROLLTEXT); | |
| 11171 | 3542 | addEffect(FX_MODE_2DDRIFTROSE, &mode_2Ddriftrose, _data_FX_MODE_2DDRIFTROSE); | |
| 11172 | 3542 | addEffect(FX_MODE_2DDISTORTIONWAVES, &mode_2Ddistortionwaves, _data_FX_MODE_2DDISTORTIONWAVES); | |
| 11173 | 3542 | addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ); // audio | |
| 11174 | 3542 | addEffect(FX_MODE_2DNOISE, &mode_2Dnoise, _data_FX_MODE_2DNOISE); | |
| 11175 | 3542 | addEffect(FX_MODE_2DFIRENOISE, &mode_2Dfirenoise, _data_FX_MODE_2DFIRENOISE); | |
| 11176 | 3542 | addEffect(FX_MODE_2DSQUAREDSWIRL, &mode_2Dsquaredswirl, _data_FX_MODE_2DSQUAREDSWIRL); | |
| 11177 | |||
| 11178 | //non audio | ||
| 11179 | 3542 | addEffect(FX_MODE_2DDNA, &mode_2Ddna, _data_FX_MODE_2DDNA); | |
| 11180 | 3542 | addEffect(FX_MODE_2DMATRIX, &mode_2Dmatrix, _data_FX_MODE_2DMATRIX); | |
| 11181 | 3542 | addEffect(FX_MODE_2DMETABALLS, &mode_2Dmetaballs, _data_FX_MODE_2DMETABALLS); | |
| 11182 | 3542 | addEffect(FX_MODE_2DFUNKYPLANK, &mode_2DFunkyPlank, _data_FX_MODE_2DFUNKYPLANK); // audio | |
| 11183 | 3542 | addEffect(FX_MODE_2DPULSER, &mode_2DPulser, _data_FX_MODE_2DPULSER); | |
| 11184 | 3542 | addEffect(FX_MODE_2DDRIFT, &mode_2DDrift, _data_FX_MODE_2DDRIFT); | |
| 11185 | 3542 | addEffect(FX_MODE_2DWAVERLY, &mode_2DWaverly, _data_FX_MODE_2DWAVERLY); // audio | |
| 11186 | 3542 | addEffect(FX_MODE_2DSUNRADIATION, &mode_2DSunradiation, _data_FX_MODE_2DSUNRADIATION); | |
| 11187 | 3542 | addEffect(FX_MODE_2DCOLOREDBURSTS, &mode_2DColoredBursts, _data_FX_MODE_2DCOLOREDBURSTS); | |
| 11188 | 3542 | addEffect(FX_MODE_2DJULIA, &mode_2DJulia, _data_FX_MODE_2DJULIA); | |
| 11189 | 3542 | addEffect(FX_MODE_2DGAMEOFLIFE, &mode_2Dgameoflife, _data_FX_MODE_2DGAMEOFLIFE); | |
| 11190 | 3542 | addEffect(FX_MODE_2DTARTAN, &mode_2Dtartan, _data_FX_MODE_2DTARTAN); | |
| 11191 | 3542 | addEffect(FX_MODE_2DPOLARLIGHTS, &mode_2DPolarLights, _data_FX_MODE_2DPOLARLIGHTS); | |
| 11192 | 3542 | addEffect(FX_MODE_2DSWIRL, &mode_2DSwirl, _data_FX_MODE_2DSWIRL); // audio | |
| 11193 | 3542 | addEffect(FX_MODE_2DLISSAJOUS, &mode_2DLissajous, _data_FX_MODE_2DLISSAJOUS); | |
| 11194 | 3542 | addEffect(FX_MODE_2DFRIZZLES, &mode_2DFrizzles, _data_FX_MODE_2DFRIZZLES); | |
| 11195 | 3542 | addEffect(FX_MODE_2DPLASMABALL, &mode_2DPlasmaball, _data_FX_MODE_2DPLASMABALL); | |
| 11196 | 3542 | addEffect(FX_MODE_2DHIPHOTIC, &mode_2DHiphotic, _data_FX_MODE_2DHIPHOTIC); | |
| 11197 | 3542 | addEffect(FX_MODE_2DSINDOTS, &mode_2DSindots, _data_FX_MODE_2DSINDOTS); | |
| 11198 | 3542 | addEffect(FX_MODE_2DDNASPIRAL, &mode_2DDNASpiral, _data_FX_MODE_2DDNASPIRAL); | |
| 11199 | 3542 | addEffect(FX_MODE_2DBLACKHOLE, &mode_2DBlackHole, _data_FX_MODE_2DBLACKHOLE); | |
| 11200 | 3542 | addEffect(FX_MODE_2DSOAP, &mode_2Dsoap, _data_FX_MODE_2DSOAP); | |
| 11201 | 3542 | addEffect(FX_MODE_2DOCTOPUS, &mode_2Doctopus, _data_FX_MODE_2DOCTOPUS); | |
| 11202 | 3542 | addEffect(FX_MODE_2DWAVINGCELL, &mode_2Dwavingcell, _data_FX_MODE_2DWAVINGCELL); | |
| 11203 | 3542 | addEffect(FX_MODE_2DAKEMI, &mode_2DAkemi, _data_FX_MODE_2DAKEMI); // audio | |
| 11204 | |||
| 11205 | #ifndef WLED_DISABLE_PARTICLESYSTEM2D | ||
| 11206 | 3542 | addEffect(FX_MODE_PARTICLEVOLCANO, &mode_particlevolcano, _data_FX_MODE_PARTICLEVOLCANO); | |
| 11207 | 3542 | addEffect(FX_MODE_PARTICLEFIRE, &mode_particlefire, _data_FX_MODE_PARTICLEFIRE); | |
| 11208 | 3542 | addEffect(FX_MODE_PARTICLEFIREWORKS, &mode_particlefireworks, _data_FX_MODE_PARTICLEFIREWORKS); | |
| 11209 | 3542 | addEffect(FX_MODE_PARTICLEVORTEX, &mode_particlevortex, _data_FX_MODE_PARTICLEVORTEX); | |
| 11210 | 3542 | addEffect(FX_MODE_PARTICLEPERLIN, &mode_particleperlin, _data_FX_MODE_PARTICLEPERLIN); | |
| 11211 | 3542 | addEffect(FX_MODE_PARTICLEPIT, &mode_particlepit, _data_FX_MODE_PARTICLEPIT); | |
| 11212 | 3542 | addEffect(FX_MODE_PARTICLEBOX, &mode_particlebox, _data_FX_MODE_PARTICLEBOX); | |
| 11213 | 3542 | addEffect(FX_MODE_PARTICLEATTRACTOR, &mode_particleattractor, _data_FX_MODE_PARTICLEATTRACTOR); // 872 bytes | |
| 11214 | 3542 | addEffect(FX_MODE_PARTICLEIMPACT, &mode_particleimpact, _data_FX_MODE_PARTICLEIMPACT); | |
| 11215 | 3542 | addEffect(FX_MODE_PARTICLEWATERFALL, &mode_particlewaterfall, _data_FX_MODE_PARTICLEWATERFALL); | |
| 11216 | 3542 | addEffect(FX_MODE_PARTICLESPRAY, &mode_particlespray, _data_FX_MODE_PARTICLESPRAY); | |
| 11217 | 3542 | addEffect(FX_MODE_PARTICLESGEQ, &mode_particleGEQ, _data_FX_MODE_PARTICLEGEQ); | |
| 11218 | 3542 | addEffect(FX_MODE_PARTICLECENTERGEQ, &mode_particlecenterGEQ, _data_FX_MODE_PARTICLECIRCULARGEQ); | |
| 11219 | 3542 | addEffect(FX_MODE_PARTICLEGHOSTRIDER, &mode_particleghostrider, _data_FX_MODE_PARTICLEGHOSTRIDER); | |
| 11220 | 3542 | addEffect(FX_MODE_PARTICLEBLOBS, &mode_particleblobs, _data_FX_MODE_PARTICLEBLOBS); | |
| 11221 | 3542 | addEffect(FX_MODE_PARTICLEGALAXY, &mode_particlegalaxy, _data_FX_MODE_PARTICLEGALAXY); | |
| 11222 | #endif // WLED_DISABLE_PARTICLESYSTEM2D | ||
| 11223 | #endif // WLED_DISABLE_2D | ||
| 11224 | |||
| 11225 | #ifndef WLED_DISABLE_PARTICLESYSTEM1D | ||
| 11226 | 3542 | addEffect(FX_MODE_PSDRIP, &mode_particleDrip, _data_FX_MODE_PARTICLEDRIP); | |
| 11227 | 3542 | addEffect(FX_MODE_PSPINBALL, &mode_particlePinball, _data_FX_MODE_PSPINBALL); //potential replacement for: bouncing balls, rollingballs, popcorn | |
| 11228 | 3542 | addEffect(FX_MODE_PSDANCINGSHADOWS, &mode_particleDancingShadows, _data_FX_MODE_PARTICLEDANCINGSHADOWS); | |
| 11229 | 3542 | addEffect(FX_MODE_PSFIREWORKS1D, &mode_particleFireworks1D, _data_FX_MODE_PS_FIREWORKS1D); | |
| 11230 | 3542 | addEffect(FX_MODE_PSSPARKLER, &mode_particleSparkler, _data_FX_MODE_PS_SPARKLER); | |
| 11231 | 3542 | addEffect(FX_MODE_PSHOURGLASS, &mode_particleHourglass, _data_FX_MODE_PS_HOURGLASS); | |
| 11232 | 3542 | addEffect(FX_MODE_PS1DSPRAY, &mode_particle1Dspray, _data_FX_MODE_PS_1DSPRAY); | |
| 11233 | 3542 | addEffect(FX_MODE_PSBALANCE, &mode_particleBalance, _data_FX_MODE_PS_BALANCE); | |
| 11234 | 3542 | addEffect(FX_MODE_PSCHASE, &mode_particleChase, _data_FX_MODE_PS_CHASE); | |
| 11235 | 3542 | addEffect(FX_MODE_PSSTARBURST, &mode_particleStarburst, _data_FX_MODE_PS_STARBURST); | |
| 11236 | 3542 | addEffect(FX_MODE_PS1DGEQ, &mode_particle1DGEQ, _data_FX_MODE_PS_1D_GEQ); | |
| 11237 | 3542 | addEffect(FX_MODE_PSFIRE1D, &mode_particleFire1D, _data_FX_MODE_PS_FIRE1D); | |
| 11238 | 3542 | addEffect(FX_MODE_PS1DSONICSTREAM, &mode_particle1DsonicStream, _data_FX_MODE_PS_SONICSTREAM); | |
| 11239 | 3542 | addEffect(FX_MODE_PS1DSONICBOOM, &mode_particle1DsonicBoom, _data_FX_MODE_PS_SONICBOOM); | |
| 11240 | 3542 | addEffect(FX_MODE_PS1DSPRINGY, &mode_particleSpringy, _data_FX_MODE_PS_SPRINGY); | |
| 11241 | #endif // WLED_DISABLE_PARTICLESYSTEM1D | ||
| 11242 | |||
| 11243 | 3542 | } | |
| 11244 |