@@ -4500,6 +4500,76 @@ uint16_t mode_FlowStripe(void) {
45004500} // mode_FlowStripe()
45014501static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = " Flow Stripe@Hue speed,Effect speed;;!;1" ;
45024502
4503+ /*
4504+ Shimmer effect: moves a gradient with optional modulators across the strip at a given interval, up to 60 seconds
4505+ It can be used as an overlay to other effects or standalone
4506+ by DedeHai (Damian Schneider), based on idea from @Charming-Lime (#4905)
4507+ */
4508+ uint16_t mode_shimmer () {
4509+ if (!SEGENV.allocateData (sizeof (uint32_t ))) { return mode_static (); }
4510+ uint32_t * lastTime = reinterpret_cast <uint32_t *>(SEGENV.data );
4511+
4512+ uint32_t radius = (SEGMENT.custom1 * SEGLEN >> 7 ) + 1 ; // [1, 2*SEGLEN+1] pixels
4513+ uint32_t traversalDistance = (SEGLEN + 2 * radius) << 8 ; // total subpixels to cross, 1 pixel = 256 subpixels
4514+ uint32_t traversalTime = 200 + (255 - SEGMENT.speed ) * 80 ; // [200, 20600] ms
4515+ uint32_t speed = ((traversalDistance << 5 ) / traversalTime); // subpixels/512ms
4516+ int32_t position = static_cast <int32_t >(SEGENV.step ); // current position in subpixels
4517+ uint16_t inputstate = (uint16_t (SEGMENT.intensity ) << 8 ) | uint16_t (SEGMENT.custom1 ); // current user input state
4518+
4519+ // init
4520+ if (SEGENV.call == 0 || inputstate != SEGENV.aux1 ) {
4521+ position = -(radius << 8 );
4522+ SEGENV.aux0 = 0 ; // aux0 is pause timer
4523+ *lastTime = strip.now ;
4524+ SEGENV.aux1 = inputstate; // save user input state
4525+ }
4526+
4527+ if (SEGMENT.speed ) {
4528+ uint32_t deltaTime = (strip.now - *lastTime) & 0x7F ; // clamp to 127ms to avoid overflows. note: speed*deltaTime can still overflow for segments > ~10k pixels
4529+ *lastTime = strip.now ;
4530+
4531+ if (SEGENV.aux0 > 0 ) {
4532+ SEGENV.aux0 = (SEGENV.aux0 > deltaTime) ? SEGENV.aux0 - deltaTime : 0 ;
4533+ } else {
4534+ // calculate movement step and update position
4535+ int32_t step = 1 + ((speed * deltaTime) >> 5 ); // subpixels moved this frame. note >>5 as speed is in subpixels/512ms
4536+ position += step;
4537+ int endposition = (SEGLEN + radius) << 8 ;
4538+ if (position > endposition) {
4539+ SEGENV.aux0 = SEGMENT.intensity * 236 ; // [0, 60180] ms pause
4540+ if (SEGMENT.check3 ) SEGENV.aux0 = hw_random (SEGENV.aux0 + 1000 ); // randomise interval, +1 second to affect low intensity values
4541+ position = -(radius << 8 ); // reset to start position (out of frame)
4542+ }
4543+ SEGENV.step = (uint32_t )position; // save back
4544+ }
4545+ if (SEGMENT.check2 ) position = (SEGLEN << 8 ) - position; // invert position (and direction)
4546+ } else {
4547+ position = (SEGLEN << 7 ); // at speed=0, make it static in the center (this enables to use modulators only)
4548+ }
4549+
4550+ for (int i = 0 ; i < SEGLEN; i++) {
4551+ uint32_t dist = abs (position - (i << 8 ));
4552+ if (dist < (radius << 8 )) {
4553+ CRGBA color = SEGMENT.color_from_palette (i * 255 / SEGLEN, false , false , 0 );
4554+ uint8_t blend = dist / radius; // linear gradient note: dist is in subpixels, radius in pixels, result is [0, 255] since dist < radius*256
4555+ if (SEGMENT.custom2 ) {
4556+ uint8_t modVal; // modulation value
4557+ if (SEGMENT.check1 ) {
4558+ modVal = (sin16_t ((i * SEGMENT.custom2 << 6 ) + (strip.now * SEGMENT.custom3 << 5 )) >> 8 ) + 128 ; // sine modulation: regular "Zebra" stripes
4559+ } else {
4560+ modVal = perlin16 ((i * SEGMENT.custom2 << 7 ), strip.now * SEGMENT.custom3 << 5 ) >> 8 ; // perlin noise modulation
4561+ }
4562+ color.nscale8_video (modVal); // dim by modulator value
4563+ }
4564+ SEGMENT.setPixelColor (i, color.nblend (SEGCOLOR (1 ), blend)); // blend to background color
4565+ } else {
4566+ SEGMENT.setPixelColor (i, SEGCOLOR (1 )); // might be better to check if SEGCOLOR(1) != BLACK to allow (simpler) layering
4567+ }
4568+ }
4569+
4570+ return FRAMETIME;
4571+ }
4572+ static const char _data_FX_MODE_SHIMMER[] PROGMEM = " Shimmer@Speed,Interval,Size,Granular,Flow,Zebra,Reverse,Sporadic;Fx,Bg;!;1;pal=15,sx=220,ix=10,c2=0,c3=0" ;
45034573
45044574#ifndef WLED_DISABLE_2D
45054575// /////////////////////////////////////////////////////////////////////////////
@@ -8882,6 +8952,7 @@ void WS2812FX::setupEffectData() {
88828952 addEffect (FX_MODE_PERLINMOVE, &mode_perlinmove, _data_FX_MODE_PERLINMOVE);
88838953 addEffect (FX_MODE_FLOWSTRIPE, &mode_FlowStripe, _data_FX_MODE_FLOWSTRIPE);
88848954 addEffect (FX_MODE_WAVESINS, &mode_wavesins, _data_FX_MODE_WAVESINS);
8955+ addEffect (FX_MODE_SHIMMER, &mode_shimmer, _data_FX_MODE_SHIMMER);
88858956 #ifndef WLED_DISABLE_PARTICLESYSTEM1D
88868957 addEffect (FX_MODE_PS1DDRIP, &mode_particleDrip, _data_FX_MODE_PS1DDRIP);
88878958 addEffect (FX_MODE_PS1DPINBALL, &mode_particlePinball, _data_FX_MODE_PS1DPINBALL);
0 commit comments