Merge pull request #139 from MoonModules/upstream_patch_clusterf
AC minor patch cluster * Anti-Aliased Lines and Circles * replacing deprecated functions in ws.cpp * using global brightness in analogue clock overlay * fix for palette names (custom palettes) * bugfix for UI: when resizing the window, it always jumped to the Colors tab * UI: add webpage shortcuts for tabs
This commit is contained in:
@@ -76,7 +76,7 @@ private:
|
||||
bool sensorFound = false;
|
||||
|
||||
// Home Assistant and MQTT
|
||||
String mqttLuminanceTopic = FPSTR("");
|
||||
String mqttLuminanceTopic;
|
||||
bool mqttInitialized = false;
|
||||
bool HomeAssistantDiscovery = true; // Publish Home Assistant Discovery messages
|
||||
|
||||
|
||||
@@ -626,7 +626,7 @@ void MultiRelay::addToJsonInfo(JsonObject &root) {
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if ((_relay[i].pin<0 && !usePcf8574) || !_relay[i].external) continue;
|
||||
uiDomString = F("Relay "); uiDomString += i;
|
||||
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
||||
infoArr = user.createNestedArray(uiDomString); // timer value
|
||||
|
||||
uiDomString = F("<button class=\"btn btn-xs\" onclick=\"requestJson({");
|
||||
uiDomString += FPSTR(_name);
|
||||
|
||||
@@ -2551,7 +2551,7 @@ uint16_t ripple_base()
|
||||
uint16_t cx = rippleorigin >> 8;
|
||||
uint16_t cy = rippleorigin & 0xFF;
|
||||
uint8_t mag = scale8(sin8((propF>>2)), amp);
|
||||
if (propI > 0) SEGMENT.draw_circle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag));
|
||||
if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -6271,8 +6271,8 @@ uint16_t mode_2Dfloatingblobs(void) {
|
||||
}
|
||||
}
|
||||
uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0);
|
||||
if (blob->r[i] > 1.f) SEGMENT.fill_circle(blob->x[i], blob->y[i], roundf(blob->r[i]), c);
|
||||
else SEGMENT.setPixelColorXY(blob->x[i], blob->y[i], c);
|
||||
if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c);
|
||||
else SEGMENT.setPixelColorXY((int)roundf(blob->x[i]), (int)roundf(blob->y[i]), c);
|
||||
// move x
|
||||
if (blob->x[i] + blob->r[i] >= cols - 1) blob->x[i] += (blob->sX[i] * ((cols - 1 - blob->x[i]) / blob->r[i] + 0.005f));
|
||||
else if (blob->x[i] - blob->r[i] <= 0) blob->x[i] += (blob->sX[i] * (blob->x[i] / blob->r[i] + 0.005f));
|
||||
|
||||
53
wled00/FX.h
53
wled00/FX.h
@@ -122,6 +122,10 @@ bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.
|
||||
#define PURPLE (uint32_t)0x400080
|
||||
#define ORANGE (uint32_t)0xFF3000
|
||||
#define PINK (uint32_t)0xFF1493
|
||||
#define GREY (uint32_t)0x808080
|
||||
#define GRAY GREY
|
||||
#define DARKGREY (uint32_t)0x333333
|
||||
#define DARKGRAY DARKGREY
|
||||
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
|
||||
#define DARKSLATEGRAY (uint32_t)0x2F4F4F
|
||||
#define DARKSLATEGREY (uint32_t)0x2F4F4F
|
||||
@@ -614,11 +618,11 @@ typedef struct Segment {
|
||||
// 1D strip
|
||||
uint16_t virtualLength(void) const;
|
||||
void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
|
||||
void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline
|
||||
void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
|
||||
inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline
|
||||
inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
|
||||
void setPixelColor(float i, uint32_t c, bool aa = true);
|
||||
void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
||||
void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
||||
inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
uint32_t __attribute__((pure)) getPixelColor(int i); // WLEDMM attribute added
|
||||
// 1D support functions (some implement 2D as well)
|
||||
void blur(uint8_t, bool smear = false);
|
||||
@@ -626,10 +630,10 @@ typedef struct Segment {
|
||||
void fade_out(uint8_t r);
|
||||
void fadeToBlackBy(uint8_t fadeBy);
|
||||
void blendPixelColor(int n, uint32_t color, uint8_t blend);
|
||||
void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
void addPixelColor(int n, uint32_t color, bool fast = false);
|
||||
void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline
|
||||
void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline
|
||||
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline
|
||||
inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline
|
||||
void fadePixelColor(uint16_t n, uint8_t fade);
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
uint32_t __attribute__((pure)) color_from_palette(uint_fast16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255);
|
||||
@@ -665,6 +669,7 @@ typedef struct Segment {
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); }
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); }
|
||||
//#ifdef WLED_USE_AA_PIXELS
|
||||
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true, bool fast=true);
|
||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
|
||||
@@ -673,10 +678,10 @@ typedef struct Segment {
|
||||
uint32_t __attribute__((pure)) getPixelColorXY(int x, int y);
|
||||
// 2D support functions
|
||||
void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend);
|
||||
void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
void addPixelColorXY(int x, int y, uint32_t color, bool fast = false);
|
||||
void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } // automatically inline
|
||||
void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); }
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } // automatically inline
|
||||
inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); }
|
||||
void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade);
|
||||
void box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight)
|
||||
void blurRow(uint32_t row, fract8 blur_amount, bool smear = false);
|
||||
@@ -684,18 +689,20 @@ typedef struct Segment {
|
||||
void moveX(int8_t delta, bool wrap = false);
|
||||
void moveY(int8_t delta, bool wrap = false);
|
||||
void move(uint8_t dir, uint8_t delta, bool wrap = false);
|
||||
void draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
|
||||
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
|
||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
|
||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
|
||||
void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
||||
void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false);
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline
|
||||
void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0);
|
||||
void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // automatic inline
|
||||
inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // automatic inline
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0);
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline
|
||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||
void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
|
||||
//void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
|
||||
void blur2d(fract8 blur_amount) { blur(blur_amount); }
|
||||
void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
||||
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
||||
void nscale8(uint8_t scale);
|
||||
bool jsonToPixels(char *name, uint8_t fileNr); //WLEDMM for artifx
|
||||
#else
|
||||
@@ -704,6 +711,7 @@ typedef struct Segment {
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); }
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); }
|
||||
//#ifdef WLED_USE_AA_PIXELS
|
||||
inline void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) { setPixelColor(x, c, aa); }
|
||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
|
||||
@@ -722,9 +730,12 @@ typedef struct Segment {
|
||||
inline void moveX(int8_t delta, bool wrap = false) {}
|
||||
inline void moveY(int8_t delta, bool wrap = false) {}
|
||||
inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {}
|
||||
inline void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c) {}
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {}
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) {}
|
||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
|
||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
|
||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {}
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {}
|
||||
|
||||
@@ -427,56 +427,38 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
|
||||
}
|
||||
|
||||
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
|
||||
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { //WLEDMM: use fast types
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
const uint_fast16_t dim1 = vertical ? rows : cols;
|
||||
const uint_fast16_t dim2 = vertical ? cols : rows;
|
||||
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
const int dim1 = vertical ? rows : cols;
|
||||
const int dim2 = vertical ? cols : rows;
|
||||
if (i >= dim2) return;
|
||||
const float seep = blur_amount/255.f;
|
||||
const float keep = 3.f - 2.f*seep;
|
||||
// 1D box blur
|
||||
CRGB tmp[dim1];
|
||||
for (uint_fast16_t j = 0; j < dim1; j++) {
|
||||
uint_fast16_t x = vertical ? i : j;
|
||||
uint_fast16_t y = vertical ? j : i;
|
||||
int_fast16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
|
||||
int_fast16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
|
||||
uint_fast16_t xn = vertical ? x : x+1;
|
||||
uint_fast16_t yn = vertical ? y+1 : y;
|
||||
CRGB curr = getPixelColorXY(x,y);
|
||||
CRGB prev = (xp<0 || yp<0) ? CRGB::Black : getPixelColorXY(xp,yp);
|
||||
CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : getPixelColorXY(xn,yn);
|
||||
uint16_t r, g, b;
|
||||
r = (curr.r*keep + (prev.r + next.r)*seep) / 3;
|
||||
g = (curr.g*keep + (prev.g + next.g)*seep) / 3;
|
||||
b = (curr.b*keep + (prev.b + next.b)*seep) / 3;
|
||||
tmp[j] = CRGB(r,g,b);
|
||||
uint32_t out[dim1], in[dim1];
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
int x = vertical ? i : j;
|
||||
int y = vertical ? j : i;
|
||||
in[j] = getPixelColorXY(x, y);
|
||||
}
|
||||
for (uint_fast16_t j = 0; j < dim1; j++) {
|
||||
uint_fast16_t x = vertical ? i : j;
|
||||
uint_fast16_t y = vertical ? j : i;
|
||||
setPixelColorXY((int)x, (int)y, tmp[j]);
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
uint32_t curr = in[j];
|
||||
uint32_t prev = j > 0 ? in[j-1] : BLACK;
|
||||
uint32_t next = j < dim1-1 ? in[j+1] : BLACK;
|
||||
uint8_t r, g, b, w;
|
||||
r = (R(curr)*keep + (R(prev) + R(next))*seep) / 3;
|
||||
g = (G(curr)*keep + (G(prev) + G(next))*seep) / 3;
|
||||
b = (B(curr)*keep + (B(prev) + B(next))*seep) / 3;
|
||||
w = (W(curr)*keep + (W(prev) + W(next))*seep) / 3;
|
||||
out[j] = RGBW32(r,g,b,w);
|
||||
}
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
int x = vertical ? i : j;
|
||||
int y = vertical ? j : i;
|
||||
setPixelColorXY(x, y, out[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
|
||||
// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
|
||||
//
|
||||
// 0 = no spread at all
|
||||
// 64 = moderate spreading
|
||||
// 172 = maximum smooth, even spreading
|
||||
//
|
||||
// 173..255 = wider spreading, but increasing flicker
|
||||
//
|
||||
// Total light is NOT entirely conserved, so many repeated
|
||||
// calls to 'blur' will also result in the light fading,
|
||||
// eventually all the way to black; this is by design so that
|
||||
// it can be used to (slowly) clear the LEDs to black.
|
||||
|
||||
void Segment::blur1d(fract8 blur_amount) { //WLEDMM: use fast types
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
for (uint_fast16_t y = 0; y < rows; y++) blurRow(y, blur_amount);
|
||||
}
|
||||
|
||||
void Segment::moveX(int8_t delta, bool wrap) {
|
||||
@@ -533,37 +515,71 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
|
||||
}
|
||||
}
|
||||
|
||||
void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
if (!isActive()) return; // not active
|
||||
// Bresenham’s Algorithm
|
||||
int d = 3 - (2*radius);
|
||||
int y = radius, x = 0;
|
||||
while (y >= x) {
|
||||
setPixelColorXY(cx+x, cy+y, col);
|
||||
setPixelColorXY(cx-x, cy+y, col);
|
||||
setPixelColorXY(cx+x, cy-y, col);
|
||||
setPixelColorXY(cx-x, cy-y, col);
|
||||
setPixelColorXY(cx+y, cy+x, col);
|
||||
setPixelColorXY(cx-y, cy+x, col);
|
||||
setPixelColorXY(cx+y, cy-x, col);
|
||||
setPixelColorXY(cx-y, cy-x, col);
|
||||
x++;
|
||||
if (d > 0) {
|
||||
y--;
|
||||
d += 4 * (x - y) + 10;
|
||||
} else {
|
||||
d += 4 * x + 6;
|
||||
void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) {
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
if (soft) {
|
||||
// Xiaolin Wu’s algorithm
|
||||
int rsq = radius*radius;
|
||||
int x = 0;
|
||||
int y = radius;
|
||||
unsigned oldFade = 0;
|
||||
while (x < y) {
|
||||
float yf = sqrtf(float(rsq - x*x)); // needs to be floating point
|
||||
unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep
|
||||
if (oldFade > fade) y--;
|
||||
oldFade = fade;
|
||||
setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true));
|
||||
setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true));
|
||||
setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true));
|
||||
setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true));
|
||||
setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true));
|
||||
setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true));
|
||||
setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true));
|
||||
setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true));
|
||||
setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true));
|
||||
setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true));
|
||||
setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true));
|
||||
setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true));
|
||||
setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true));
|
||||
setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true));
|
||||
setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true));
|
||||
setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true));
|
||||
x++;
|
||||
}
|
||||
} else {
|
||||
// Bresenham’s Algorithm
|
||||
int d = 3 - (2*radius);
|
||||
int y = radius, x = 0;
|
||||
while (y >= x) {
|
||||
setPixelColorXY(cx+x, cy+y, col);
|
||||
setPixelColorXY(cx-x, cy+y, col);
|
||||
setPixelColorXY(cx+x, cy-y, col);
|
||||
setPixelColorXY(cx-x, cy-y, col);
|
||||
setPixelColorXY(cx+y, cy+x, col);
|
||||
setPixelColorXY(cx-y, cy+x, col);
|
||||
setPixelColorXY(cx+y, cy-x, col);
|
||||
setPixelColorXY(cx-y, cy-x, col);
|
||||
x++;
|
||||
if (d > 0) {
|
||||
y--;
|
||||
d += 4 * (x - y) + 10;
|
||||
} else {
|
||||
d += 4 * x + 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
||||
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (int16_t y = -radius; y <= radius; y++) {
|
||||
for (int16_t x = -radius; x <= radius; x++) {
|
||||
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) {
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
// draw soft bounding circle
|
||||
if (soft) drawCircle(cx, cy, radius, col, soft);
|
||||
// fill it
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
if (x * x + y * y <= radius * radius &&
|
||||
int16_t(cx)+x>=0 && int16_t(cy)+y>=0 &&
|
||||
int16_t(cx)+x<cols && int16_t(cy)+y<rows)
|
||||
@@ -582,20 +598,57 @@ void Segment::nscale8(uint8_t scale) { //WLEDMM: use fast types
|
||||
}
|
||||
|
||||
//line function
|
||||
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {
|
||||
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
|
||||
const int16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
|
||||
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
||||
int16_t err = (dx>dy ? dx : -dy)/2, e2;
|
||||
for (;;) {
|
||||
setPixelColorXY(x0,y0,c);
|
||||
if (x0==x1 && y0==y1) break;
|
||||
e2 = err;
|
||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
|
||||
const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; // x distance & step
|
||||
const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; // y distance & step
|
||||
|
||||
// single pixel (line length == 0)
|
||||
if (dx+dy == 0) {
|
||||
setPixelColorXY(x0, y0, c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (soft) {
|
||||
// Xiaolin Wu’s algorithm
|
||||
const bool steep = dy > dx;
|
||||
if (steep) {
|
||||
// we need to go along longest dimension
|
||||
std::swap(x0,y0);
|
||||
std::swap(x1,y1);
|
||||
}
|
||||
if (x0 > x1) {
|
||||
// we need to go in increasing fashion
|
||||
std::swap(x0,x1);
|
||||
std::swap(y0,y1);
|
||||
}
|
||||
float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0);
|
||||
float intersectY = y0;
|
||||
for (int x = x0; x <= x1; x++) {
|
||||
unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep
|
||||
unsigned seep = 0xFFFF - keep; // how much background to keep
|
||||
int y = int(intersectY);
|
||||
if (steep) std::swap(x,y); // temporarily swap if steep
|
||||
// pixel coverage is determined by fractional part of y co-ordinate
|
||||
setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true));
|
||||
setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true));
|
||||
intersectY += gradient;
|
||||
if (steep) std::swap(x,y); // restore if steep
|
||||
}
|
||||
} else {
|
||||
// Bresenham's algorithm
|
||||
int err = (dx>dy ? dx : -dy)/2; // error direction
|
||||
for (;;) {
|
||||
setPixelColorXY(x0, y0, c);
|
||||
if (x0==x1 && y0==y1) break;
|
||||
int e2 = err;
|
||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@ function onLoad()
|
||||
|
||||
selectSlot(0);
|
||||
updateTablinks(0);
|
||||
handleLocationHash();
|
||||
pmtLS = localStorage.getItem('wledPmt');
|
||||
|
||||
// Load initial data
|
||||
@@ -279,7 +280,6 @@ function updateTablinks(tabI)
|
||||
{
|
||||
var tablinks = gEBCN("tablinks");
|
||||
for (var i of tablinks) i.classList.remove('active');
|
||||
if (pcMode) return;
|
||||
tablinks[tabI].classList.add('active');
|
||||
}
|
||||
|
||||
@@ -290,6 +290,21 @@ function openTab(tabI, force = false)
|
||||
_C.classList.toggle('smooth', false);
|
||||
_C.style.setProperty('--i', iSlide);
|
||||
updateTablinks(tabI);
|
||||
switch (tabI) {
|
||||
case 0: window.location.hash = "Colors"; break;
|
||||
case 1: window.location.hash = "Effects"; break;
|
||||
case 2: window.location.hash = "Segments"; break;
|
||||
case 3: window.location.hash = "Presets"; break;
|
||||
}
|
||||
}
|
||||
|
||||
function handleLocationHash() {
|
||||
switch (window.location.hash) {
|
||||
case "#Colors": openTab(0); break;
|
||||
case "#Effects": openTab(1); break;
|
||||
case "#Segments": openTab(2); break;
|
||||
case "#Presets": openTab(3); break;
|
||||
}
|
||||
}
|
||||
|
||||
var timeout;
|
||||
@@ -3615,12 +3630,11 @@ function togglePcMode(fromB = false)
|
||||
if (fromB) {
|
||||
pcModeA = !pcModeA;
|
||||
localStorage.setItem('pcm', pcModeA);
|
||||
openTab(0, true);
|
||||
}
|
||||
pcMode = (wW >= 1024) && pcModeA;
|
||||
if (cpick) cpick.resize(pcMode && wW>1023 && wW<1250 ? 230 : 260); // for tablet in landscape
|
||||
if (!fromB && ((wW < 1024 && lastw < 1024) || (wW >= 1024 && lastw >= 1024))) return; // no change in size and called from size()
|
||||
openTab(0, true);
|
||||
updateTablinks(0);
|
||||
gId('buttonPcm').className = (pcMode) ? "active":"";
|
||||
gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto";
|
||||
sCol('--bh', gId('bot').clientHeight + "px");
|
||||
@@ -3652,6 +3666,7 @@ size();
|
||||
_C.style.setProperty('--n', N);
|
||||
|
||||
window.addEventListener('resize', size, true);
|
||||
window.addEventListener('hashchange', handleLocationHash);
|
||||
|
||||
_C.addEventListener('mousedown', lock, false);
|
||||
_C.addEventListener('touchstart', lock, false);
|
||||
|
||||
@@ -340,8 +340,8 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
seg.fill(BLACK); // WLEDMM why now?
|
||||
}
|
||||
|
||||
uint16_t start = 0, stop = 0;
|
||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
start = 0, stop = 0;
|
||||
set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
|
||||
for (size_t i = 0; i < iarr.size(); i++) {
|
||||
if(iarr[i].is<JsonInteger>()) {
|
||||
@@ -1554,10 +1554,20 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
|
||||
uint16_t used = strip.getLengthTotal();
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
char buffer[2000];
|
||||
strcpy_P(buffer, PSTR("{\"leds\":["));
|
||||
obuf = buffer;
|
||||
olen = 9;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (strip.isMatrix) {
|
||||
// ignore anything behid matrix (i.e. extra strip)
|
||||
used = Segment::maxWidth*Segment::maxHeight; // always the size of matrix (more or less than strip.getLengthTotal())
|
||||
n = 1;
|
||||
if (used > MAX_LIVE_LEDS) n = 2;
|
||||
if (used > MAX_LIVE_LEDS*4) n = 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
DynamicBuffer buffer(9 + (9*MAX_LIVE_LEDS) + 7 + 5 + 6 + 5 + 6 + 5 + 2);
|
||||
char* buf = buffer.data(); // assign buffer for oappnd() functions
|
||||
strncpy_P(buffer.data(), PSTR("{\"leds\":["), buffer.size());
|
||||
buf += 9; // sizeof(PSTR()) from last line
|
||||
|
||||
for (size_t i= 0; i < used; i += n)
|
||||
{
|
||||
@@ -1575,20 +1585,21 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
g = qadd8(w, G(c));
|
||||
b = qadd8(w, B(c));
|
||||
}
|
||||
olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
|
||||
buf += sprintf_P(buf, PSTR("\"%06X\","), RGBW32(r,g,b,0));
|
||||
}
|
||||
olen -= 1;
|
||||
oappend((const char*)F("],\"n\":"));
|
||||
oappendi(n);
|
||||
oappend("}");
|
||||
buf--; // remove last comma
|
||||
buf += sprintf_P(buf, PSTR("],\"n\":%d"), n);
|
||||
(*buf++) = '}';
|
||||
(*buf++) = 0;
|
||||
|
||||
if (request) {
|
||||
request->send(200, "application/json", buffer);
|
||||
request->send(200, "application/json", toString(std::move(buffer)));
|
||||
}
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
else {
|
||||
wsc->text(obuf, olen);
|
||||
wsc->text(toString(std::move(buffer)));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,11 +25,11 @@ void _overlayAnalogClock()
|
||||
{
|
||||
if (secondPixel < analogClock12pixel)
|
||||
{
|
||||
strip.setRange(analogClock12pixel, overlayMax, 0xFF0000);
|
||||
strip.setRange(overlayMin, secondPixel, 0xFF0000);
|
||||
strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, bri));
|
||||
strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, bri));
|
||||
} else
|
||||
{
|
||||
strip.setRange(analogClock12pixel, secondPixel, 0xFF0000);
|
||||
strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, bri));
|
||||
}
|
||||
}
|
||||
if (analogClock5MinuteMarks)
|
||||
@@ -38,12 +38,12 @@ void _overlayAnalogClock()
|
||||
{
|
||||
int pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i);
|
||||
if (pix > overlayMax) pix -= overlaySize;
|
||||
strip.setPixelColor(pix, 0x00FFAA);
|
||||
strip.setPixelColor(pix, color_fade(0x00FFAA, bri));
|
||||
}
|
||||
}
|
||||
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000);
|
||||
strip.setPixelColor(minutePixel, 0x00FF00);
|
||||
strip.setPixelColor(hourPixel, 0x0000FF);
|
||||
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, bri));
|
||||
strip.setPixelColor(minutePixel, color_fade(0x00FF00, bri));
|
||||
strip.setPixelColor(hourPixel, color_fade(0x0000FF, bri));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -267,8 +267,8 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) {
|
||||
snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode);
|
||||
if (src == JSON_palette_names && mode > (GRADIENT_PALETTE_COUNT + 13)) {
|
||||
snprintf_P(dest, maxLen, PSTR("~ Custom %d ~"), 255-mode);
|
||||
dest[maxLen-1] = '\0';
|
||||
return strlen(dest);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,6 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
{
|
||||
DEBUG_PRINTF("sendDataWs\n");
|
||||
if (!ws.count()) return;
|
||||
AsyncWebSocketMessageBuffer * buffer;
|
||||
|
||||
if (!requestJSONBufferLock(12)) {
|
||||
if (client) {
|
||||
@@ -138,17 +137,7 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
// DEBUG_PRINTF("%s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM
|
||||
#endif
|
||||
if (len < 1) return; // WLEDMM do not allocate 0 size buffer
|
||||
|
||||
// WLEDMM use exceptions to catch out-of-memory errors
|
||||
#if __cpp_exceptions
|
||||
try{
|
||||
buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes on ESP8266
|
||||
} catch(...) {
|
||||
buffer = nullptr;
|
||||
}
|
||||
#else
|
||||
buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes on ESP8266
|
||||
#endif
|
||||
AsyncWebSocketBuffer buffer(len);
|
||||
#ifdef ESP8266
|
||||
size_t heap2 = ESP.getFreeHeap();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
@@ -161,24 +150,19 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
USER_PRINTLN(F("WS buffer allocation failed."));
|
||||
ws.closeAll(1013); //code 1013 = temporary overload, try again later
|
||||
ws.cleanupClients(0); //disconnect all clients to release memory
|
||||
ws._cleanBuffers();
|
||||
errorFlag = ERR_LOW_WS_MEM;
|
||||
return; //out of memory
|
||||
}
|
||||
|
||||
buffer->lock();
|
||||
serializeJson(doc, (char *)buffer->get(), len);
|
||||
serializeJson(doc, (char *)buffer.data(), len);
|
||||
|
||||
DEBUG_PRINT(F("Sending WS data "));
|
||||
if (client) {
|
||||
client->text(buffer);
|
||||
client->text(std::move(buffer));
|
||||
DEBUG_PRINTLN(F("to a single client."));
|
||||
} else {
|
||||
ws.textAll(buffer);
|
||||
ws.textAll(std::move(buffer));
|
||||
DEBUG_PRINTLN(F("to multiple clients."));
|
||||
}
|
||||
buffer->unlock();
|
||||
ws._cleanBuffers();
|
||||
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
@@ -227,32 +211,21 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static"
|
||||
#endif
|
||||
size_t pos = (strip.isMatrix ? 4 : 2);
|
||||
size_t bufSize = pos + (used/n)*3;
|
||||
|
||||
if ((bufSize < 1) || (used < 1)) return(false); // WLEDMM should not happen
|
||||
//AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize);
|
||||
// WLEDMM protect against exceptions due to low memory
|
||||
AsyncWebSocketMessageBuffer * wsBuf = nullptr;
|
||||
#if __cpp_exceptions
|
||||
try{
|
||||
#endif
|
||||
wsBuf = ws.makeBuffer(bufSize);
|
||||
#if __cpp_exceptions
|
||||
} catch(...) {
|
||||
#else
|
||||
if (wsBuf == nullptr) { // 8266 does not support exceptions
|
||||
#endif
|
||||
wsBuf = nullptr;
|
||||
USER_PRINTLN(F("WS buffer allocation failed."));
|
||||
//ws.closeAll(1013); //code 1013 = temporary overload, try again later
|
||||
//ws.cleanupClients(0); //disconnect all clients to release memory
|
||||
ws._cleanBuffers();
|
||||
}
|
||||
|
||||
if (!wsBuf) return false; //out of memory
|
||||
uint8_t* buffer = wsBuf->get();
|
||||
if (!buffer) return false; //out of memory
|
||||
if ((bufSize < 1) || (used < 1)) return(false); // WLEDMM should not happen
|
||||
AsyncWebSocketBuffer wsBuf(bufSize);
|
||||
if (!wsBuf) {
|
||||
USER_PRINTLN(F("WS buffer allocation failed."));
|
||||
errorFlag = ERR_LOW_WS_MEM;
|
||||
return false; //out of memory
|
||||
}
|
||||
uint8_t* buffer = reinterpret_cast<uint8_t*>(wsBuf.data());
|
||||
if (!buffer) {
|
||||
USER_PRINTLN(F("WS buffer allocation failed."));
|
||||
errorFlag = ERR_LOW_WS_MEM;
|
||||
return false; //out of memory
|
||||
}
|
||||
|
||||
wsBuf->lock(); // protect buffer from being cleaned by another WS instance
|
||||
buffer[0] = 'L';
|
||||
buffer[1] = 1; //version
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@@ -290,9 +263,7 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static"
|
||||
}
|
||||
}
|
||||
|
||||
wsc->binary(wsBuf);
|
||||
wsBuf->unlock(); // un-protect buffer
|
||||
ws._cleanBuffers(); // cleans up if the message is not added to any clients.
|
||||
wsc->binary(std::move(wsBuf));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user