diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 84e0b5ef..711cb0e2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -776,6 +776,16 @@ void Segment::deletejMap() { } } + +// WLEDMM constants for mapping mode "Pinwheel" +constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps +constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big" +constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps +constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians +constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians +// WLEDMM end + + // 1D strip uint16_t Segment::virtualLength() const { #ifndef WLED_DISABLE_2D @@ -806,7 +816,11 @@ uint16_t Segment::virtualLength() const { vLen = max(vW,vH) * 0.5; // get the longest dimension break; case M12_sPinWheel: //WLEDMM - vLen = 360; // full circle + //vLen = full circle + if (max(vW,vH) <= Pinwheel_Size_Medium) + vLen = Pinwheel_Steps_Medium; + else + vLen = Pinwheel_Steps_Big; break; } return vLen; @@ -935,24 +949,35 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT } } break; - case M12_sPinWheel: { - // i = 0 through 359 - float centerX = (vW-1) / 2; - float centerY = (vH-1) / 2; + case M12_sPinWheel: { // WLEDMM + // i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium) + float centerX = roundf((vW-1) / 2.0f); + float centerY = roundf((vH-1) / 2.0f); // int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1; - - int distance = 0; - float cosVal = cosf((float)i * (float)DEG_TO_RAD); // i = current angle - float sinVal = sinf((float)i * (float)DEG_TO_RAD); - while (true) { - int x = roundf(centerX + distance * cosVal); - int y = roundf(centerY + distance * sinVal); - // Check bounds - if (x < 0 || x >= vW || y < 0 || y >= vH) { - break; - } + float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians + float cosVal = cosf(angleRad); + float sinVal = sinf(angleRad); + + // draw line at angle, starting at center and ending at the segment edge + // we use fixed point math for better speed. Starting distance is 0.5 for better rounding + constexpr int_fast32_t Fixed_Scale = 512; // fixpoint scaling factor + int_fast32_t posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point + int_fast32_t posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point + int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) + int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) + + int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint + int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint + // draw until we hit any edge + while ((posx > 0) && (posy > 0) && (posx < maxX) && (posy < maxY)) { + // scale down to integer (compiler will replace division with appropriate bitshift) + int x = posx / Fixed_Scale; + int y = posy / Fixed_Scale; + // set pixel setPixelColorXY(x, y, col); - distance++; + // advance to next position + posx += inc_x; + posy += inc_y; } break; } @@ -1094,12 +1119,13 @@ uint32_t Segment::getPixelColor(int i) return getPixelColorXY(vW / 2, vH / 2 - i - 1); break; case M12_sPinWheel: //WLEDMM - // not 100% accurate, returns outer edge of circle - int distance = min(vH, vW) / 2; - float centerX = (vW - 1) / 2; - float centerY = (vH - 1) / 2; - int x = round(centerX + distance * cos(i * DEG_TO_RAD)); - int y = round(centerY + distance * sin(i * DEG_TO_RAD)); + // not 100% accurate, returns outer edge of circle + float distance = max(1.0f, min(vH-1, vW-1) / 2.0f); + float centerX = (vW - 1) / 2.0f; + float centerY = (vH - 1) / 2.0f; + float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians + int x = roundf(centerX + distance * cosf(angleRad)); + int y = roundf(centerY + distance * sinf(angleRad)); return getPixelColorXY(x, y); } return 0; diff --git a/wled00/wled.h b/wled00/wled.h index 50b3e1ed..c98fa856 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2402250 +#define VERSION 2402251 // 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_