Skip to content

Commit c9b3d0c

Browse files
DedeHaiblazoncek
authored andcommitted
Adding Shimmer FX (wled#4923)
Sends a shimmer across the strip at defined (or random) intervals Optional brightness modulators: sine or perlin noise Can be used as an overlay to other effects.
1 parent 4f53dcd commit c9b3d0c

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

wled00/FX.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4500,6 +4500,76 @@ uint16_t mode_FlowStripe(void) {
45004500
} // mode_FlowStripe()
45014501
static 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);

wled00/FX.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
256256
#define FX_MODE_BLENDS 115
257257
#define FX_MODE_TV_SIMULATOR 116
258258
//#define FX_MODE_DYNAMIC_SMOOTH 117 // candidate for removal (check3 in dynamic)
259+
#define FX_MODE_SHIMMER 161 // gap fill, non SR 1D effect
260+
259261
// new 0.14 2D effects
260262
#define FX_MODE_2DSPACESHIPS 118 //gap fill
261263
#define FX_MODE_2DCRAZYBEES 119 //gap fill

0 commit comments

Comments
 (0)