From 2fe809f15acd0eb75f65bc59bb9d30c7ce836fb4 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 7 Feb 2025 09:46:06 +0100 Subject: [PATCH 1/8] consolidated double loops into function - saves ~500 bytes of flash - slight speed improvement --- wled00/FX.cpp | 78 +++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 216cd7a3f..51726215b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7468,7 +7468,36 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //Soap //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick -// adapted for WLED by @blazoncek +// adapted for WLED by @blazoncek, optimization by @dedehai +void soapProcessPixels(bool isRow, int size1, int size2, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { + for (int i = 0; i < size1; i++) { + int amount = ((int)noise3d[isRow ? XY(0, i) : XY(i, 0)] - 128) * 2 * amplitude + 256 * shift; + int delta = abs(amount) >> 8; + int fraction = abs(amount) & 255; + for (int j = 0; j < size2; j++) { + int zD, zF; + if (amount < 0) { + zD = j - delta; + zF = zD - 1; + } else { + zD = j + delta; + zF = zD + 1; + } + CRGB PixelA = CRGB::Black; + if ((zD >= 0) && (zD < size2)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); + CRGB PixelB = CRGB::Black; + if ((zF >= 0) && (zF < size2)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); + ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); + } + for (int j = 0; j < size2; j++) { + if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); + else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); + } + } +} + uint16_t mode_2Dsoap() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up @@ -7526,52 +7555,9 @@ uint16_t mode_2Dsoap() { CRGB ledsbuff[MAX(cols,rows)]; amplitude = (cols >= 16) ? (cols-8)/8 : 1; - for (int y = 0; y < rows; y++) { - int amount = ((int)noise3d[XY(0,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[XY(abs(zD),y)]*3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3); - ledsbuff[x] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); - } - for (int x = 0; x < cols; x++) SEGMENT.setPixelColorXY(x, y, ledsbuff[x]); - } - + soapProcessPixels(true, rows, cols, noise3d, amplitude, shiftX, ledsbuff); // rows 1166192 vs 1165634 amplitude = (rows >= 16) ? (rows-8)/8 : 1; - for (int x = 0; x < cols; x++) { - int amount = ((int)noise3d[XY(x,0)] - 128) * 2 * amplitude + 256*shiftY; - int delta = abs(amount) >> 8; - int fraction = abs(amount) & 255; - for (int 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[XY(x,abs(zD))]*3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*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]); - } + soapProcessPixels(false, cols, rows, noise3d, amplitude, shiftY, ledsbuff); // cols return FRAMETIME; } From b9ceacb43d8cd019cbe3a343dc8250fcaa069a46 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 7 Feb 2025 11:14:13 +0100 Subject: [PATCH 2/8] more optimizations and better readability --- wled00/FX.cpp | 62 ++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 51726215b..50406aa91 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7469,33 +7469,39 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick // adapted for WLED by @blazoncek, optimization by @dedehai -void soapProcessPixels(bool isRow, int size1, int size2, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { - for (int i = 0; i < size1; i++) { - int amount = ((int)noise3d[isRow ? XY(0, i) : XY(i, 0)] - 128) * 2 * amplitude + 256 * shift; - int delta = abs(amount) >> 8; - int fraction = abs(amount) & 255; - for (int j = 0; j < size2; j++) { - int zD, zF; - if (amount < 0) { - zD = j - delta; - zF = zD - 1; - } else { - zD = j + delta; - zF = zD + 1; - } - CRGB PixelA = CRGB::Black; - if ((zD >= 0) && (zD < size2)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < size2)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); - ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); - } - for (int j = 0; j < size2; j++) { - if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); - else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); - } +void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { //1153477-1152873 + const int cols = SEG_W; + const int rows = SEG_H; + int rowcol, colrow; + rowcol = isRow ? rows : cols; + colrow = isRow ? cols : rows; + + for (int i = 0; i < rowcol; i++) { + int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * 2 * amplitude + 256 * shift; + int delta = abs(amount) >> 8; + int fraction = abs(amount) & 255; + for (int j = 0; j < colrow; j++) { + int zD, zF; + if (amount < 0) { + zD = j - delta; + zF = zD - 1; + } else { + zD = j + delta; + zF = zD + 1; + } + CRGB PixelA = CRGB::Black; + if ((zD >= 0) && (zD < colrow)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zD)%cols) + i*cols : i + (abs(zD)%rows)*cols] * 3); + CRGB PixelB = CRGB::Black; + if ((zF >= 0) && (zF < colrow)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zF)%cols) + i*cols : i + (abs(zF)%rows)*cols] * 3); + ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); } + for (int j = 0; j < colrow; j++) { + if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); + else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); + } + } } uint16_t mode_2Dsoap() { @@ -7555,9 +7561,9 @@ uint16_t mode_2Dsoap() { CRGB ledsbuff[MAX(cols,rows)]; amplitude = (cols >= 16) ? (cols-8)/8 : 1; - soapProcessPixels(true, rows, cols, noise3d, amplitude, shiftX, ledsbuff); // rows 1166192 vs 1165634 + soapProcessPixels(true, noise3d, amplitude, shiftX, ledsbuff); // rows amplitude = (rows >= 16) ? (rows-8)/8 : 1; - soapProcessPixels(false, cols, rows, noise3d, amplitude, shiftY, ledsbuff); // cols + soapProcessPixels(false, noise3d, amplitude, shiftY, ledsbuff); // cols return FRAMETIME; } From d92e60ee5f9e5dbf96d4952e3b50a863ff9f17ef Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 7 Feb 2025 15:23:44 +0100 Subject: [PATCH 3/8] adding XY() lambda function back in - slight increase in code size, speed is the same but better readability. --- wled00/FX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 50406aa91..9066e960d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7472,6 +7472,7 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { //1153477-1152873 const int cols = SEG_W; const int rows = SEG_H; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; int rowcol, colrow; rowcol = isRow ? rows : cols; colrow = isRow ? cols : rows; @@ -7491,10 +7492,10 @@ void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, C } CRGB PixelA = CRGB::Black; if ((zD >= 0) && (zD < colrow)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zD)%cols) + i*cols : i + (abs(zD)%rows)*cols] * 3); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); CRGB PixelB = CRGB::Black; if ((zF >= 0) && (zF < colrow)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zF)%cols) + i*cols : i + (abs(zF)%rows)*cols] * 3); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); } for (int j = 0; j < colrow; j++) { From 8e7d6d5dad09a326b09e2334127b6863c1b61857 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 8 Feb 2025 10:06:29 +0100 Subject: [PATCH 4/8] cleanup and added Density slider - moved local variables into function - made coordinates an array - amplitude can now be changed by user (default setting is a slight increase to original which cannot be avoided without complicated logic or default slider setting) --- wled00/FX.cpp | 49 ++++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9066e960d..d4288676c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7469,16 +7469,18 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick // adapted for WLED by @blazoncek, optimization by @dedehai -void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { //1153477-1152873 +void soapProcessPixels(bool isRow, uint8_t* noise3d) { const int cols = SEG_W; const int rows = SEG_H; const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; - int rowcol, colrow; - rowcol = isRow ? rows : cols; - colrow = isRow ? cols : rows; + CRGB ledsbuff[MAX(cols,rows)]; + const int rowcol = isRow ? rows : cols; + const int colrow = isRow ? cols : rows; + int amplitude = isRow ? (cols-8) >> 3 : (rows-8) >> 3; + amplitude = 2 * max(1, amplitude * (1 + SEGMENT.custom1) >> 6); for (int i = 0; i < rowcol; i++) { - int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * 2 * amplitude + 256 * shift; + int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * amplitude; int delta = abs(amount) >> 8; int fraction = abs(amount) & 255; for (int j = 0; j < colrow; j++) { @@ -7515,31 +7517,25 @@ uint16_t mode_2Dsoap() { const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) 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); + uint8_t *noise3d = reinterpret_cast(SEGENV.data); + uint32_t *noisecoord = reinterpret_cast(SEGENV.data + dataSize); // x, y, z coordinates const uint32_t scale32_x = 160000U/cols; const uint32_t scale32_y = 160000U/rows; const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2; const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes - // init - if (SEGENV.call == 0) { - *noise32_x = hw_random(); - *noise32_y = hw_random(); - *noise32_z = hw_random(); - } else { - *noise32_x += mov; - *noise32_y += mov; - *noise32_z += mov; + for (int i = 0; i < 3; i++) { + if (SEGENV.call == 0) + noisecoord[i] = hw_random(); // init + else + noisecoord[i] += 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; + uint8_t data = inoise16(noisecoord[0] + ioffset, noisecoord[1] + joffset, noisecoord[2]) >> 8; noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness); } } @@ -7554,21 +7550,12 @@ uint16_t mode_2Dsoap() { } } - int zD; - int zF; - int amplitude; - int shiftX = 0; //(SEGMENT.custom1 - 128) / 4; - int shiftY = 0; //(SEGMENT.custom2 - 128) / 4; - CRGB ledsbuff[MAX(cols,rows)]; - - amplitude = (cols >= 16) ? (cols-8)/8 : 1; - soapProcessPixels(true, noise3d, amplitude, shiftX, ledsbuff); // rows - amplitude = (rows >= 16) ? (rows-8)/8 : 1; - soapProcessPixels(false, noise3d, amplitude, shiftY, ledsbuff); // cols + soapProcessPixels(true, noise3d); // rows + soapProcessPixels(false, noise3d); // cols return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2;pal=11"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 From 2473065b986ceea25eda5139a6920b5e584a5fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 9 Feb 2025 18:23:53 +0100 Subject: [PATCH 5/8] Soap gap bugfix & aditional size tuning --- wled00/FX.cpp | 86 +++++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d4288676c..44366bbc7 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7469,40 +7469,54 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick // adapted for WLED by @blazoncek, optimization by @dedehai -void soapProcessPixels(bool isRow, uint8_t* noise3d) { - const int cols = SEG_W; - const int rows = SEG_H; - const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; - CRGB ledsbuff[MAX(cols,rows)]; - const int rowcol = isRow ? rows : cols; - const int colrow = isRow ? cols : rows; - int amplitude = isRow ? (cols-8) >> 3 : (rows-8) >> 3; - amplitude = 2 * max(1, amplitude * (1 + SEGMENT.custom1) >> 6); +static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { + const int cols = SEG_W; + const int rows = SEG_H; + const auto XY = [&](int x, int y) { return x + y * cols; }; + const auto abs = [](int x) { return x<0 ? -x : x; }; + const int tRC = isRow ? rows : cols; // transpose if isRow + const int tCR = isRow ? cols : rows; // transpose if isRow + const int amplitude = 2 * ((tCR >= 16) ? (tCR-8) : 8) / (1 + ((255 - SEGMENT.custom1) >> 5)); + const int shift = 0; //(128 - SEGMENT.custom2)*2; - for (int i = 0; i < rowcol; i++) { - int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * amplitude; - int delta = abs(amount) >> 8; + CRGB ledsbuff[tCR]; + + for (int i = 0; i < tRC; i++) { + int amount = ((int)noise3d[isRow ? i*cols : i] - 128) * amplitude + shift; // use first row/column: XY(0,i)/XY(i,0) + int delta = abs(amount) >> 8; int fraction = abs(amount) & 255; - for (int j = 0; j < colrow; j++) { + for (int j = 0; j < tCR; j++) { int zD, zF; if (amount < 0) { - zD = j - delta; - zF = zD - 1; + zD = j - delta; + zF = zD - 1; } else { - zD = j + delta; - zF = zD + 1; + zD = j + delta; + zF = zD + 1; } - CRGB PixelA = CRGB::Black; - if ((zD >= 0) && (zD < colrow)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < colrow)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); + int yA = abs(zD); + int yB = abs(zF); + int xA = i; + int xB = i; + if (isRow) { + std::swap(xA,yA); + std::swap(xB,yB); + } + const int indxA = XY(xA,yA); + const int indxB = XY(xB,yB); + CRGB PixelA; + CRGB PixelB; + if ((zD >= 0) && (zD < tCR)) PixelA = pixels[indxA]; + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[indxA]*3); + if ((zF >= 0) && (zF < tCR)) PixelB = pixels[indxB]; + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[indxB]*3); ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); } - for (int j = 0; j < colrow; j++) { - if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); - else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); + for (int j = 0; j < tCR; j++) { + CRGB c = ledsbuff[j]; + if (isRow) std::swap(j,i); + SEGMENT.setPixelColorXY(i, j, pixels[XY(i,j)] = c); + if (isRow) std::swap(j,i); } } } @@ -7512,24 +7526,22 @@ uint16_t mode_2Dsoap() { const int cols = SEG_W; const int rows = SEG_H; - const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; + const auto XY = [&](int x, int y) { return x + y * cols; }; - const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped + const size_t segSize = SEGMENT.width() * SEGMENT.height(); // prevent reallocation if mirrored or grouped + const size_t dataSize = segSize * (sizeof(uint8_t) + sizeof(CRGB)); // pixels and noise if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed uint8_t *noise3d = reinterpret_cast(SEGENV.data); + CRGB *pixels = reinterpret_cast(SEGENV.data + segSize * sizeof(uint8_t)); uint32_t *noisecoord = reinterpret_cast(SEGENV.data + dataSize); // x, y, z coordinates const uint32_t scale32_x = 160000U/cols; const uint32_t scale32_y = 160000U/rows; const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2; const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes - for (int i = 0; i < 3; i++) { - if (SEGENV.call == 0) - noisecoord[i] = hw_random(); // init - else - noisecoord[i] += mov; - } + if (SEGENV.call == 0) for (int i = 0; i < 3; i++) noisecoord[i] = hw_random(); // init + else for (int i = 0; i < 3; i++) noisecoord[i] += mov; for (int i = 0; i < cols; i++) { int32_t ioffset = scale32_x * (i - cols / 2); @@ -7550,12 +7562,12 @@ uint16_t mode_2Dsoap() { } } - soapProcessPixels(true, noise3d); // rows - soapProcessPixels(false, noise3d); // cols + soapPixels(true, noise3d, pixels); // rows + soapPixels(false, noise3d, pixels); // cols return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11,c1=0"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 From 2cc73660bfb09cc851a8529b53c30a4343b01165 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 10 Feb 2025 08:30:36 +0100 Subject: [PATCH 6/8] bugfix (XY needs the modulo for zF/zD), updated amplitude for better range --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 44366bbc7..26b7779de 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7472,11 +7472,11 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { const int cols = SEG_W; const int rows = SEG_H; - const auto XY = [&](int x, int y) { return x + y * cols; }; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; const auto abs = [](int x) { return x<0 ? -x : x; }; const int tRC = isRow ? rows : cols; // transpose if isRow const int tCR = isRow ? cols : rows; // transpose if isRow - const int amplitude = 2 * ((tCR >= 16) ? (tCR-8) : 8) / (1 + ((255 - SEGMENT.custom1) >> 5)); + const int amplitude = max(1, (tCR - 8) >> 3) * (1 + (SEGMENT.custom1 >> 5)); const int shift = 0; //(128 - SEGMENT.custom2)*2; CRGB ledsbuff[tCR]; From bdec873fed0617ffaf3271c36a396cee1d4b505b Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 10 Feb 2025 08:42:22 +0100 Subject: [PATCH 7/8] removed slider default --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 26b7779de..82fc99960 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7567,7 +7567,7 @@ uint16_t mode_2Dsoap() { return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11,c1=0"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 From aba736cb965f9dde78780883dd6d1e533e8e1f5d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 10 Feb 2025 20:26:34 +0100 Subject: [PATCH 8/8] moved modulo --- wled00/FX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 82fc99960..95cf3a7ee 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7472,7 +7472,7 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { const int cols = SEG_W; const int rows = SEG_H; - const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; + const auto XY = [&](int x, int y) { return x + y * cols; }; const auto abs = [](int x) { return x<0 ? -x : x; }; const int tRC = isRow ? rows : cols; // transpose if isRow const int tCR = isRow ? cols : rows; // transpose if isRow @@ -7494,8 +7494,8 @@ static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { zD = j + delta; zF = zD + 1; } - int yA = abs(zD); - int yB = abs(zF); + int yA = abs(zD)%tCR; + int yB = abs(zF)%tCR; int xA = i; int xB = i; if (isRow) {