Skip to content

Commit e17c30e

Browse files
committed
Merge pull request wled#3961 from Brandon502/0_15
Added Pinwheel Expand 1D ->2D effect mapping mode
1 parent 118163d commit e17c30e

2 files changed

Lines changed: 93 additions & 36 deletions

File tree

wled00/FX.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ typedef enum mapping1D2D {
355355
M12_jMap = 4, //WLEDMM jMap
356356
M12_sCircle = 5, //WLEDMM Circle
357357
M12_sBlock = 6, //WLEDMM Block
358-
M12_sPinWheel = 7 //WLEDMM PinWheel
358+
M12_sPinwheel = 7 //WLEDMM Pinwheel
359359
} mapping1D2D_t;
360360

361361
// segment, 72 bytes

wled00/FX_fcn.cpp

Lines changed: 92 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -793,14 +793,41 @@ void Segment::deletejMap() {
793793
}
794794

795795

796-
// WLEDMM constants for mapping mode "Pinwheel"
797-
constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps
798-
constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
799-
constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps
800-
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
801-
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
802-
// WLEDMM end
803-
796+
// Constants for mapping mode "Pinwheel"
797+
#ifndef WLED_DISABLE_2D
798+
constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16
799+
constexpr int Pinwheel_Size_Small = 16; // larger than this -> use "Medium"
800+
constexpr int Pinwheel_Steps_Medium = 192; // no holes up to 32x32
801+
constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
802+
constexpr int Pinwheel_Steps_Big = 304; // no holes up to 50x50
803+
constexpr int Pinwheel_Size_Big = 50; // larger than this -> use "XL"
804+
constexpr int Pinwheel_Steps_XL = 368;
805+
constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360) / Pinwheel_Steps_Small; // conversion: from 0...72 to Radians
806+
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...192 to Radians
807+
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...304 to Radians
808+
constexpr float Int_to_Rad_XL = (DEG_TO_RAD * 360) / Pinwheel_Steps_XL; // conversion: from 0...368 to Radians
809+
810+
constexpr int Fixed_Scale = 512; // fixpoint scaling factor (9bit for fraction)
811+
812+
// Pinwheel helper function: pixel index to radians
813+
static float getPinwheelAngle(int i, int vW, int vH) {
814+
int maxXY = max(vW, vH);
815+
if (maxXY <= Pinwheel_Size_Small) return float(i) * Int_to_Rad_Small;
816+
if (maxXY <= Pinwheel_Size_Medium) return float(i) * Int_to_Rad_Med;
817+
if (maxXY <= Pinwheel_Size_Big) return float(i) * Int_to_Rad_Big;
818+
// else
819+
return float(i) * Int_to_Rad_XL;
820+
}
821+
// Pinwheel helper function: matrix dimensions to number of rays
822+
static int getPinwheelLength(int vW, int vH) {
823+
int maxXY = max(vW, vH);
824+
if (maxXY <= Pinwheel_Size_Small) return Pinwheel_Steps_Small;
825+
if (maxXY <= Pinwheel_Size_Medium) return Pinwheel_Steps_Medium;
826+
if (maxXY <= Pinwheel_Size_Big) return Pinwheel_Steps_Big;
827+
// else
828+
return Pinwheel_Steps_XL;
829+
}
830+
#endif
804831

805832
// 1D strip
806833
uint16_t Segment::virtualLength() const {
@@ -831,12 +858,8 @@ uint16_t Segment::virtualLength() const {
831858
else
832859
vLen = max(vW,vH) * 0.5; // get the longest dimension
833860
break;
834-
case M12_sPinWheel: //WLEDMM
835-
//vLen = full circle
836-
if (max(vW,vH) <= Pinwheel_Size_Medium)
837-
vLen = Pinwheel_Steps_Medium;
838-
else
839-
vLen = Pinwheel_Steps_Big;
861+
case M12_sPinwheel:
862+
vLen = getPinwheelLength(vW, vH);
840863
break;
841864
}
842865
return vLen;
@@ -978,32 +1001,46 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
9781001
}
9791002
}
9801003
break;
981-
case M12_sPinWheel: { // WLEDMM
982-
// i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
1004+
case M12_sPinwheel: {
1005+
// i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small)
9831006
float centerX = roundf((vW-1) / 2.0f);
9841007
float centerY = roundf((vH-1) / 2.0f);
985-
// int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
986-
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
1008+
float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians
9871009
float cosVal = cosf(angleRad);
9881010
float sinVal = sinf(angleRad);
9891011

1012+
// avoid re-painting the same pixel
1013+
int lastX = INT_MIN; // impossible position
1014+
int lastY = INT_MIN; // impossible position
9901015
// draw line at angle, starting at center and ending at the segment edge
9911016
// we use fixed point math for better speed. Starting distance is 0.5 for better rounding
992-
constexpr int_fast32_t Fixed_Scale = 512; // fixpoint scaling factor
993-
int_fast32_t posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point
994-
int_fast32_t posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
995-
int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
996-
int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
1017+
// int_fast16_t and int_fast32_t types changed to int, minimum bits commented
1018+
int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
1019+
int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
1020+
int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
1021+
int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
9971022

9981023
int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
9991024
int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
1000-
// draw until we hit any edge
1001-
while ((posx > 0) && (posy > 0) && (posx < maxX) && (posy < maxY)) {
1025+
1026+
// Odd rays start further from center if prevRay started at center.
1027+
static int prevRay = INT_MIN; // previous ray number
1028+
if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) {
1029+
int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel
1030+
posx += inc_x * jump;
1031+
posy += inc_y * jump;
1032+
}
1033+
prevRay = i;
1034+
1035+
// draw ray until we hit any edge
1036+
while ((posx >= 0) && (posy >= 0) && (posx < maxX) && (posy < maxY)) {
10021037
// scale down to integer (compiler will replace division with appropriate bitshift)
10031038
int x = posx / Fixed_Scale;
10041039
int y = posy / Fixed_Scale;
10051040
// set pixel
1006-
setPixelColorXY(x, y, col);
1041+
if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different
1042+
lastX = x;
1043+
lastY = y;
10071044
// advance to next position
10081045
posx += inc_x;
10091046
posy += inc_y;
@@ -1154,16 +1191,36 @@ uint32_t Segment::getPixelColor(int i)
11541191
else
11551192
return getPixelColorXY(vW / 2, vH / 2 - i - 1);
11561193
break;
1157-
case M12_sPinWheel: //WLEDMM
1158-
// not 100% accurate, returns outer edge of circle
1159-
float distance = max(1.0f, min(vH-1, vW-1) / 2.0f);
1160-
float centerX = (vW - 1) / 2.0f;
1161-
float centerY = (vH - 1) / 2.0f;
1162-
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
1163-
int x = roundf(centerX + distance * cosf(angleRad));
1164-
int y = roundf(centerY + distance * sinf(angleRad));
1194+
case M12_sPinwheel:
1195+
// not 100% accurate, returns pixel at outer edge
1196+
// i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small)
1197+
float centerX = roundf((vW-1) / 2.0f);
1198+
float centerY = roundf((vH-1) / 2.0f);
1199+
float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians
1200+
float cosVal = cosf(angleRad);
1201+
float sinVal = sinf(angleRad);
1202+
1203+
int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
1204+
int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
1205+
int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
1206+
int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
1207+
int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
1208+
int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
1209+
1210+
// trace ray from center until we hit any edge - to avoid rounding problems, we use the same method as in setPixelColor
1211+
int x = INT_MIN;
1212+
int y = INT_MIN;
1213+
while ((posx >= 0) && (posy >= 0) && (posx < maxX) && (posy < maxY)) {
1214+
// scale down to integer (compiler will replace division with appropriate bitshift)
1215+
x = posx / Fixed_Scale;
1216+
y = posy / Fixed_Scale;
1217+
// advance to next position
1218+
posx += inc_x;
1219+
posy += inc_y;
1220+
}
11651221
return getPixelColorXY(x, y);
1166-
}
1222+
break;
1223+
}
11671224
return 0;
11681225
}
11691226
#endif

0 commit comments

Comments
 (0)