Skip to content

Commit 8a0de9a

Browse files
committed
Rename Wu pixel, add ellipse drawing
- fix "blur expansion" in PS
1 parent fdf772d commit 8a0de9a

File tree

5 files changed

+200
-70
lines changed

5 files changed

+200
-70
lines changed

wled00/FX.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3252,7 +3252,7 @@ uint16_t mode_exploding_fireworks(void)
32523252
// launch
32533253
if (flare->vel > 12 * gravity) {
32543254
// flare
3255-
if (is2D) SEGMENT.wu_pixel(uint32_t(flare->posX*255.f), uint32_t(((float)rows - flare->pos - 1.f)*255.f), CRGBA(flare->col, flare->col, flare->col));
3255+
if (is2D) SEGMENT.setWuPixelColor(uint32_t(flare->posX*255.f), uint32_t(((float)rows - flare->pos - 1.f)*255.f), CRGBA(flare->col, flare->col, flare->col));
32563256
else SEGMENT.setPixelColor((flare->posX > 0.0f) ? rows - int(flare->pos) - 1 : int(flare->pos), CRGBA(flare->col, flare->col, flare->col));
32573257
flare->pos += flare->vel;
32583258
flare->pos = constrain(flare->pos, 0, rows-1);
@@ -3317,7 +3317,7 @@ uint16_t mode_exploding_fireworks(void)
33173317
c.g = qsub8(c.g, cooling);
33183318
c.b = qsub8(c.b, cooling * 2);
33193319
}
3320-
if (is2D) SEGMENT.wu_pixel(uint32_t(sparks[i].posX*255.f), uint32_t(((float)rows - sparks[i].pos - 1.f)*255.f), c);
3320+
if (is2D) SEGMENT.setWuPixelColor(uint32_t(sparks[i].posX*255.f), uint32_t(((float)rows - sparks[i].pos - 1.f)*255.f), c);
33213321
else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c);
33223322
}
33233323
}
@@ -5625,7 +5625,7 @@ uint16_t mode_2Dghostrider(void) {
56255625
SEGMENT.fadeToBlackBy((SEGMENT.speed>>2)+64);
56265626

56275627
CRGBA color = ULTRAWHITE;
5628-
SEGMENT.wu_pixel(lighter->gPosX * 256 / 10, lighter->gPosY * 256 / 10, color);
5628+
SEGMENT.setWuPixelColor(lighter->gPosX * 256 / 10, lighter->gPosY * 256 / 10, color);
56295629

56305630
lighter->gPosX += lighter->Vspeed * sin_t(radians(lighter->gAngle));
56315631
lighter->gPosY += lighter->Vspeed * cos_t(radians(lighter->gAngle));
@@ -5653,7 +5653,7 @@ uint16_t mode_2Dghostrider(void) {
56535653
lighter->lightersPosX[i] += -7 * sin_t(radians(lighter->Angle[i]));
56545654
lighter->lightersPosY[i] += -7 * cos_t(radians(lighter->Angle[i]));
56555655
}
5656-
SEGMENT.wu_pixel(lighter->lightersPosX[i] * 256 / 10, lighter->lightersPosY[i] * 256 / 10, SEGMENT.color_from_palette((256 - lighter->time[i]), false, false, 255));
5656+
SEGMENT.setWuPixelColor(lighter->lightersPosX[i] * 256 / 10, lighter->lightersPosY[i] * 256 / 10, SEGMENT.color_from_palette((256 - lighter->time[i]), false, false, 255));
56575657
}
56585658
SEGMENT.blur(SEGMENT.intensity>>3);
56595659
}
@@ -5935,7 +5935,7 @@ uint16_t mode_2Ddriftrose(void) {
59355935
float angle = radians(i * 10);
59365936
uint32_t x = (CX + (sin_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f;
59375937
uint32_t y = (CY + (cos_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f;
5938-
SEGMENT.wu_pixel(x, y, SEGMENT.color_wheel(map(i, 1,37, 0,255)));
5938+
SEGMENT.setWuPixelColor(x, y, SEGMENT.color_wheel(map(i, 1,37, 0,255)));
59395939
}
59405940
if (SEGMENT.intensity>>4) SEGMENT.blur(SEGMENT.intensity>>4);
59415941

@@ -6740,13 +6740,13 @@ uint16_t mode_particlepit(void) {
67406740
PartSys->particles[i].y = (PartSys->maxY << 1); // particles appear somewhere above the matrix, maximum is double the height
67416741
PartSys->particles[i].vx = (int16_t)hw_random16(SEGMENT.speed >> 1) - (SEGMENT.speed >> 2); // side speed is +/-
67426742
PartSys->particles[i].vy = map(SEGMENT.speed, 0, 255, -5, -100); // downward speed
6743-
PartSys->particles[i].hue = hw_random16(); // set random color
6743+
PartSys->particles[i].hue = hw_random8(); // set random color
67446744
PartSys->particleFlags[i].collide = true; // enable collision for particle
67456745
PartSys->particles[i].sat = ((SEGMENT.custom3) << 3) + 7;
67466746
// set particle size
67476747
if (SEGMENT.custom1 == 255) {
67486748
PartSys->setParticleSize(1); // set global size to 1 for advanced rendering (no single pixel particles)
6749-
PartSys->advPartProps[i].size = hw_random16(SEGMENT.custom1); // set each particle to random size
6749+
PartSys->advPartProps[i].size = hw_random8(64,255); // set each particle to random size
67506750
} else {
67516751
PartSys->setParticleSize(SEGMENT.custom1); // set global size
67526752
PartSys->advPartProps[i].size = 0; // use global size

wled00/FX.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,12 +520,12 @@ class Segment {
520520

521521
inline CRGBA *getPixels() const { return pixels; }
522522
inline void setPixelColorRaw(unsigned i, CRGBA c) const { pixels[i] = c; }
523-
inline void addPixelColorRaw(unsigned i, CRGBA c) const { pixels[i] += c; }
523+
inline void addPixelColorRaw(unsigned i, CRGBA c) const { pixels[i] += c; } // somehow this crashes ESP
524524
inline void blendPixelColorRaw(unsigned i, CRGBA c, uint8_t b) const { pixels[i].nblend(c, b); }
525525
inline CRGBA getPixelColorRaw(unsigned i) const { return pixels[i]; };
526526
#ifndef WLED_DISABLE_2D
527527
inline void setPixelColorXYRaw(unsigned x, unsigned y, CRGBA c) const { auto XY = [](unsigned X, unsigned Y){ return X + Y*Segment::vWidth(); }; pixels[XY(x,y)] = c; }
528-
inline void addPixelColorXYRaw(unsigned x, unsigned y, CRGBA c) const { auto XY = [](unsigned X, unsigned Y){ return X + Y*Segment::vWidth(); }; pixels[XY(x,y)] += c; }
528+
inline void addPixelColorXYRaw(unsigned x, unsigned y, CRGBA c) const { auto XY = [](unsigned X, unsigned Y){ return X + Y*Segment::vWidth(); }; pixels[XY(x,y)] += c; } // somehow this crashes ESP
529529
inline void blendPixelColorXYRaw(unsigned x, unsigned y, CRGBA c, uint8_t b) const { auto XY = [](unsigned X, unsigned Y){ return X + Y*Segment::vWidth(); }; pixels[XY(x,y)].nblend(c, b); }
530530
inline CRGBA getPixelColorXYRaw(unsigned x, unsigned y) const { auto XY = [](unsigned X, unsigned Y){ return X + Y*Segment::vWidth(); }; return pixels[XY(x,y)]; };
531531
#endif
@@ -740,11 +740,12 @@ class Segment {
740740
void moveX(int delta, bool wrap = false) const;
741741
void moveY(int delta, bool wrap = false) const;
742742
void move(unsigned dir, unsigned delta, bool wrap = false) const;
743-
void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA c, bool soft = false) const;
744-
void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA c, bool soft = false) const;
743+
void drawCircle(uint16_t cx, uint16_t cy, uint16_t radius, CRGBA c, bool soft = false) const;
744+
void fillCircle(uint16_t cx, uint16_t cy, uint16_t radius, CRGBA c, bool soft = false) const;
745+
void drawEllipse(uint32_t cx, uint32_t cy, uint32_t rx, uint32_t ry, CRGBA color, bool fill = false, bool soft = false);
745746
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGBA c, bool soft = false) const;
746747
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGBA color, CRGBA col2 = 0, int8_t rotate = 0) const;
747-
void wu_pixel(uint32_t x, uint32_t y, CRGBA c) const;
748+
void setWuPixelColor(uint32_t x, uint32_t y, CRGBA c) const;
748749
#else
749750
inline bool is2D() const { return false; }
750751
inline void setPixelColorXY(int x, int y, CRGBA c) const { setPixelColor(x, c); }
@@ -771,7 +772,7 @@ class Segment {
771772
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA c, bool soft = false) {}
772773
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGBA c, bool soft = false) {}
773774
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGBA color, CRGBA = 0, int8_t = 0) {}
774-
inline void wu_pixel(uint32_t x, uint32_t y, CRGBA c) {}
775+
inline void setWuPixelColor(uint32_t x, uint32_t y, CRGBA c) {}
775776
#endif
776777

777778
friend class WS2812FX;

wled00/FX_2Dfcn.cpp

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ void Segment::move(unsigned dir, unsigned delta, bool wrap) const {
426426
}
427427
}
428428

429-
void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bool soft) const {
429+
void Segment::drawCircle(uint16_t cx, uint16_t cy, uint16_t radius, CRGBA col, bool soft) const {
430430
if (!isActive() || radius == 0) return; // not active
431431
if (soft) {
432432
// Xiaolin Wu’s algorithm
@@ -446,11 +446,11 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bo
446446
int dx = (i & 1) ? -1 : 1; // 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1
447447
int dy = (i & 2) ? -1 : 1; // 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1
448448
if (swaps) {
449-
px = cx + (y - adj) * dx;
450-
py = cy + x * dy;
449+
px = cx + (y - adj) * dx;
450+
py = cy + x * dy;
451451
} else {
452-
px = cx + x * dx;
453-
py = cy + (y - adj) * dy;
452+
px = cx + x * dx;
453+
py = cy + (y - adj) * dy;
454454
}
455455
if (px < 0 || py < 0 || px >= (int)vWidth() || py >= (int)vHeight()) continue;
456456
blendPixelColorXYRaw(px, py, col, (uint8_t)(adj ? fade : 255 - fade));
@@ -483,22 +483,95 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bo
483483
}
484484

485485
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
486-
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGBA col, bool soft) const {
486+
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint16_t radius, CRGBA col, bool soft) const {
487487
if (!isActive() || radius == 0) return; // not active
488488
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
489489
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
490490
// draw soft bounding circle
491491
if (soft) drawCircle(cx, cy, radius, col, soft);
492492
// fill it
493+
uint32_t rSq = radius * radius;
493494
for (int y = -radius; y <= radius; y++) {
494495
for (int x = -radius; x <= radius; x++) {
495-
if (x * x + y * y <= radius * radius &&
496+
if (x * x + y * y <= rSq &&
496497
int(cx)+x >= 0 && int(cy)+y >= 0 &&
497-
int(cx)+x < vW && int(cy)+y < vH)
498+
int(cx)+x < vW && int(cy)+y < vH) {
499+
col += getPixelColorXYRaw(cx + x, cy + y);
498500
setPixelColorXYRaw(cx + x, cy + y, col);
501+
}
502+
}
503+
}
504+
}
505+
506+
/*
507+
// see https://www.geeksforgeeks.org/dsa/midpoint-ellipse-drawing-algorithm/
508+
void Segment::drawEllipse(uint32_t cx, uint32_t cy, uint32_t rx, uint32_t ry, CRGBA color, bool fill, bool soft) {
509+
// all coodinates and radii are in 16.8 fixed point notation (use >> 8 to convert to pixel coordinates)
510+
if (!isActive()) return; // not active
511+
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
512+
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
513+
if (cx >= vW<<8 || cy >= vH<<8) return; // center outside segment
514+
int32_t rxSq = (rx * rx);
515+
int32_t rySq = (ry * ry);
516+
int32_t x = 0, y = ry;
517+
//auto fEllipse = [&](int32_t x, int32_t y) {
518+
// return (rySq * x * x) + (rxSq * y * y) - (rxSq * rySq);
519+
//};
520+
521+
// Region 1
522+
int32_t d1 = roundf((float)(rySq - (rxSq * ry)) + (0.25f * rxSq)); // initial decision parameter
523+
int32_t dx = 2 * rySq * x;
524+
int32_t dy = 2 * rxSq * y;
525+
526+
while (dx < dy) {
527+
if (fill) {
528+
drawLine((cx - x)>>8, (cy + y)>>8, (cx + x)>>8, (cy + y)>>8, color, false);
529+
drawLine((cx - x)>>8, (cy - y)>>8, (cx + x)>>8, (cy - y)>>8, color, false);
530+
} else {
531+
setWuPixelColor(cx - x, cy + y, color);
532+
setWuPixelColor(cx + x, cy + y, color);
533+
setWuPixelColor(cx - x, cy - y, color);
534+
setWuPixelColor(cx + x, cy - y, color);
535+
}
536+
if (d1 < 0) {
537+
x += 256; // increment x by 1 in 16.8 pixel notation
538+
dx += (2 * rySq);
539+
d1 += dx + rySq;
540+
} else {
541+
x += 256;
542+
y -= 256;
543+
dx += (2 * rySq);
544+
dy -= (2 * rxSq);
545+
d1 += dx - dy + rySq;
546+
}
547+
}
548+
549+
// Region 2
550+
int32_t d2 = (rxSq * ((x + 0.5f) * (x + 0.5f))) + (rxSq * ((y - 1) * (y - 1))) - (rxSq * rySq);
551+
while (y >= 0) {
552+
if (fill) {
553+
drawLine((cx - x)>>8, (cy + y)>>8, (cx + x)>>8, (cy + y)>>8, color, false);
554+
drawLine((cx - x)>>8, (cy - y)>>8, (cx + x)>>8, (cy - y)>>8, color, false);
555+
} else {
556+
setWuPixelColor(cx - x, cy + y, color);
557+
setWuPixelColor(cx + x, cy + y, color);
558+
setWuPixelColor(cx - x, cy - y, color);
559+
setWuPixelColor(cx + x, cy - y, color);
560+
}
561+
if (d2 > 0) {
562+
y -= 256;
563+
dy -= (2 * rxSq);
564+
d2 += rxSq - dy;
565+
} else {
566+
y -= 256;
567+
x += 256;
568+
dx += (2 * rySq);
569+
dy -= (2 * rxSq);
570+
d2 += dx - dy + rxSq;
499571
}
500572
}
501573
}
574+
*/
502575

503576
//line function
504577
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGBA c, bool soft) const {
@@ -605,7 +678,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
605678
// https://gist.github.com/sutaburosu/32a203c2efa2bb584f4b846a91066583#file-cakeday_hack-ino-L154
606679
// @param x 16.8 fixed point
607680
// @param y 16.8 fixed point
608-
void Segment::wu_pixel(uint32_t x, uint32_t y, CRGBA c) const {
681+
void Segment::setWuPixelColor(uint32_t x, uint32_t y, CRGBA c) const {
609682
if (!isActive()) return; // not active
610683
// extract the fractional parts and derive their inverses
611684
unsigned xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
@@ -616,10 +689,10 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGBA c) const {
616689
for (int i = 0; i < 4; i++) {
617690
int wu_x = (x >> 8) + (i & 1); // precalculate x
618691
int wu_y = (y >> 8) + ((i >> 1) & 1); // precalculate y
619-
CRGBA led = getPixelColorXY(wu_x, wu_y);
620-
c.a = wu[i]; // set alpha to weight
621-
led += c;
622-
setPixelColorXY(wu_x, wu_y, led);
692+
if (/*wu_x >= 0 && wu_y >= 0 && */wu_x < (int)vWidth() && wu_y < (int)vHeight()) {
693+
c.a = wu[i]; // set alpha to weight
694+
setPixelColorXYRaw(wu_x, wu_y, getPixelColorXYRaw(wu_x, wu_y).add(c, true)); // also modifies resulting opacity; should use addPixelColorXYRaw but that crashes ESP
695+
}
623696
}
624697
}
625698

0 commit comments

Comments
 (0)