Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4875,6 +4875,78 @@ uint16_t mode_FlowStripe(void) {
} // mode_FlowStripe()
static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Effect speed;;!;pal=11";

/*
Shimmer effect: moves a gradient with optional modulators across the strip at a given interval, up to 60 seconds
It can be used as an overlay to other effects or standalone
by DedeHai (Damian Schneider), based on idea from @Charming-Lime (#4905)
*/
uint16_t mode_shimmer() {
if(!SEGENV.allocateData(sizeof(uint32_t))) { return mode_static(); }
uint32_t* lastTime = reinterpret_cast<uint32_t*>(SEGENV.data);

uint32_t radius = (SEGMENT.custom1 * SEGLEN >> 7) + 1; // [1, 2*SEGLEN+1] pixels
uint32_t traversalDistance = (SEGLEN + 2 * radius) << 8; // total subpixels to cross, 1 pixel = 256 subpixels
uint32_t traversalTime = 200 + (255 - SEGMENT.speed) * 80; // [200, 20600] ms
uint32_t speed = ((traversalDistance << 5) / traversalTime); // subpixels/512ms
int32_t position = static_cast<int32_t>(SEGENV.step); // current position in subpixels
uint16_t inputstate = (uint16_t(SEGMENT.intensity) << 8) | uint16_t(SEGMENT.custom1); // current user input state

// init
if (SEGENV.call == 0 || inputstate != SEGENV.aux1) {
position = -(radius << 8);
SEGENV.aux0 = 0; // aux0 is pause timer
*lastTime = strip.now;
SEGENV.aux1 = inputstate; // save user input state
}

if(SEGMENT.speed) {
uint32_t deltaTime = (strip.now - *lastTime) & 0x7F; // clamp to 127ms to avoid overflows. note: speed*deltaTime can still overflow for segments > ~10k pixels
*lastTime = strip.now;

if (SEGENV.aux0 > 0) {
SEGENV.aux0 = (SEGENV.aux0 > deltaTime) ? SEGENV.aux0 - deltaTime : 0;
} else {
// calculate movement step and update position
int32_t step = 1 + ((speed * deltaTime) >> 5); // subpixels moved this frame. note >>5 as speed is in subpixels/512ms
position += step;
int endposition = (SEGLEN + radius) << 8;
if (position > endposition) {
SEGENV.aux0 = SEGMENT.intensity * 236; // [0, 60180] ms pause
if(SEGMENT.check3) SEGENV.aux0 = hw_random(SEGENV.aux0 + 1000); // randomise interval, +1 second to affect low intensity values
position = -(radius << 8); // reset to start position (out of frame)
}
SEGENV.step = (uint32_t)position; // save back
}

if (SEGMENT.check2)
position = (SEGLEN << 8) - position; // invert position (and direction)
} else {
position = (SEGLEN << 7); // at speed=0, make it static in the center (this enables to use modulators only)
}

for (int i = 0; i < SEGLEN; i++) {
uint32_t dist = abs(position - (i << 8));
if (dist < (radius << 8)) {
uint32_t color = SEGMENT.color_from_palette(i * 255 / SEGLEN, false, false, 0);
uint8_t blend = dist / radius; // linear gradient note: dist is in subpixels, radius in pixels, result is [0, 255] since dist < radius*256
if (SEGMENT.custom2) {
uint8_t modVal; // modulation value
if (SEGMENT.check1) {
modVal = (sin16_t((i * SEGMENT.custom2 << 6) + (strip.now * SEGMENT.custom3 << 5)) >> 8) + 128; // sine modulation: regular "Zebra" stripes
} else {
modVal = perlin16((i * SEGMENT.custom2 << 7), strip.now * SEGMENT.custom3 << 5) >> 8; // perlin noise modulation
}
color = color_fade(color, modVal, true); // dim by modulator value
}
SEGMENT.setPixelColor(i, color_blend(color, SEGCOLOR(1), blend)); // blend to background color
} else {
SEGMENT.setPixelColor(i, SEGCOLOR(1));
}
}

return FRAMETIME;
}
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";

#ifndef WLED_DISABLE_2D
///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -10805,6 +10877,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_FLOWSTRIPE, &mode_FlowStripe, _data_FX_MODE_FLOWSTRIPE);
addEffect(FX_MODE_WAVESINS, &mode_wavesins, _data_FX_MODE_WAVESINS);
addEffect(FX_MODE_ROCKTAVES, &mode_rocktaves, _data_FX_MODE_ROCKTAVES);
addEffect(FX_MODE_SHIMMER, &mode_shimmer, _data_FX_MODE_SHIMMER);

// --- 2D effects ---
#ifndef WLED_DISABLE_2D
Expand Down
1 change: 1 addition & 0 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define FX_MODE_DJLIGHT 159
#define FX_MODE_2DFUNKYPLANK 160
//#define FX_MODE_2DCENTERBARS 161
#define FX_MODE_SHIMMER 161 // gap fill, non SR 1D effect
#define FX_MODE_2DPULSER 162
#define FX_MODE_BLURZ 163
#define FX_MODE_2DDRIFT 164
Expand Down