Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Pinwheel Expand 1D Effect #3961

Merged
merged 18 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ typedef enum mapping1D2D {
M12_Pixels = 0,
M12_pBar = 1,
M12_pArc = 2,
M12_pCorner = 3
M12_pCorner = 3,
M12_sPinwheel = 4
} mapping1D2D_t;

// segment, 80 bytes
Expand Down
58 changes: 57 additions & 1 deletion wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,14 @@ uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
return vLen;
}

// 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


// 1D strip
uint16_t IRAM_ATTR Segment::virtualLength() const {
#ifndef WLED_DISABLE_2D
Expand All @@ -652,6 +660,12 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
case M12_pArc:
vLen = max(vW,vH); // get the longest dimension
break;
case M12_sPinwheel:
if (max(vW,vH) <= Pinwheel_Size_Medium)
vLen = Pinwheel_Steps_Medium;
else
vLen = Pinwheel_Steps_Big;
break;
}
return vLen;
}
Expand Down Expand Up @@ -718,6 +732,38 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col);
for (int y = 0; y < i; y++) setPixelColorXY(i, y, col);
break;
case M12_sPinwheel: {
// 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;
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);
// advance to next position
posx += inc_x;
posy += inc_y;
}
break;
}
}
return;
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
Expand Down Expand Up @@ -833,7 +879,17 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i)
// use longest dimension
return vW>vH ? getPixelColorXY(i, 0) : getPixelColorXY(0, i);
break;
}
case M12_sPinwheel:
// 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);
break;
}
return 0;
}
#endif
Expand Down
1 change: 1 addition & 0 deletions wled00/data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ function populateSegments(s)
`<option value="1" ${inst.m12==1?' selected':''}>Bar</option>`+
`<option value="2" ${inst.m12==2?' selected':''}>Arc</option>`+
`<option value="3" ${inst.m12==3?' selected':''}>Corner</option>`+
`<option value="4" ${inst.m12==4?' selected':''}>Pinwheel</option>`+
`</select></div>`+
`</div>`;
let sndSim = `<div data-snd="si" class="lbl-s hide">Sound sim<br>`+
Expand Down