@@ -7467,42 +7467,86 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@
7467
7467
// Soap
7468
7468
// @Stepko
7469
7469
// Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick
7470
- // adapted for WLED by @blazoncek
7470
+ // adapted for WLED by @blazoncek, optimization by @dedehai
7471
+ static void soapPixels (bool isRow, uint8_t *noise3d, CRGB *pixels) {
7472
+ const int cols = SEG_W;
7473
+ const int rows = SEG_H;
7474
+ const auto XY = [&](int x, int y) { return x + y * cols; };
7475
+ const auto abs = [](int x) { return x<0 ? -x : x; };
7476
+ const int tRC = isRow ? rows : cols; // transpose if isRow
7477
+ const int tCR = isRow ? cols : rows; // transpose if isRow
7478
+ const int amplitude = max (1 , (tCR - 8 ) >> 3 ) * (1 + (SEGMENT.custom1 >> 5 ));
7479
+ const int shift = 0 ; // (128 - SEGMENT.custom2)*2;
7480
+
7481
+ CRGB ledsbuff[tCR];
7482
+
7483
+ for (int i = 0 ; i < tRC; i++) {
7484
+ int amount = ((int )noise3d[isRow ? i*cols : i] - 128 ) * amplitude + shift; // use first row/column: XY(0,i)/XY(i,0)
7485
+ int delta = abs (amount) >> 8 ;
7486
+ int fraction = abs (amount) & 255 ;
7487
+ for (int j = 0 ; j < tCR; j++) {
7488
+ int zD, zF;
7489
+ if (amount < 0 ) {
7490
+ zD = j - delta;
7491
+ zF = zD - 1 ;
7492
+ } else {
7493
+ zD = j + delta;
7494
+ zF = zD + 1 ;
7495
+ }
7496
+ int yA = abs (zD)%tCR;
7497
+ int yB = abs (zF)%tCR;
7498
+ int xA = i;
7499
+ int xB = i;
7500
+ if (isRow) {
7501
+ std::swap (xA,yA);
7502
+ std::swap (xB,yB);
7503
+ }
7504
+ const int indxA = XY (xA,yA);
7505
+ const int indxB = XY (xB,yB);
7506
+ CRGB PixelA;
7507
+ CRGB PixelB;
7508
+ if ((zD >= 0 ) && (zD < tCR)) PixelA = pixels[indxA];
7509
+ else PixelA = ColorFromPalette (SEGPALETTE, ~noise3d[indxA]*3 );
7510
+ if ((zF >= 0 ) && (zF < tCR)) PixelB = pixels[indxB];
7511
+ else PixelB = ColorFromPalette (SEGPALETTE, ~noise3d[indxB]*3 );
7512
+ ledsbuff[j] = (PixelA.nscale8 (ease8InOutApprox (255 - fraction))) + (PixelB.nscale8 (ease8InOutApprox (fraction)));
7513
+ }
7514
+ for (int j = 0 ; j < tCR; j++) {
7515
+ CRGB c = ledsbuff[j];
7516
+ if (isRow) std::swap (j,i);
7517
+ SEGMENT.setPixelColorXY (i, j, pixels[XY (i,j)] = c);
7518
+ if (isRow) std::swap (j,i);
7519
+ }
7520
+ }
7521
+ }
7522
+
7471
7523
uint16_t mode_2Dsoap () {
7472
7524
if (!strip.isMatrix || !SEGMENT.is2D ()) return mode_static (); // not a 2D set-up
7473
7525
7474
7526
const int cols = SEG_W;
7475
7527
const int rows = SEG_H;
7476
- const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; };
7528
+ const auto XY = [&](int x, int y) { return x + y * cols; };
7477
7529
7478
- const size_t dataSize = SEGMENT.width () * SEGMENT.height () * sizeof (uint8_t ); // prevent reallocation if mirrored or grouped
7530
+ const size_t segSize = SEGMENT.width () * SEGMENT.height (); // prevent reallocation if mirrored or grouped
7531
+ const size_t dataSize = segSize * (sizeof (uint8_t ) + sizeof (CRGB)); // pixels and noise
7479
7532
if (!SEGENV.allocateData (dataSize + sizeof (uint32_t )*3 )) return mode_static (); // allocation failed
7480
7533
7481
- uint8_t *noise3d = reinterpret_cast <uint8_t *>(SEGENV.data );
7482
- uint32_t *noise32_x = reinterpret_cast <uint32_t *>(SEGENV.data + dataSize);
7483
- uint32_t *noise32_y = reinterpret_cast <uint32_t *>(SEGENV.data + dataSize + sizeof (uint32_t ));
7484
- uint32_t *noise32_z = reinterpret_cast <uint32_t *>(SEGENV.data + dataSize + sizeof (uint32_t )*2 );
7534
+ uint8_t *noise3d = reinterpret_cast <uint8_t *>(SEGENV.data );
7535
+ CRGB *pixels = reinterpret_cast <CRGB*>(SEGENV.data + segSize * sizeof (uint8_t ));
7536
+ uint32_t *noisecoord = reinterpret_cast <uint32_t *>(SEGENV.data + dataSize); // x, y, z coordinates
7485
7537
const uint32_t scale32_x = 160000U /cols;
7486
7538
const uint32_t scale32_y = 160000U /rows;
7487
7539
const uint32_t mov = MIN (cols,rows)*(SEGMENT.speed +2 )/2 ;
7488
7540
const uint8_t smoothness = MIN (250 ,SEGMENT.intensity ); // limit as >250 produces very little changes
7489
7541
7490
- // init
7491
- if (SEGENV.call == 0 ) {
7492
- *noise32_x = hw_random ();
7493
- *noise32_y = hw_random ();
7494
- *noise32_z = hw_random ();
7495
- } else {
7496
- *noise32_x += mov;
7497
- *noise32_y += mov;
7498
- *noise32_z += mov;
7499
- }
7542
+ if (SEGENV.call == 0 ) for (int i = 0 ; i < 3 ; i++) noisecoord[i] = hw_random (); // init
7543
+ else for (int i = 0 ; i < 3 ; i++) noisecoord[i] += mov;
7500
7544
7501
7545
for (int i = 0 ; i < cols; i++) {
7502
7546
int32_t ioffset = scale32_x * (i - cols / 2 );
7503
7547
for (int j = 0 ; j < rows; j++) {
7504
7548
int32_t joffset = scale32_y * (j - rows / 2 );
7505
- uint8_t data = inoise16 (*noise32_x + ioffset, *noise32_y + joffset, *noise32_z ) >> 8 ;
7549
+ uint8_t data = inoise16 (noisecoord[ 0 ] + ioffset, noisecoord[ 1 ] + joffset, noisecoord[ 2 ] ) >> 8 ;
7506
7550
noise3d[XY (i,j)] = scale8 (noise3d[XY (i,j)], smoothness) + scale8 (data, 255 - smoothness);
7507
7551
}
7508
7552
}
@@ -7517,64 +7561,12 @@ uint16_t mode_2Dsoap() {
7517
7561
}
7518
7562
}
7519
7563
7520
- int zD;
7521
- int zF;
7522
- int amplitude;
7523
- int shiftX = 0 ; // (SEGMENT.custom1 - 128) / 4;
7524
- int shiftY = 0 ; // (SEGMENT.custom2 - 128) / 4;
7525
- CRGB ledsbuff[MAX (cols,rows)];
7526
-
7527
- amplitude = (cols >= 16 ) ? (cols-8 )/8 : 1 ;
7528
- for (int y = 0 ; y < rows; y++) {
7529
- int amount = ((int )noise3d[XY (0 ,y)] - 128 ) * 2 * amplitude + 256 *shiftX;
7530
- int delta = abs (amount) >> 8 ;
7531
- int fraction = abs (amount) & 255 ;
7532
- for (int x = 0 ; x < cols; x++) {
7533
- if (amount < 0 ) {
7534
- zD = x - delta;
7535
- zF = zD - 1 ;
7536
- } else {
7537
- zD = x + delta;
7538
- zF = zD + 1 ;
7539
- }
7540
- CRGB PixelA = CRGB::Black;
7541
- if ((zD >= 0 ) && (zD < cols)) PixelA = SEGMENT.getPixelColorXY (zD, y);
7542
- else PixelA = ColorFromPalette (SEGPALETTE, ~noise3d[XY (abs (zD),y)]*3 );
7543
- CRGB PixelB = CRGB::Black;
7544
- if ((zF >= 0 ) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY (zF, y);
7545
- else PixelB = ColorFromPalette (SEGPALETTE, ~noise3d[XY (abs (zF),y)]*3 );
7546
- ledsbuff[x] = (PixelA.nscale8 (ease8InOutApprox (255 - fraction))) + (PixelB.nscale8 (ease8InOutApprox (fraction)));
7547
- }
7548
- for (int x = 0 ; x < cols; x++) SEGMENT.setPixelColorXY (x, y, ledsbuff[x]);
7549
- }
7550
-
7551
- amplitude = (rows >= 16 ) ? (rows-8 )/8 : 1 ;
7552
- for (int x = 0 ; x < cols; x++) {
7553
- int amount = ((int )noise3d[XY (x,0 )] - 128 ) * 2 * amplitude + 256 *shiftY;
7554
- int delta = abs (amount) >> 8 ;
7555
- int fraction = abs (amount) & 255 ;
7556
- for (int y = 0 ; y < rows; y++) {
7557
- if (amount < 0 ) {
7558
- zD = y - delta;
7559
- zF = zD - 1 ;
7560
- } else {
7561
- zD = y + delta;
7562
- zF = zD + 1 ;
7563
- }
7564
- CRGB PixelA = CRGB::Black;
7565
- if ((zD >= 0 ) && (zD < rows)) PixelA = SEGMENT.getPixelColorXY (x, zD);
7566
- else PixelA = ColorFromPalette (SEGPALETTE, ~noise3d[XY (x,abs (zD))]*3 );
7567
- CRGB PixelB = CRGB::Black;
7568
- if ((zF >= 0 ) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY (x, zF);
7569
- else PixelB = ColorFromPalette (SEGPALETTE, ~noise3d[XY (x,abs (zF))]*3 );
7570
- ledsbuff[y] = (PixelA.nscale8 (ease8InOutApprox (255 - fraction))) + (PixelB.nscale8 (ease8InOutApprox (fraction)));
7571
- }
7572
- for (int y = 0 ; y < rows; y++) SEGMENT.setPixelColorXY (x, y, ledsbuff[y]);
7573
- }
7564
+ soapPixels (true , noise3d, pixels); // rows
7565
+ soapPixels (false , noise3d, pixels); // cols
7574
7566
7575
7567
return FRAMETIME;
7576
7568
}
7577
- static const char _data_FX_MODE_2DSOAP[] PROGMEM = " Soap@!,Smoothness;;!;2;pal=11" ;
7569
+ static const char _data_FX_MODE_2DSOAP[] PROGMEM = " Soap@!,Smoothness,Density ;;!;2;pal=11" ;
7578
7570
7579
7571
7580
7572
// Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21
0 commit comments