diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b5949d00..f189fb76 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7333,7 +7333,7 @@ static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Hea // Distortion waves - ldirko // https://editor.soulmatelights.com/gallery/1089-distorsion-waves -// apated for WLD by @blazoncek +// adapted for WLED by @blazoncek uint16_t mode_2Ddistortionwaves() { if (!strip.isMatrix) return mode_static(); // not a 2D set-up @@ -7384,6 +7384,123 @@ uint16_t mode_2Ddistortionwaves() { } static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2;"; +//Soap +//@Stepko +//Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick +// adapted for WLED by @blazoncek +uint16_t mode_2Dsoap() { + if (!strip.isMatrix) return mode_static(); // not a 2D set-up + + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + + const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped + if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*5)) return mode_static(); //allocation failed + + uint8_t *noise3d = reinterpret_cast(SEGENV.data); + uint32_t *noise32_x = reinterpret_cast(SEGENV.data + dataSize); + uint32_t *noise32_y = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)); + uint32_t *noise32_z = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)*2); + uint32_t *scale32_x = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)*3); + uint32_t *scale32_y = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)*4); + + // init + if (SEGENV.call == 0) { + SEGMENT.setUpLeds(); + *noise32_x = random16(); + *noise32_y = random16(); + *noise32_z = random16(); + *scale32_x = 160000/cols; + *scale32_y = 160000/rows; + for (int i = 0; i < cols; i++) { + int32_t ioffset = *scale32_x * (i - cols / 2); + for (int j = 0; j < rows; j++) { + int32_t joffset = *scale32_y * (j - rows / 2); + uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8; + noise3d[i*cols + j] = scale8(noise3d[i*cols + j], SEGMENT.intensity) + scale8(data, 255 - SEGMENT.intensity); + SEGMENT.setPixelColorXY(i, j, ColorFromPalette(SEGPALETTE,~noise3d[i*cols + j]*3)); + SEGMENT.color_wheel(1); + } + } + } + + uint32_t mov = max(cols,rows)*SEGMENT.speed/4; + *noise32_x += mov; + *noise32_y += mov; + *noise32_z += mov; + + for (int i = 0; i < cols; i++) { + int32_t ioffset = *scale32_x * (i - cols / 2); + for (int j = 0; j < rows; j++) { + int32_t joffset = *scale32_y * (j - rows / 2); + uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8; + noise3d[i*cols + j] = scale8(noise3d[i*cols + j], SEGMENT.intensity) + scale8(data, 255 - SEGMENT.intensity); + } + } + + int zD; + int zF; + int amplitude; + int8_t shiftX = 0; //(SEGMENT.custom1 - 128) / 4; + int8_t shiftY = 0; //(SEGMENT.custom2 - 128) / 4; + CRGB ledsbuff[cols+rows]; + + amplitude = (cols >= 16) ? (cols-8)/8 : 1; + for (int y = 0; y < rows; y++) { + int amount = ((int)noise3d[y] - 128) * 2 * amplitude + 256*shiftX; + int delta = abs(amount) >> 8; + int fraction = abs(amount) & 255; + for (int x = 0; x < cols; x++) { + if (amount < 0) { + zD = x - delta; + zF = zD - 1; + } else { + zD = x + delta; + zF = zD + 1; + } + CRGB PixelA = CRGB::Black; + if ((zD >= 0) && (zD < cols)) PixelA = SEGMENT.getPixelColorXY(zD, y); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[(abs(zD)%cols)*cols + y]*3); + CRGB PixelB = CRGB::Black; + if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[(abs(zF)%cols)*cols + y]*3); + ledsbuff[x] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); // lerp8by8(PixelA, PixelB, fraction ); + } + for (size_t x = 0; x < cols; x++) { + SEGMENT.setPixelColorXY(x, y, ledsbuff[x]); + } + } + + amplitude = (rows >= 16) ? (rows-8)/8 : 1; + for (int x = 0; x < cols; x++) { + int amount = ((int)noise3d[x*cols] - 128) * 2 * amplitude + 256*shiftY; + int delta = abs(amount) >> 8; + int fraction = abs(amount) & 255; + for (size_t y = 0; y < rows; y++) { + if (amount < 0) { + zD = y - delta; + zF = zD - 1; + } else { + zD = y + delta; + zF = zD + 1; + } + CRGB PixelA = CRGB::Black; + if ((zD >= 0) && (zD < rows)) PixelA = SEGMENT.getPixelColorXY(x, zD); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[x*cols + abs(zD)%rows]*3); + CRGB PixelB = CRGB::Black; + if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[x*cols + abs(zF)%rows]*3); + ledsbuff[y] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); + } + for (int y = 0; y < rows; y++) { + SEGMENT.setPixelColorXY(x, y, ledsbuff[y]); + } + } + + return FRAMETIME; +} +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2;"; + #endif // WLED_DISABLE_2D @@ -7617,6 +7734,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_2DSINDOTS, &mode_2DSindots, _data_FX_MODE_2DSINDOTS); addEffect(FX_MODE_2DDNASPIRAL, &mode_2DDNASpiral, _data_FX_MODE_2DDNASPIRAL); addEffect(FX_MODE_2DBLACKHOLE, &mode_2DBlackHole, _data_FX_MODE_2DBLACKHOLE); + addEffect(FX_MODE_2DSOAP, &mode_2Dsoap, _data_FX_MODE_2DSOAP); addEffect(FX_MODE_2DAKEMI, &mode_2DAkemi, _data_FX_MODE_2DAKEMI); // audio #endif // WLED_DISABLE_2D diff --git a/wled00/FX.h b/wled00/FX.h index 07f2aae6..b824cfd4 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -255,6 +255,7 @@ #define FX_MODE_2DSCROLLTEXT 122 //gap fill #define FX_MODE_2DDRIFTROSE 123 //gap fill #define FX_MODE_2DDISTORTIONWAVES 124 +#define FX_MODE_2DSOAP 125 // WLED-SR effects (SR compatible IDs !!!) #define FX_MODE_PIXELS 128 diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 95298c72..ee907125 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -228,6 +228,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { case FX_MODE_GLITTER : pal = 11; break; // rainbow colors case FX_MODE_SUNRISE : pal = 35; break; // heat palette case FX_MODE_RAILWAY : pal = 3; break; // prim + sec + case FX_MODE_2DSOAP : pal = 11; break; // rainbow colors } switch (pal) { case 0: //default palette. Exceptions for specific effects above