diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2e74f743..f4448d33 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5137,6 +5137,7 @@ static const char _data_FX_MODE_2DDNASPIRAL[] PROGMEM = "DNA Spiral@Scroll speed // 2D Drift // ///////////////////////// uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmatelights.com/gallery/884-drift , Modified by: Andrew Tuline + // optimized for large panels by @softhack007 if (!strip.isMatrix) return mode_static(); // not a 2D set-up const uint16_t cols = SEGMENT.virtualWidth(); @@ -5147,22 +5148,40 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli SEGMENT.fill(BLACK); } - SEGMENT.fadeToBlackBy(128); + if (SEGMENT.intensity > 1) SEGMENT.fadeToBlackBy(128); + else SEGMENT.fill(BLACK); // WLEDMM fill is faster than fade + const float maxDim = max(cols, rows)/2.0f; - const uint16_t maxDim = MAX(cols, rows)/2; - unsigned long t = strip.now / (32 - (SEGMENT.speed>>3)); - unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup - for (float i = 1; i < maxDim; i += 0.25) { - float angle = radians(t * (maxDim - i)); - uint16_t myX = (cols>>1) + (uint16_t)(sinf(angle) * i) + (cols%2); - uint16_t myY = (rows>>1) + (uint16_t)(cosf(angle) * i) + (rows%2); - SEGMENT.setPixelColorXY(myX, myY, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND)); + // WLEDMM calculate timebase in float, so we don't need to worry about rounding + const float strip_now = strip.now & 0x003FFFFF; // float can exactly represent numbers up to 22bit + float t; + if (maxDim < 6.0f) t = strip_now / float(16U - (SEGMENT.speed>>4)); // up to 12 (faster) + else if (maxDim <= 16.0f) t = strip_now / float(32U - (SEGMENT.speed>>3)); // 12..32 (standard) + else if (maxDim <= 32.0f) t = strip_now / float(64U - (SEGMENT.speed>>2)); // 32..64 (slower) + else t = strip_now / float(256U - SEGMENT.speed); // above 64 (slowest) + + // WLEDMM pre-calculate some values to speed up the main loop + const int colsCenter = (cols >> 1) + (cols % 2); + const int rowsCenter = (rows >> 1) + (rows % 2); + unsigned t_20 = t/20.0f; // softhack007: pre-calculating this gives about 10% speedup + const float step = (maxDim < 6.0f) ? 0.52f : (maxDim > 24.0f) ? 0.16666666f : 0.25f; // WLEDMM more detail on larger panels + + for (float i = 1.0f; i <= maxDim; i += step) { + unsigned i_20 = i * 20.0f; + float t_maxdim = t * (maxDim - i); + float angle = float(DEG_TO_RAD) * t_maxdim; + int mySin = sinf(angle) * i; + int myCos = cosf(angle) * i; + + if ((unsigned(colsCenter+mySin) < cols) && (unsigned(rowsCenter+myCos) < rows)) // don't draw invisible pixels + SEGMENT.setPixelColorXY(colsCenter+mySin, rowsCenter+myCos, ColorFromPalette(SEGPALETTE, i_20 + t_20, 255, LINEARBLEND)); + if ((SEGMENT.check1) && (unsigned(colsCenter+myCos) < cols) && (unsigned(rowsCenter+mySin) < rows)) + SEGMENT.setPixelColorXY(colsCenter+myCos, rowsCenter+mySin, ColorFromPalette(SEGPALETTE, i_20 + t_20, 255, LINEARBLEND)); // twin mode } - SEGMENT.blur(SEGMENT.intensity>>3); - + SEGMENT.blur(SEGMENT.intensity>>((!SEGMENT.check2) * 3), SEGMENT.check2); // user-defined blur - thanks @dedehai return FRAMETIME; } // mode_2DDrift() -static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur amount;;!;2"; +static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur,,,,Twin,Smear;;!;2;ix=0"; ////////////////////////// @@ -6730,7 +6749,13 @@ uint16_t mode_2Ddriftrose(void) { const float CX = (cols-cols%2)/2.f - .5f; const float CY = (rows-rows%2)/2.f - .5f; - const float L = min(cols, rows) / 2.f; + + unsigned L2 = SEGENV.check3 ? max(cols, rows) : min(cols, rows); // WLEDMM we use "max" to use the complete segment + if (SEGENV.check3 && (abs(int(cols) - int(rows)) < 4)) L2 = L2 * 1.4142f; // WLEDMM make "expand" look a bit bigger on square panels + const float L = L2 / 2.f; + // WLEDMM pre-calculate some values + const uint32_t wu_cols = SEGMENT.virtualWidth() * 256; + const uint32_t wu_rows = SEGMENT.virtualHeight() * 256; if (SEGENV.call == 0) { SEGMENT.setUpLeds(); @@ -6739,15 +6764,16 @@ uint16_t mode_2Ddriftrose(void) { SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); for (size_t i = 1; i < 37; i++) { - uint32_t x = (CX + (sinf(radians(i * 10)) * (beatsin8(i, 0, L*2)-L))) * 255.f; - uint32_t y = (CY + (cosf(radians(i * 10)) * (beatsin8(i, 0, L*2)-L))) * 255.f; - SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); + float angle = float(DEG_TO_RAD) * i * 10; + uint32_t x = int((CX + (sinf(angle) * (beatsin8(i, 0, L2)-L))) * 255.f); + uint32_t y = int((CY + (cosf(angle) * (beatsin8(i, 0, L2)-L))) * 255.f); + if ((x < wu_cols) && (y < wu_rows)) SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); } SEGMENT.blur((SEGMENT.intensity>>4)+1); return FRAMETIME; } -static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;2"; +static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur,,,,,,Full Expand ☾;;;2"; #endif // WLED_DISABLE_2D diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 4aa7afbb..bb12b66a 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -12,24 +12,33 @@ IRAM_ATTR_YN __attribute__((hot)) uint32_t color_blend(uint32_t color1, uint32_t const uint_fast16_t blendmax = b16 ? 0xFFFF : 0xFF; if(blend >= blendmax) return color2; const uint_fast8_t shift = b16 ? 16 : 8; - const uint_fast16_t blend2 = blendmax - blend; // WLEDMM pre-calculate value - uint32_t w1 = W(color1); - uint32_t r1 = R(color1); - uint32_t g1 = G(color1); - uint32_t b1 = B(color1); + uint16_t w1 = W(color1); // WLEDMM 16bit to make sure the compiler uses 32bit (not 64bit) for the math + uint16_t r1 = R(color1); + uint16_t g1 = G(color1); + uint16_t b1 = B(color1); - uint32_t w2 = W(color2); - uint32_t r2 = R(color2); - uint32_t g2 = G(color2); - uint32_t b2 = B(color2); + uint16_t w2 = W(color2); + uint16_t r2 = R(color2); + uint16_t g2 = G(color2); + uint16_t b2 = B(color2); - uint32_t w3 = ((w2 * blend) + (w1 * blend2)) >> shift; - uint32_t r3 = ((r2 * blend) + (r1 * blend2)) >> shift; - uint32_t g3 = ((g2 * blend) + (g1 * blend2)) >> shift; - uint32_t b3 = ((b2 * blend) + (b1 * blend2)) >> shift; - - return RGBW32(r3, g3, b3, w3); + if (b16 == false) { + // WLEDMM based on fastled blend8() - better accuracy for 8bit + uint8_t w3 = (w1+w2 == 0) ? 0 : (((w1 << 8)|w2) + (w2 * blend) - (w1*blend) ) >> 8; + uint8_t r3 = (((r1 << 8)|r2) + (r2 * blend) - (r1*blend) ) >> 8; + uint8_t g3 = (((g1 << 8)|g2) + (g2 * blend) - (g1*blend) ) >> 8; + uint8_t b3 = (((b1 << 8)|b2) + (b2 * blend) - (b1*blend) ) >> 8; + return RGBW32(r3, g3, b3, w3); + } else { + // old code has lots of "jumps" due to roundding errors + const uint_fast16_t blend2 = blendmax - blend; // WLEDMM pre-calculate value + uint32_t w3 = ((w2 * blend) + (w1 * blend2)) >> shift; + uint32_t r3 = ((r2 * blend) + (r1 * blend2)) >> shift; + uint32_t g3 = ((g2 * blend) + (g1 * blend2)) >> shift; + uint32_t b3 = ((b2 * blend) + (b1 * blend2)) >> shift; + return RGBW32(r3, g3, b3, w3); + } } /* @@ -75,25 +84,27 @@ IRAM_ATTR_YN __attribute__((hot)) uint32_t color_fade(uint32_t c1, uint8_t amoun if (amount == 255) return c1; // WLEDMM small optimization - plus it avoids over-fading in "video" mode if (amount == 0) return 0; // WLEDMM shortcut - uint32_t scaledcolor; // color order is: W R G B from MSB to LSB - uint32_t r = R(c1); - uint32_t g = G(c1); - uint32_t b = B(c1); - uint32_t w = W(c1); + uint32_t scaledcolor = 0; // color order is: W R G B from MSB to LSB + uint16_t w = W(c1); // WLEDMM 16bit to make sure the compiler uses 32bit (not 64bit) for the math + uint16_t r = R(c1); + uint16_t g = G(c1); + uint16_t b = B(c1); if (video) { - uint32_t scale = amount; // 32bit for faster calculation - scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0); - scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0); - scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); - if (w>0) scaledcolor |= (((w * scale) >> 8) << 24) + ((scale) ? 1 : 0); // WLEDMM small speedup when no white channel + uint16_t scale = amount; // 32bit for faster calculation + // bugfix: doing "+1" after shifting is obviously wrong + // optimization: ((r && scale) ? 1 : 0) can be simplified to "if (r > 0) +1" ; if we arive here, then scale != 0 and scale < 255 + if (w>0) scaledcolor |= (((w * scale) >> 8) +1) << 24; // WLEDMM small speedup when no white channel + if (r>0) scaledcolor |= (((r * scale) >> 8) +1) << 16; + if (g>0) scaledcolor |= (((g * scale) >> 8) +1) << 8; + if (b>0) scaledcolor |= ((b * scale) >> 8) +1; return scaledcolor; } else { - uint32_t scale = 1 + amount; - scaledcolor = ((r * scale) >> 8) << 16; - scaledcolor |= ((g * scale) >> 8) << 8; - scaledcolor |= (b * scale) >> 8; + uint16_t scale = 1 + amount; if (w>0) scaledcolor |= ((w * scale) >> 8) << 24; // WLEDMM small speedup when no white channel + scaledcolor |= ((r * scale) >> 8) << 16; + scaledcolor |= (g * scale) & 0x0000FF00; // WLEDMM faster than right-left shift "" >>8 ) <<8" + scaledcolor |= (b * scale) >> 8; return scaledcolor; } } diff --git a/wled00/wled.h b/wled00/wled.h index ce0cc151..85a9fe84 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2411130 +#define VERSION 2411150 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_