@@ -4877,6 +4877,78 @@ uint16_t mode_FlowStripe(void) {
48774877} // mode_FlowStripe()
48784878static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = " Flow Stripe@Hue speed,Effect speed;;!;pal=11" ;
48794879
4880+ /*
4881+ Shimmer effect: moves a gradient with optional modulators across the strip at a given interval, up to 60 seconds
4882+ It can be used as an overlay to other effects or standalone
4883+ by DedeHai (Damian Schneider), based on idea from @Charming-Lime (#4905)
4884+ */
4885+ uint16_t mode_shimmer () {
4886+ if (!SEGENV.allocateData (sizeof (uint32_t ))) { return mode_static (); }
4887+ uint32_t * lastTime = reinterpret_cast <uint32_t *>(SEGENV.data );
4888+
4889+ uint32_t radius = (SEGMENT.custom1 * SEGLEN >> 7 ) + 1 ; // [1, 2*SEGLEN+1] pixels
4890+ uint32_t traversalDistance = (SEGLEN + 2 * radius) << 8 ; // total subpixels to cross, 1 pixel = 256 subpixels
4891+ uint32_t traversalTime = 200 + (255 - SEGMENT.speed ) * 80 ; // [200, 20600] ms
4892+ uint32_t speed = ((traversalDistance << 5 ) / traversalTime); // subpixels/512ms
4893+ int32_t position = static_cast <int32_t >(SEGENV.step ); // current position in subpixels
4894+ uint16_t inputstate = (uint16_t (SEGMENT.intensity ) << 8 ) | uint16_t (SEGMENT.custom1 ); // current user input state
4895+
4896+ // init
4897+ if (SEGENV.call == 0 || inputstate != SEGENV.aux1 ) {
4898+ position = -(radius << 8 );
4899+ SEGENV.aux0 = 0 ; // aux0 is pause timer
4900+ *lastTime = strip.now ;
4901+ SEGENV.aux1 = inputstate; // save user input state
4902+ }
4903+
4904+ if (SEGMENT.speed ) {
4905+ uint32_t deltaTime = (strip.now - *lastTime) & 0x7F ; // clamp to 127ms to avoid overflows. note: speed*deltaTime can still overflow for segments > ~10k pixels
4906+ *lastTime = strip.now ;
4907+
4908+ if (SEGENV.aux0 > 0 ) {
4909+ SEGENV.aux0 = (SEGENV.aux0 > deltaTime) ? SEGENV.aux0 - deltaTime : 0 ;
4910+ } else {
4911+ // calculate movement step and update position
4912+ int32_t step = 1 + ((speed * deltaTime) >> 5 ); // subpixels moved this frame. note >>5 as speed is in subpixels/512ms
4913+ position += step;
4914+ int endposition = (SEGLEN + radius) << 8 ;
4915+ if (position > endposition) {
4916+ SEGENV.aux0 = SEGMENT.intensity * 236 ; // [0, 60180] ms pause
4917+ if (SEGMENT.check3 ) SEGENV.aux0 = hw_random (SEGENV.aux0 + 1000 ); // randomise interval, +1 second to affect low intensity values
4918+ position = -(radius << 8 ); // reset to start position (out of frame)
4919+ }
4920+ SEGENV.step = (uint32_t )position; // save back
4921+ }
4922+
4923+ if (SEGMENT.check2 )
4924+ position = (SEGLEN << 8 ) - position; // invert position (and direction)
4925+ } else {
4926+ position = (SEGLEN << 7 ); // at speed=0, make it static in the center (this enables to use modulators only)
4927+ }
4928+
4929+ for (int i = 0 ; i < SEGLEN; i++) {
4930+ uint32_t dist = abs (position - (i << 8 ));
4931+ if (dist < (radius << 8 )) {
4932+ uint32_t color = SEGMENT.color_from_palette (i * 255 / SEGLEN, false , false , 0 );
4933+ uint8_t blend = dist / radius; // linear gradient note: dist is in subpixels, radius in pixels, result is [0, 255] since dist < radius*256
4934+ if (SEGMENT.custom2 ) {
4935+ uint8_t modVal; // modulation value
4936+ if (SEGMENT.check1 ) {
4937+ modVal = (sin16_t ((i * SEGMENT.custom2 << 6 ) + (strip.now * SEGMENT.custom3 << 5 )) >> 8 ) + 128 ; // sine modulation: regular "Zebra" stripes
4938+ } else {
4939+ modVal = perlin16 ((i * SEGMENT.custom2 << 7 ), strip.now * SEGMENT.custom3 << 5 ) >> 8 ; // perlin noise modulation
4940+ }
4941+ color = color_fade (color, modVal, true ); // dim by modulator value
4942+ }
4943+ SEGMENT.setPixelColor (i, color_blend (color, SEGCOLOR (1 ), blend)); // blend to background color
4944+ } else {
4945+ SEGMENT.setPixelColor (i, SEGCOLOR (1 ));
4946+ }
4947+ }
4948+
4949+ return FRAMETIME;
4950+ }
4951+ 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" ;
48804952
48814953#ifndef WLED_DISABLE_2D
48824954// /////////////////////////////////////////////////////////////////////////////
@@ -10814,6 +10886,7 @@ void WS2812FX::setupEffectData() {
1081410886 addEffect (FX_MODE_FLOWSTRIPE, &mode_FlowStripe, _data_FX_MODE_FLOWSTRIPE);
1081510887 addEffect (FX_MODE_WAVESINS, &mode_wavesins, _data_FX_MODE_WAVESINS);
1081610888 addEffect (FX_MODE_ROCKTAVES, &mode_rocktaves, _data_FX_MODE_ROCKTAVES);
10889+ addEffect (FX_MODE_SHIMMER, &mode_shimmer, _data_FX_MODE_SHIMMER);
1081710890
1081810891 // --- 2D effects ---
1081910892#ifndef WLED_DISABLE_2D
0 commit comments