From 3f006b689ccaa6766bb8f1a0065f570a43460f1f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 18 May 2025 18:12:58 +0200 Subject: [PATCH] update to distortionwave FX - fixed "jumpyness" by improving offset calculation resolution - added palette support - added two rendering modes for use with palette: one uses hue-mapping, one uses brightness mapping - added alternate animation mode (from initial source) - extended scaling: zoom checkmark (depends on matrix size) --- wled00/FX.cpp | 63 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9584ea8e7b..eba3242a4a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7412,7 +7412,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 -// adapted for WLED by @blazoncek +// adapted for WLED by @blazoncek, improvements by @dedehai uint16_t mode_2Ddistortionwaves() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up @@ -7421,20 +7421,23 @@ uint16_t mode_2Ddistortionwaves() { uint8_t speed = SEGMENT.speed/32; uint8_t scale = SEGMENT.intensity/32; - - uint8_t w = 2; + if(SEGMENT.check2) scale += 192 / (cols+rows); // zoom out some more. note: not changing scale slider for backwards compatibility unsigned a = strip.now/32; unsigned a2 = a/2; unsigned a3 = a/3; + unsigned colsScaled = cols * scale; + unsigned rowsScaled = rows * scale; + + unsigned cx = beatsin16_t(10-speed,0,colsScaled); + unsigned cy = beatsin16_t(12-speed,0,rowsScaled); + unsigned cx1 = beatsin16_t(13-speed,0,colsScaled); + unsigned cy1 = beatsin16_t(15-speed,0,rowsScaled); + unsigned cx2 = beatsin16_t(17-speed,0,colsScaled); + unsigned cy2 = beatsin16_t(14-speed,0,rowsScaled); + + byte rdistort, gdistort, bdistort; - unsigned cx = beatsin8_t(10-speed,0,cols-1)*scale; - unsigned cy = beatsin8_t(12-speed,0,rows-1)*scale; - unsigned cx1 = beatsin8_t(13-speed,0,cols-1)*scale; - unsigned cy1 = beatsin8_t(15-speed,0,rows-1)*scale; - unsigned cx2 = beatsin8_t(17-speed,0,cols-1)*scale; - unsigned cy2 = beatsin8_t(14-speed,0,rows-1)*scale; - unsigned xoffs = 0; for (int x = 0; x < cols; x++) { xoffs += scale; @@ -7443,25 +7446,49 @@ uint16_t mode_2Ddistortionwaves() { for (int y = 0; y < rows; y++) { yoffs += scale; - byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; - byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; - byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; + if(SEGMENT.check3) { + // alternate mode from original code + rdistort = cos8_t (((x+y)*8+a2)&255)>>1; + gdistort = cos8_t (((x+y)*8+a3+32)&255)>>1; + bdistort = cos8_t (((x+y)*8+a+64)&255)>>1; + } else { + rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; + gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; + bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; + } - byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); - byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); - byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); + byte valueR = rdistort + ((a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 ))<<1); + byte valueG = gdistort + ((a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 ))<<1); + byte valueB = bdistort + ((a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 ))<<1); valueR = gamma8(cos8_t(valueR)); valueG = gamma8(cos8_t(valueG)); valueB = gamma8(cos8_t(valueB)); - SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); + if(SEGMENT.palette == 0) { + // use RGB values (original color mode) + SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); + } else { + // use palette + uint8_t brightness = (valueR + valueG + valueB) / 3; + if(SEGMENT.check1) { // map brightness to palette index + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP)); + } else { + // color mapping: calculate hue from pixel color, map it to palette index + CHSV hsvclr = rgb2hsv_approximate(CRGB(valueR>>2, valueG>>2, valueB>>2)); // scale colors down to not saturate for better hue extraction + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hsvclr.h, brightness)); + } + } } } + // palette mode and not filling: smear-blur to cover up palette wrapping artefacts + if(!SEGMENT.check1 && SEGMENT.palette) + SEGMENT.blur(200, true); + return FRAMETIME; } -static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2"; +static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale,,,,Fill,Zoom,Alt;;!;2;pal=0"; //Soap