From 2119d08543407811ea370dd2f0e39b683002abf6 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 28 Apr 2023 22:00:35 +0200 Subject: [PATCH 1/8] Octopus 2D effect - by Stepko --- wled00/FX.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 1 + 2 files changed, 53 insertions(+) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c3f82ae3f..34a16da07 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7495,6 +7495,57 @@ uint16_t mode_2Dsoap() { } static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2"; + +//Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 +//Octopus (https://editor.soulmatelights.com/gallery/671-octopus) +//Stepko and Sutaburosu +// adapted for WLED by @blazoncek +uint16_t mode_2Doctopus() { + if (!strip.isMatrix) return mode_static(); // not a 2D set-up + + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + const uint8_t C_X = cols / 2; + const uint8_t C_Y = rows / 2; + const uint8_t mapp = 255 / cols; + + typedef struct { + uint8_t angle; + uint8_t radius; + } map_t; + + const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(map_t); // prevent reallocation if mirrored or grouped + if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + + map_t *rMap = reinterpret_cast(SEGENV.data); + + if (SEGENV.call == 0) { + SEGENV.aux0 = 0; // t + for (int x = -C_X; x < C_X + (cols % 2); x++) { + for (int y = -C_Y; y < C_Y + (rows % 2); y++) { + rMap[XY(x + C_X, y + C_Y)].angle = 128 * (atan2f(y, x) / PI); + rMap[XY(x + C_X, y + C_Y)].radius = hypotf(x, y) * mapp; //thanks Sutaburosu + } + } + } + + SEGENV.aux0 += SEGMENT.speed / 32 + 1; // 1-8 range + for (uint8_t x = 0; x < cols; x++) { + for (uint8_t y = 0; y < rows; y++) { + byte angle = rMap[XY(x,y)].angle; + byte radius = rMap[XY(x,y)].radius; + //CRGB c = CHSV(SEGENV.aux0 / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.aux0) + radius - SEGENV.aux0 * 2 + angle * (SEGMENT.custom3/3+1))); + uint16_t intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.aux0/2) + radius - SEGENV.aux0 + angle * (SEGMENT.custom3/4+1)); + intensity = map(intensity*intensity, 0, 65535, 0, SEGMENT.intensity); // add a bit of non-linearity to brightness + CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.aux0 / 2 - radius, intensity); + SEGMENT.setPixelColorXY(x, y, c); + } + } + return FRAMETIME; +} +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,!,,,Legs;;!;2;ix=255"; + + #endif // WLED_DISABLE_2D @@ -7729,6 +7780,7 @@ void WS2812FX::setupEffectData() { 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_2DOCTOPUS, &mode_2Doctopus, _data_FX_MODE_2DOCTOPUS); 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 b4ba2f21c..897f397d2 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -256,6 +256,7 @@ #define FX_MODE_2DDRIFTROSE 123 //gap fill #define FX_MODE_2DDISTORTIONWAVES 124 //gap fill #define FX_MODE_2DSOAP 125 //gap fill +#define FX_MODE_2DOCTOPUS 126 //gap fill // WLED-SR effects (SR compatible IDs !!!) #define FX_MODE_PIXELS 128 From f0dade5856002a65db7b08fc8e334d0dcbedc608 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 29 Apr 2023 15:51:25 +0200 Subject: [PATCH 2/8] Uneven matrix fix. --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 34a16da07..f3bbb957f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7507,7 +7507,7 @@ uint16_t mode_2Doctopus() { const uint16_t rows = SEGMENT.virtualHeight(); const uint8_t C_X = cols / 2; const uint8_t C_Y = rows / 2; - const uint8_t mapp = 255 / cols; + const uint8_t mapp = 255 / MAX(cols,rows); typedef struct { uint8_t angle; From 61eb7b0a6a0314ad4c3ec588e2742aa0a5f4cd2a Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 29 Apr 2023 17:04:16 +0200 Subject: [PATCH 3/8] Waving Cell FX --- wled00/FX.cpp | 19 +++++++++++++++++++ wled00/FX.h | 1 + 2 files changed, 20 insertions(+) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f3bbb957f..0f04810ed 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7546,6 +7546,24 @@ uint16_t mode_2Doctopus() { static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,!,,,Legs;;!;2;ix=255"; +//Waving Cell +//@Stepko (https://editor.soulmatelights.com/gallery/1704-wavingcells) +// adapted for WLED by @blazoncek +uint16_t mode_2Dwavingcell() { + if (!strip.isMatrix) return mode_static(); // not a 2D set-up + + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + + uint32_t t = millis()/(256-SEGMENT.speed); + for (int x = 0; x < cols; x++) for (int y = 0; y Date: Sun, 30 Apr 2023 13:25:08 +0200 Subject: [PATCH 4/8] Tweaks. --- wled00/FX.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 0f04810ed..b27311662 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7520,7 +7520,7 @@ uint16_t mode_2Doctopus() { map_t *rMap = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { - SEGENV.aux0 = 0; // t + SEGENV.step = 0; // t for (int x = -C_X; x < C_X + (cols % 2); x++) { for (int y = -C_Y; y < C_Y + (rows % 2); y++) { rMap[XY(x + C_X, y + C_Y)].angle = 128 * (atan2f(y, x) / PI); @@ -7529,15 +7529,15 @@ uint16_t mode_2Doctopus() { } } - SEGENV.aux0 += SEGMENT.speed / 32 + 1; // 1-8 range - for (uint8_t x = 0; x < cols; x++) { - for (uint8_t y = 0; y < rows; y++) { + SEGENV.step += SEGMENT.speed / 32 + 1; // 1-4 range + for (int x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; - //CRGB c = CHSV(SEGENV.aux0 / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.aux0) + radius - SEGENV.aux0 * 2 + angle * (SEGMENT.custom3/3+1))); - uint16_t intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.aux0/2) + radius - SEGENV.aux0 + angle * (SEGMENT.custom3/4+1)); - intensity = map(intensity*intensity, 0, 65535, 0, SEGMENT.intensity); // add a bit of non-linearity to brightness - CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.aux0 / 2 - radius, intensity); + //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); + uint16_t intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); + intensity = map(intensity*intensity, 0, 65535, 0, SEGMENT.intensity); // add a bit of non-linearity for cleaner display + CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); } } @@ -7555,13 +7555,16 @@ uint16_t mode_2Dwavingcell() { const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - uint32_t t = millis()/(256-SEGMENT.speed); + uint32_t t = millis()/(257-SEGMENT.speed); + uint8_t aX = SEGMENT.custom1/16 + 9; + uint8_t aY = SEGMENT.custom2/16 + 1; + uint8_t aZ = SEGMENT.custom3 + 1; for (int x = 0; x < cols; x++) for (int y = 0; y Date: Mon, 1 May 2023 20:43:03 +0200 Subject: [PATCH 5/8] Fix for mirroring --- wled00/FX.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index bc34f95e4..8e484f521 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7406,12 +7406,11 @@ uint16_t mode_2Dsoap() { *noise32_x = random16(); *noise32_y = random16(); *noise32_z = random16(); - 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[XY(i,j)] = scale8(noise3d[XY(i,j)], SEGMENT.intensity) + scale8(data, 255 - SEGMENT.intensity); + for (int i = 0; i < SEGMENT.width(); i++) { + int32_t ioffset = scale32_x * (i - SEGMENT.width() / 2); + for (int j = 0; j < SEGMENT.height(); j++) { + int32_t joffset = scale32_y * (j - SEGMENT.height() / 2); + noise3d[XY(i,j)] = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8; SEGMENT.setPixelColorXY(i, j, ColorFromPalette(SEGPALETTE,~noise3d[XY(i,j)]*3)); } } @@ -7499,8 +7498,6 @@ uint16_t mode_2Doctopus() { const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - const uint8_t C_X = cols / 2; - const uint8_t C_Y = rows / 2; const uint8_t mapp = 255 / MAX(cols,rows); typedef struct { @@ -7513,8 +7510,13 @@ uint16_t mode_2Doctopus() { map_t *rMap = reinterpret_cast(SEGENV.data); - if (SEGENV.call == 0) { + // re-init if SEGMENT dimensions changed + if (SEGENV.call == 0 || SEGMENT.aux0 != cols || SEGMENT.aux1 != rows) { SEGENV.step = 0; // t + SEGMENT.aux0 = cols; + SEGMENT.aux1 = rows; + const uint8_t C_X = cols / 2; + const uint8_t C_Y = rows / 2; for (int x = -C_X; x < C_X + (cols % 2); x++) { for (int y = -C_Y; y < C_Y + (rows % 2); y++) { rMap[XY(x + C_X, y + C_Y)].angle = 128 * (atan2f(y, x) / PI); From 3da086438b744836f59377fb9180a6dad54e1e43 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 2 May 2023 11:16:24 +0200 Subject: [PATCH 6/8] Add rotating to Octopus Soap optimization --- wled00/FX.cpp | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 8e484f521..226f63577 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7380,6 +7380,7 @@ 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 @@ -7397,8 +7398,10 @@ uint16_t mode_2Dsoap() { 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 = 160000U/cols; - uint32_t scale32_y = 160000U/rows; + 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) { @@ -7406,27 +7409,28 @@ uint16_t mode_2Dsoap() { *noise32_x = random16(); *noise32_y = random16(); *noise32_z = random16(); - for (int i = 0; i < SEGMENT.width(); i++) { - int32_t ioffset = scale32_x * (i - SEGMENT.width() / 2); - for (int j = 0; j < SEGMENT.height(); j++) { - int32_t joffset = scale32_y * (j - SEGMENT.height() / 2); - noise3d[XY(i,j)] = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8; - SEGMENT.setPixelColorXY(i, j, ColorFromPalette(SEGPALETTE,~noise3d[XY(i,j)]*3)); - } - } + } else { + *noise32_x += mov; + *noise32_y += mov; + *noise32_z += mov; } - uint32_t mov = MAX(cols,rows)*(SEGMENT.speed+1)/2; - *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[XY(i,j)] = scale8(noise3d[XY(i,j)], SEGMENT.intensity) + scale8(data, 256 - SEGMENT.intensity); + noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness); + } + } + // init also if dimensions changed + if (SEGENV.call == 0 || SEGMENT.aux0 != cols || SEGMENT.aux1 != rows) { + SEGMENT.aux0 = cols; + SEGMENT.aux1 = rows; + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + SEGMENT.setPixelColorXY(i, j, ColorFromPalette(SEGPALETTE,~noise3d[XY(i,j)]*3)); + } } } @@ -7534,12 +7538,15 @@ uint16_t mode_2Doctopus() { uint16_t intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); intensity = map(intensity*intensity, 0, 65535, 0, SEGMENT.intensity); // add a bit of non-linearity for cleaner display CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); - SEGMENT.setPixelColorXY(x, y, c); + int rX = SEGMENT.custom1 ? (strip.now / (320 - SEGMENT.custom1) + x) % cols : x; + int rY = SEGMENT.custom2 ? (strip.now / (320 - SEGMENT.custom2) + y) % rows : y; + SEGMENT.setPixelColorXY(rX, rY, c); } } + return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,!,,,Legs;;!;2;ix=255"; +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,!,Rotate X,Rotate Y,Legs;;!;2;ix=255,c1=0,c2=0"; //Waving Cell From 16b66afa7a27941e29a1077504519808e2d9227c Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 10 May 2023 21:06:48 +0200 Subject: [PATCH 7/8] Octopus offset --- wled00/FX.cpp | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c3873765e..e3b6a2028 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7518,21 +7518,25 @@ uint16_t mode_2Doctopus() { } map_t; const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(map_t); // prevent reallocation if mirrored or grouped - if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + if (!SEGENV.allocateData(dataSize + 2)) return mode_static(); //allocation failed map_t *rMap = reinterpret_cast(SEGENV.data); + uint8_t *offsX = reinterpret_cast(SEGENV.data + dataSize); + uint8_t *offsY = reinterpret_cast(SEGENV.data + dataSize + 1); - // re-init if SEGMENT dimensions changed - if (SEGENV.call == 0 || SEGMENT.aux0 != cols || SEGMENT.aux1 != rows) { + // re-init if SEGMENT dimensions or offset changed + if (SEGENV.call == 0 || SEGENV.aux0 != cols || SEGENV.aux1 != rows || SEGMENT.custom1 != *offsX || SEGMENT.custom2 != *offsY) { SEGENV.step = 0; // t - SEGMENT.aux0 = cols; - SEGMENT.aux1 = rows; - const uint8_t C_X = cols / 2; - const uint8_t C_Y = rows / 2; - for (int x = -C_X; x < C_X + (cols % 2); x++) { - for (int y = -C_Y; y < C_Y + (rows % 2); y++) { - rMap[XY(x + C_X, y + C_Y)].angle = 128 * (atan2f(y, x) / PI); - rMap[XY(x + C_X, y + C_Y)].radius = hypotf(x, y) * mapp; //thanks Sutaburosu + SEGENV.aux0 = cols; + SEGENV.aux1 = rows; + *offsX = SEGMENT.custom1; + *offsY = SEGMENT.custom2; + const uint8_t C_X = cols / 2 + (SEGMENT.custom1 - 128)*cols/255; + const uint8_t C_Y = rows / 2 + (SEGMENT.custom2 - 128)*rows/255; + for (int x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) { + rMap[XY(x, y)].angle = 128 * (atan2f(y - C_Y, x - C_X) / PI); + rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu } } } @@ -7544,17 +7548,14 @@ uint16_t mode_2Doctopus() { byte radius = rMap[XY(x,y)].radius; //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); uint16_t intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); - intensity = map(intensity*intensity, 0, 65535, 0, SEGMENT.intensity); // add a bit of non-linearity for cleaner display + intensity = map(intensity*intensity, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); - int rX = SEGMENT.custom1 ? (strip.now / (320 - SEGMENT.custom1) + x) % cols : x; - int rY = SEGMENT.custom2 ? (strip.now / (320 - SEGMENT.custom2) + y) % rows : y; - SEGMENT.setPixelColorXY(rX, rY, c); + SEGMENT.setPixelColorXY(x, y, c); } } - return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,!,Rotate X,Rotate Y,Legs;;!;2;ix=255,c1=0,c2=0"; +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs;;!;2;"; //Waving Cell From cae43e97cd3f6db93059cabb47a1e412afadf162 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 13 May 2023 15:17:49 +0200 Subject: [PATCH 8/8] Corner fix --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e3b6a2028..5d0d30ba7 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7510,7 +7510,7 @@ uint16_t mode_2Doctopus() { const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - const uint8_t mapp = 255 / MAX(cols,rows); + const uint8_t mapp = 180 / MAX(cols,rows); typedef struct { uint8_t angle; @@ -7535,7 +7535,7 @@ uint16_t mode_2Doctopus() { const uint8_t C_Y = rows / 2 + (SEGMENT.custom2 - 128)*rows/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 128 * (atan2f(y - C_Y, x - C_X) / PI); + rMap[XY(x, y)].angle = 40.7436f * atan2f(y - C_Y, x - C_X); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu } }