Merge pull request #3107 from Aircoookie/onepx-segment
Tweaks & bugfixes.
This commit is contained in:
commit
fb1999c474
@ -106,6 +106,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
static FourLineDisplayUsermod *instance;
|
||||
bool initDone = false;
|
||||
volatile bool drawing = false;
|
||||
volatile bool lockRedraw = false;
|
||||
|
||||
// HW interface & configuration
|
||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||
@ -198,25 +199,33 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) {
|
||||
if (type == NONE || !enabled) return;
|
||||
drawing = true;
|
||||
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
||||
if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string);
|
||||
else u8x8->drawString(col, row, string);
|
||||
drawing = false;
|
||||
}
|
||||
void draw2x2String(uint8_t col, uint8_t row, const char *string) {
|
||||
if (type == NONE || !enabled) return;
|
||||
drawing = true;
|
||||
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8->draw2x2String(col, row, string);
|
||||
drawing = false;
|
||||
}
|
||||
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) {
|
||||
if (type == NONE || !enabled) return;
|
||||
drawing = true;
|
||||
u8x8->setFont(font);
|
||||
if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph);
|
||||
else u8x8->drawGlyph(col, row, glyph);
|
||||
drawing = false;
|
||||
}
|
||||
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) {
|
||||
if (type == NONE || !enabled) return;
|
||||
drawing = true;
|
||||
u8x8->setFont(font);
|
||||
u8x8->draw2x2Glyph(col, row, glyph);
|
||||
drawing = false;
|
||||
}
|
||||
uint8_t getCols() {
|
||||
if (type==NONE || !enabled) return 0;
|
||||
@ -224,7 +233,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
void clear() {
|
||||
if (type == NONE || !enabled) return;
|
||||
drawing = true;
|
||||
u8x8->clear();
|
||||
drawing = false;
|
||||
}
|
||||
void setPowerSave(uint8_t save) {
|
||||
if (type == NONE || !enabled) return;
|
||||
@ -238,6 +249,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
|
||||
void draw2x2GlyphIcons() {
|
||||
drawing = true;
|
||||
if (lineHeight == 2) {
|
||||
drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon
|
||||
drawGlyph( 5, 0, 2, u8x8_4LineDisplay_WLED_icons_2x2, true); //speed icon
|
||||
@ -251,6 +263,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
drawGlyph(15, 2, 4, u8x8_4LineDisplay_WLED_icons_1x1); //palette icon
|
||||
drawGlyph(15, 3, 5, u8x8_4LineDisplay_WLED_icons_1x1); //effect icon
|
||||
}
|
||||
drawing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,8 +275,8 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
if (type == NONE || !enabled || !displayTurnedOff) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
drawing = true;
|
||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||
if (drawing) return;
|
||||
|
||||
char lineBuffer[LINE_BUFFER_SIZE];
|
||||
static byte lastSecond;
|
||||
@ -299,7 +312,23 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent);
|
||||
drawString(12, lineHeight*2+1, lineBuffer, true); // even with double sized rows print seconds in 1 line
|
||||
}
|
||||
drawing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable sleep (turn the display off) or clock mode.
|
||||
*/
|
||||
void sleepOrClock(bool enabled) {
|
||||
if (enabled) {
|
||||
displayTurnedOff = true;
|
||||
if (clockMode && ntpEnabled) {
|
||||
knownMinute = knownHour = 99;
|
||||
showTime();
|
||||
} else
|
||||
setPowerSave(1);
|
||||
} else {
|
||||
displayTurnedOff = false;
|
||||
setPowerSave(0);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -483,7 +512,8 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
}
|
||||
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
while (drawing && millis()-now < 25) delay(1); // wait if someone else is drawing
|
||||
if (drawing || lockRedraw) return;
|
||||
|
||||
if (apActive && WLED_WIFI_CONFIGURED && now<15000) {
|
||||
knownSsid = apSSID;
|
||||
@ -546,7 +576,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
|
||||
lastRedraw = now;
|
||||
|
||||
|
||||
// Turn the display back on
|
||||
wakeDisplay();
|
||||
|
||||
@ -580,44 +610,49 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
void updateBrightness() {
|
||||
knownBrightness = bri;
|
||||
if (overlayUntil == 0) {
|
||||
lockRedraw = true;
|
||||
brightness100 = ((uint16_t)bri*100)/255;
|
||||
char lineBuffer[4];
|
||||
sprintf_P(lineBuffer, PSTR("%-3d"), brightness100);
|
||||
drawString(1, lineHeight, lineBuffer);
|
||||
//lastRedraw = millis();
|
||||
lockRedraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
void updateSpeed() {
|
||||
knownEffectSpeed = effectSpeed;
|
||||
if (overlayUntil == 0) {
|
||||
lockRedraw = true;
|
||||
fxspeed100 = ((uint16_t)effectSpeed*100)/255;
|
||||
char lineBuffer[4];
|
||||
sprintf_P(lineBuffer, PSTR("%-3d"), fxspeed100);
|
||||
drawString(5, lineHeight, lineBuffer);
|
||||
//lastRedraw = millis();
|
||||
lockRedraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
void updateIntensity() {
|
||||
knownEffectIntensity = effectIntensity;
|
||||
if (overlayUntil == 0) {
|
||||
lockRedraw = true;
|
||||
fxintensity100 = ((uint16_t)effectIntensity*100)/255;
|
||||
char lineBuffer[4];
|
||||
sprintf_P(lineBuffer, PSTR("%-3d"), fxintensity100);
|
||||
drawString(9, lineHeight, lineBuffer);
|
||||
//lastRedraw = millis();
|
||||
lockRedraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
void drawStatusIcons() {
|
||||
uint8_t col = 15;
|
||||
uint8_t row = 0;
|
||||
lockRedraw = true;
|
||||
drawGlyph(col, row, (wificonnected ? 20 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // wifi icon
|
||||
if (lineHeight==2) { col--; } else { row++; }
|
||||
drawGlyph(col, row, (bri > 0 ? 9 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // power icon
|
||||
if (lineHeight==2) { col--; } else { col = row = 0; }
|
||||
drawGlyph(col, row, (nightlightActive ? 6 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // moon icon for nighlight mode
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,7 +667,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
|
||||
//Draw the arrow for the current setting beiong changed
|
||||
void drawArrow() {
|
||||
lockRedraw = true;
|
||||
if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1);
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
//Display the current effect or palette (desiredEntry)
|
||||
@ -640,6 +677,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
|
||||
char lineBuffer[MAX_JSON_CHARS];
|
||||
if (overlayUntil == 0) {
|
||||
lockRedraw = true;
|
||||
// Find the mode name in JSON
|
||||
uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1);
|
||||
if (lineBuffer[0]=='*' && lineBuffer[1]==' ') {
|
||||
@ -692,6 +730,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
smallBuffer3[smallChars3] = 0;
|
||||
drawString(1, row*lineHeight, smallBuffer3, true);
|
||||
}
|
||||
lockRedraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,12 +745,12 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
if (displayTurnedOff) {
|
||||
unsigned long now = millis();
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
drawing = true;
|
||||
if (drawing) return false;
|
||||
lockRedraw = true;
|
||||
clear();
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
//lastRedraw = millis();
|
||||
drawing = false;
|
||||
lockRedraw = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -724,8 +763,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
*/
|
||||
void overlay(const char* line1, long showHowLong, byte glyphType) {
|
||||
unsigned long now = millis();
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
drawing = true;
|
||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||
if (drawing) return;
|
||||
lockRedraw = true;
|
||||
// Turn the display back on
|
||||
if (!wakeDisplay()) clear();
|
||||
// Print the overlay
|
||||
@ -739,7 +779,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
drawString(0, (glyphType<255?3:0)*lineHeight, buf.c_str());
|
||||
}
|
||||
overlayUntil = millis() + showHowLong;
|
||||
drawing = false;
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -748,8 +788,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
*/
|
||||
void overlayLogo(long showHowLong) {
|
||||
unsigned long now = millis();
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
drawing = true;
|
||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||
if (drawing) return;
|
||||
lockRedraw = true;
|
||||
// Turn the display back on
|
||||
if (!wakeDisplay()) clear();
|
||||
// Print the overlay
|
||||
@ -799,7 +840,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
}
|
||||
overlayUntil = millis() + showHowLong;
|
||||
drawing = false;
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -809,8 +850,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
*/
|
||||
void overlay(const char* line1, const char* line2, long showHowLong) {
|
||||
unsigned long now = millis();
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
drawing = true;
|
||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||
if (drawing) return;
|
||||
lockRedraw = true;
|
||||
// Turn the display back on
|
||||
if (!wakeDisplay()) clear();
|
||||
// Print the overlay
|
||||
@ -825,13 +867,14 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
drawString(0, 2*lineHeight, buf.c_str());
|
||||
}
|
||||
overlayUntil = millis() + showHowLong;
|
||||
drawing = false;
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
void networkOverlay(const char* line1, long showHowLong) {
|
||||
unsigned long now = millis();
|
||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
||||
drawing = true;
|
||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||
if (drawing) return;
|
||||
lockRedraw = true;
|
||||
|
||||
String line;
|
||||
// Turn the display back on
|
||||
@ -863,27 +906,10 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
center(line, getCols());
|
||||
drawString(0, lineHeight*3, line.c_str());
|
||||
overlayUntil = millis() + showHowLong;
|
||||
drawing = false;
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable sleep (turn the display off) or clock mode.
|
||||
*/
|
||||
void sleepOrClock(bool enabled) {
|
||||
if (enabled) {
|
||||
displayTurnedOff = true;
|
||||
if (clockMode && ntpEnabled) {
|
||||
knownMinute = knownHour = 99;
|
||||
showTime();
|
||||
} else
|
||||
setPowerSave(1);
|
||||
} else {
|
||||
displayTurnedOff = false;
|
||||
setPowerSave(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handleButton() can be used to override default button behaviour. Returning true
|
||||
* will prevent button working in a default way.
|
||||
|
@ -124,7 +124,7 @@ uint16_t blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) {
|
||||
uint16_t mode_blink(void) {
|
||||
return blink(SEGCOLOR(0), SEGCOLOR(1), false, true);
|
||||
}
|
||||
static const char _data_FX_MODE_BLINK[] PROGMEM = "Blink@!,Duty cycle;!,!;!";
|
||||
static const char _data_FX_MODE_BLINK[] PROGMEM = "Blink@!,Duty cycle;!,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -133,7 +133,7 @@ static const char _data_FX_MODE_BLINK[] PROGMEM = "Blink@!,Duty cycle;!,!;!";
|
||||
uint16_t mode_blink_rainbow(void) {
|
||||
return blink(SEGMENT.color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), false, false);
|
||||
}
|
||||
static const char _data_FX_MODE_BLINK_RAINBOW[] PROGMEM = "Blink Rainbow@Frequency,Blink duration;!,!;!";
|
||||
static const char _data_FX_MODE_BLINK_RAINBOW[] PROGMEM = "Blink Rainbow@Frequency,Blink duration;!,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -142,7 +142,7 @@ static const char _data_FX_MODE_BLINK_RAINBOW[] PROGMEM = "Blink Rainbow@Frequen
|
||||
uint16_t mode_strobe(void) {
|
||||
return blink(SEGCOLOR(0), SEGCOLOR(1), true, true);
|
||||
}
|
||||
static const char _data_FX_MODE_STROBE[] PROGMEM = "Strobe@!;!,!;!";
|
||||
static const char _data_FX_MODE_STROBE[] PROGMEM = "Strobe@!;!,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -151,7 +151,7 @@ static const char _data_FX_MODE_STROBE[] PROGMEM = "Strobe@!;!,!;!";
|
||||
uint16_t mode_strobe_rainbow(void) {
|
||||
return blink(SEGMENT.color_wheel(SEGENV.call & 0xFF), SEGCOLOR(1), true, false);
|
||||
}
|
||||
static const char _data_FX_MODE_STROBE_RAINBOW[] PROGMEM = "Strobe Rainbow@!;,!;!";
|
||||
static const char _data_FX_MODE_STROBE_RAINBOW[] PROGMEM = "Strobe Rainbow@!;,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -350,7 +350,7 @@ uint16_t mode_breath(void) {
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_BREATH[] PROGMEM = "Breathe@!;!,!;!";
|
||||
static const char _data_FX_MODE_BREATH[] PROGMEM = "Breathe@!;!,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -366,7 +366,7 @@ uint16_t mode_fade(void) {
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_FADE[] PROGMEM = "Fade@!;!,!;!";
|
||||
static const char _data_FX_MODE_FADE[] PROGMEM = "Fade@!;!,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -754,7 +754,7 @@ uint16_t mode_multi_strobe(void) {
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!";
|
||||
static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -976,6 +976,7 @@ static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2,
|
||||
* Emulates a traffic light.
|
||||
*/
|
||||
uint16_t mode_traffic_light(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
for (int i=0; i < SEGLEN; i++)
|
||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
||||
uint32_t mdelay = 500;
|
||||
@ -1008,6 +1009,7 @@ static const char _data_FX_MODE_TRAFFIC_LIGHT[] PROGMEM = "Traffic Light@!,US st
|
||||
*/
|
||||
#define FLASH_COUNT 4
|
||||
uint16_t mode_chase_flash(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
|
||||
|
||||
for (int i = 0; i < SEGLEN; i++) {
|
||||
@ -1037,6 +1039,7 @@ static const char _data_FX_MODE_CHASE_FLASH[] PROGMEM = "Chase Flash@!;Bg,Fx;!";
|
||||
* Prim flashes running, followed by random color.
|
||||
*/
|
||||
uint16_t mode_chase_flash_random(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1);
|
||||
|
||||
for (int i = 0; i < SEGENV.aux1; i++) {
|
||||
@ -1170,6 +1173,7 @@ static const char _data_FX_MODE_DUAL_LARSON_SCANNER[] PROGMEM = "Scanner Dual@!,
|
||||
* Firing comets from one end. "Lighthouse"
|
||||
*/
|
||||
uint16_t mode_comet(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint16_t counter = strip.now * ((SEGMENT.speed >>2) +1);
|
||||
uint16_t index = (counter * SEGLEN) >> 16;
|
||||
if (SEGENV.call == 0) SEGENV.aux0 = index;
|
||||
@ -1197,7 +1201,8 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!"
|
||||
* Fireworks function.
|
||||
*/
|
||||
uint16_t mode_fireworks() {
|
||||
const uint16_t width = strip.isMatrix ? SEGMENT.virtualWidth() : SEGMENT.virtualLength();
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
const uint16_t width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength();
|
||||
const uint16_t height = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
@ -1211,18 +1216,18 @@ uint16_t mode_fireworks() {
|
||||
bool valid1 = (SEGENV.aux0 < width*height);
|
||||
bool valid2 = (SEGENV.aux1 < width*height);
|
||||
uint32_t sv1 = 0, sv2 = 0;
|
||||
if (valid1) sv1 = strip.isMatrix ? SEGMENT.getPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
|
||||
if (valid2) sv2 = strip.isMatrix ? SEGMENT.getPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width) : SEGMENT.getPixelColor(SEGENV.aux1);
|
||||
if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
|
||||
if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width) : SEGMENT.getPixelColor(SEGENV.aux1);
|
||||
if (!SEGENV.step) SEGMENT.blur(16);
|
||||
if (valid1) { if (strip.isMatrix) SEGMENT.setPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
|
||||
if (valid2) { if (strip.isMatrix) SEGMENT.setPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
|
||||
if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
|
||||
if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
|
||||
|
||||
for (int i=0; i<MAX(1, width/20); i++) {
|
||||
if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
|
||||
uint16_t index = random16(width*height);
|
||||
uint16_t j = index % width, k = index / width;
|
||||
uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0);
|
||||
if (strip.isMatrix) SEGMENT.setPixelColorXY(j, k, col);
|
||||
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(j, k, col);
|
||||
else SEGMENT.setPixelColor(index, col);
|
||||
SEGENV.aux1 = SEGENV.aux0; // old spark
|
||||
SEGENV.aux0 = index; // remember where spark occured
|
||||
@ -1234,8 +1239,8 @@ static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!;
|
||||
|
||||
|
||||
//Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h
|
||||
uint16_t mode_rain()
|
||||
{
|
||||
uint16_t mode_rain() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
const uint16_t width = SEGMENT.virtualWidth();
|
||||
const uint16_t height = SEGMENT.virtualHeight();
|
||||
SEGENV.step += FRAMETIME;
|
||||
@ -1294,7 +1299,7 @@ uint16_t mode_fire_flicker(void) {
|
||||
SEGENV.step = it;
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!";
|
||||
static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!;01";
|
||||
|
||||
|
||||
/*
|
||||
@ -1345,8 +1350,8 @@ static const char _data_FX_MODE_LOADING[] PROGMEM = "Loading@!,Fade;!,!;!;;ix=16
|
||||
|
||||
|
||||
//American Police Light with all LEDs Red and Blue
|
||||
uint16_t police_base(uint32_t color1, uint32_t color2)
|
||||
{
|
||||
uint16_t police_base(uint32_t color1, uint32_t color2) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint16_t delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster
|
||||
uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay);
|
||||
uint16_t offset = it % SEGLEN;
|
||||
@ -1794,9 +1799,9 @@ uint16_t mode_oscillate(void) {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i < SEGLEN; i++) {
|
||||
for (int i = 0; i < SEGLEN; i++) {
|
||||
uint32_t color = BLACK;
|
||||
for (int j=0; j < numOscillators; j++) {
|
||||
for (int j = 0; j < numOscillators; j++) {
|
||||
if(i >= oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
|
||||
color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128);
|
||||
}
|
||||
@ -1812,6 +1817,7 @@ static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate";
|
||||
|
||||
//TODO
|
||||
uint16_t mode_lightning(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
|
||||
uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
|
||||
uint8_t bri = 255/random8(1, 3);
|
||||
@ -1872,7 +1878,6 @@ uint16_t mode_pride_2015(void) {
|
||||
sPseudotime += duration * msmultiplier;
|
||||
sHue16 += duration * beatsin88( 400, 5,9);
|
||||
uint16_t brightnesstheta16 = sPseudotime;
|
||||
CRGB fastled_col;
|
||||
|
||||
for (int i = 0 ; i < SEGLEN; i++) {
|
||||
hue16 += hueinc16;
|
||||
@ -1898,6 +1903,7 @@ static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
|
||||
|
||||
//eight colored dots, weaving in and out of sync with each other
|
||||
uint16_t mode_juggle(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds(); //lossless getPixelColor()
|
||||
SEGMENT.fill(BLACK);
|
||||
@ -1967,6 +1973,7 @@ static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!;;c3=
|
||||
// feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used
|
||||
// in step 3 above) (Effect Intensity = Sparking).
|
||||
uint16_t mode_fire_2012() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
const uint16_t strips = SEGMENT.nrOfVStrips();
|
||||
if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed
|
||||
byte* heat = SEGENV.data;
|
||||
@ -2267,6 +2274,7 @@ static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!";
|
||||
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
|
||||
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
||||
uint16_t mode_meteor() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||
|
||||
byte* trail = SEGENV.data;
|
||||
@ -2304,6 +2312,7 @@ static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail length;!;!";
|
||||
// send a meteor from begining to to the end of the strip with a trail that randomly decays.
|
||||
// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain
|
||||
uint16_t mode_meteor_smooth() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||
|
||||
byte* trail = SEGENV.data;
|
||||
@ -2341,6 +2350,7 @@ static const char _data_FX_MODE_METEOR_SMOOTH[] PROGMEM = "Meteor Smooth@!,Trail
|
||||
|
||||
//Railway Crossing / Christmas Fairy lights
|
||||
uint16_t mode_railway() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint16_t dur = (256 - SEGMENT.speed) * 40;
|
||||
uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
|
||||
if (SEGENV.step > dur)
|
||||
@ -2441,6 +2451,7 @@ uint16_t ripple_base()
|
||||
|
||||
|
||||
uint16_t mode_ripple(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||
return ripple_base();
|
||||
}
|
||||
@ -2448,6 +2459,7 @@ static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,,,,,Overlay;
|
||||
|
||||
|
||||
uint16_t mode_ripple_rainbow(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (SEGENV.call ==0) {
|
||||
SEGENV.aux0 = random8();
|
||||
SEGENV.aux1 = random8();
|
||||
@ -2612,6 +2624,7 @@ static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rat
|
||||
//inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes
|
||||
uint16_t mode_halloween_eyes()
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
const uint16_t maxWidth = strip.isMatrix ? SEGMENT.virtualWidth() : SEGLEN;
|
||||
const uint16_t HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEGMENT.virtualWidth()>>4: SEGLEN>>5);
|
||||
const uint16_t HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2;
|
||||
@ -2721,6 +2734,7 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr
|
||||
|
||||
uint16_t spots_base(uint16_t threshold)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||
|
||||
uint16_t maxZones = SEGLEN >> 2;
|
||||
@ -2776,6 +2790,7 @@ typedef struct Ball {
|
||||
* Bouncing Balls Effect
|
||||
*/
|
||||
uint16_t mode_bouncing_balls(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
//allocate segment data
|
||||
const uint16_t strips = SEGMENT.nrOfVStrips(); // adapt for 2D
|
||||
const size_t maxNumBalls = 16;
|
||||
@ -2848,6 +2863,7 @@ static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravit
|
||||
* Sinelon stolen from FASTLED examples
|
||||
*/
|
||||
uint16_t sinelon_base(bool dual, bool rainbow=false) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
SEGMENT.fade_out(SEGMENT.intensity);
|
||||
uint16_t pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1);
|
||||
if (SEGENV.call == 0) SEGENV.aux0 = pos;
|
||||
@ -2945,6 +2961,7 @@ typedef struct Spark {
|
||||
* modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h
|
||||
*/
|
||||
uint16_t mode_popcorn(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
//allocate segment data
|
||||
uint16_t strips = SEGMENT.nrOfVStrips();
|
||||
uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
|
||||
@ -3087,7 +3104,7 @@ uint16_t mode_candle()
|
||||
{
|
||||
return candle(false);
|
||||
}
|
||||
static const char _data_FX_MODE_CANDLE[] PROGMEM = "Candle@!,!;!,!;!;1;sx=96,ix=224,pal=0";
|
||||
static const char _data_FX_MODE_CANDLE[] PROGMEM = "Candle@!,!;!,!;!;01;sx=96,ix=224,pal=0";
|
||||
|
||||
|
||||
uint16_t mode_candle_multi()
|
||||
@ -3118,6 +3135,7 @@ typedef struct particle {
|
||||
} star;
|
||||
|
||||
uint16_t mode_starburst(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
|
||||
uint8_t segs = strip.getActiveSegmentsNum();
|
||||
if (segs <= (strip.getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs
|
||||
@ -3237,6 +3255,7 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc
|
||||
*/
|
||||
uint16_t mode_exploding_fireworks(void)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
|
||||
const uint16_t rows = strip.isMatrix ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
|
||||
|
||||
@ -3371,6 +3390,7 @@ static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gr
|
||||
*/
|
||||
uint16_t mode_drip(void)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
//allocate segment data
|
||||
uint16_t strips = SEGMENT.nrOfVStrips();
|
||||
const int maxNumDrops = 4;
|
||||
@ -3466,6 +3486,7 @@ typedef struct Tetris {
|
||||
} tetris;
|
||||
|
||||
uint16_t mode_tetrix(void) {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint16_t strips = SEGMENT.nrOfVStrips(); // allow running on virtual strips (columns in 2D segment)
|
||||
uint16_t dataSize = sizeof(tetris);
|
||||
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
||||
@ -3508,7 +3529,7 @@ uint16_t mode_tetrix(void) {
|
||||
if (drop->pos > drop->stack) { // fall until top of stack
|
||||
drop->pos -= drop->speed; // may add gravity as: speed += gravity
|
||||
if (int(drop->pos) < int(drop->stack)) drop->pos = drop->stack;
|
||||
for (int i=int(drop->pos); i<SEGLEN; i++) {
|
||||
for (int i = int(drop->pos); i < SEGLEN; i++) {
|
||||
uint32_t col = i<int(drop->pos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1);
|
||||
SEGMENT.setPixelColor(indexToVStrip(i, stripNr), col);
|
||||
}
|
||||
@ -3523,7 +3544,7 @@ uint16_t mode_tetrix(void) {
|
||||
drop->brick = 0; // reset brick size (no more growing)
|
||||
if (drop->step > millis()) {
|
||||
// allow fading of virtual strip
|
||||
for (int i=0; i<SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend
|
||||
for (int i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend
|
||||
} else {
|
||||
drop->stack = 0; // reset brick stack size
|
||||
drop->step = 0; // proceed with next brick
|
||||
@ -3650,7 +3671,7 @@ uint16_t mode_heartbeat(void) {
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;;m12=1";
|
||||
static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;01;m12=1";
|
||||
|
||||
|
||||
// "Pacifica"
|
||||
@ -3774,6 +3795,7 @@ static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=5
|
||||
* Mode simulates a gradual sunrise
|
||||
*/
|
||||
uint16_t mode_sunrise() {
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
//speed 0 - static sun
|
||||
//speed 1 - 60: sunrise time in minutes
|
||||
//speed 60 - 120 : sunset time in minutes - 60;
|
||||
@ -3867,7 +3889,7 @@ static const char _data_FX_MODE_PHASEDNOISE[] PROGMEM = "Phased Noise@!,!;!,!;!"
|
||||
uint16_t mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
|
||||
random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
|
||||
|
||||
for (int i = 0; i<SEGLEN; i++) {
|
||||
for (int i = 0; i < SEGLEN; i++) {
|
||||
uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work.
|
||||
uint8_t pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed));
|
||||
if (random8() > SEGMENT.intensity) pixBri = 0;
|
||||
@ -3929,7 +3951,7 @@ uint16_t mode_sinewave(void) { // Adjustable sinewave. By Andrew Tul
|
||||
SEGENV.step += SEGMENT.speed/16; // Speed of animation.
|
||||
uint16_t freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal.
|
||||
|
||||
for (int i=0; i<SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows:
|
||||
for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows:
|
||||
int pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub)..
|
||||
//setPixCol(i, i*colorIndex/255, pixBri);
|
||||
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri));
|
||||
@ -3984,6 +4006,7 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver
|
||||
*/
|
||||
uint16_t mode_chunchun(void)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
SEGMENT.fade_out(254); // add a bit of trail
|
||||
uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4));
|
||||
uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
||||
@ -4035,6 +4058,7 @@ typedef struct Spotlight {
|
||||
*/
|
||||
uint16_t mode_dancing_shadows(void)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266
|
||||
bool initialize = SEGENV.aux0 != numSpotlights;
|
||||
SEGENV.aux0 = numSpotlights;
|
||||
@ -4161,7 +4185,7 @@ uint16_t mode_washing_machine(void) {
|
||||
|
||||
SEGENV.step += (speed * 128.0f);
|
||||
|
||||
for (int i=0; i<SEGLEN; i++) {
|
||||
for (int i = 0; i < SEGLEN; i++) {
|
||||
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
|
||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3));
|
||||
}
|
||||
@ -4498,7 +4522,7 @@ static const char _data_FX_MODE_AURORA[] PROGMEM = "Aurora@!,!;1,2,3;!;;sx=24,pa
|
||||
// 16 bit perlinmove. Use Perlin Noise instead of sinewaves for movement. By Andrew Tuline.
|
||||
// Controls are speed, # of pixels, faderate.
|
||||
uint16_t mode_perlinmove(void) {
|
||||
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
SEGMENT.fade_out(255-SEGMENT.custom1);
|
||||
for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) {
|
||||
uint16_t locn = inoise16(millis()*128/(260-SEGMENT.speed)+i*15000, millis()*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise.
|
||||
@ -6354,7 +6378,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
|
||||
SEGENV.aux0 = secondHand;
|
||||
|
||||
int pixBri = volumeRaw * SEGMENT.intensity / 64;
|
||||
for (int i=0; i<SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
|
||||
for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
|
||||
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0), pixBri));
|
||||
}
|
||||
|
||||
@ -6525,7 +6549,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline.
|
||||
plasmoip->thisphase += beatsin8(6,-4,4); // You can change direction and speed individually.
|
||||
plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline.
|
||||
|
||||
for (int i=0; i<SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows.
|
||||
for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows.
|
||||
// updated, similar to "plasma" effect - softhack007
|
||||
uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2;
|
||||
thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases.
|
||||
@ -7078,7 +7102,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
|
||||
} else {
|
||||
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude));
|
||||
}
|
||||
for (int i=0; i<SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
|
||||
for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
|
24
wled00/FX.h
24
wled00/FX.h
@ -72,7 +72,11 @@
|
||||
#ifndef MAX_NUM_SEGMENTS
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#define MAX_SEGMENT_DATA 32767
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define MAX_SEGMENT_DATA 24576
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA 32767
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* How much data bytes each segment should max allocate to leave enough space for other segments,
|
||||
@ -496,6 +500,9 @@ typedef struct Segment {
|
||||
inline bool isSelected(void) const { return selected; }
|
||||
inline bool isActive(void) const { return stop > start; }
|
||||
inline bool is2D(void) const { return (width()>1 && height()>1); }
|
||||
inline bool hasRGB(void) const { return _isRGB; }
|
||||
inline bool hasWhite(void) const { return _hasW; }
|
||||
inline bool isCCT(void) const { return _isCCT; }
|
||||
inline uint16_t width(void) const { return stop - start; } // segment width in physical pixels (length if 1D)
|
||||
inline uint16_t height(void) const { return stopY - startY; } // segment height (if 2D) in physical pixels
|
||||
inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels
|
||||
@ -711,7 +718,6 @@ class WS2812FX { // 96 bytes
|
||||
finalizeInit(),
|
||||
service(void),
|
||||
setMode(uint8_t segid, uint8_t m),
|
||||
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
setColor(uint8_t slot, uint32_t c),
|
||||
setCCT(uint16_t k),
|
||||
setBrightness(uint8_t b, bool direct = false),
|
||||
@ -728,7 +734,8 @@ class WS2812FX { // 96 bytes
|
||||
show(void),
|
||||
setTargetFps(uint8_t fps);
|
||||
|
||||
void fill(uint32_t c) { for (int i = 0; i < _length; i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||
void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
|
||||
void fill(uint32_t c) { for (int i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||
void addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp
|
||||
void setupEffectData(void); // add default effects to the list; defined in FX.cpp
|
||||
|
||||
@ -776,17 +783,17 @@ class WS2812FX { // 96 bytes
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
getLengthPhysical(void),
|
||||
getLengthTotal(void), // will include virtual/nonexistent pixels in matrix
|
||||
getFps();
|
||||
|
||||
inline uint16_t getFrameTime(void) { return _frametime; }
|
||||
inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; }
|
||||
inline uint16_t getLengthTotal(void) { return _length; }
|
||||
inline uint16_t getLength(void) { return _length; } // 2D matrix may have less pixels than W*H
|
||||
inline uint16_t getTransition(void) { return _transitionDur; }
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase,
|
||||
currentColor(uint32_t colorNew, uint8_t tNr),
|
||||
getPixelColor(uint16_t);
|
||||
|
||||
inline uint32_t getLastShow(void) { return _lastShow; }
|
||||
@ -826,6 +833,13 @@ class WS2812FX { // 96 bytes
|
||||
bool serpentine : 1; // is serpentine?
|
||||
};
|
||||
};
|
||||
panel_t()
|
||||
: xOffset(0)
|
||||
, yOffset(0)
|
||||
, width(8)
|
||||
, height(8)
|
||||
, options(0)
|
||||
{}
|
||||
} Panel;
|
||||
std::vector<Panel> panel;
|
||||
#endif
|
||||
|
@ -156,17 +156,16 @@ void WS2812FX::setUpMatrix() {
|
||||
}
|
||||
|
||||
// absolute matrix version of setPixelColor()
|
||||
void IRAM_ATTR WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
|
||||
void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (!isMatrix) return; // not a matrix set-up
|
||||
uint16_t index = y * Segment::maxWidth + x;
|
||||
if (index >= customMappingSize) return;
|
||||
#else
|
||||
uint16_t index = x;
|
||||
if (index >= _length) return;
|
||||
#endif
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
if (index >= _length) return;
|
||||
busses.setPixelColor(index, col);
|
||||
}
|
||||
|
||||
@ -174,12 +173,11 @@ void IRAM_ATTR WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
|
||||
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t index = (y * Segment::maxWidth + x);
|
||||
if (index >= customMappingSize) return 0; // customMappingSize is always W * H of matrix in 2D setup
|
||||
#else
|
||||
uint16_t index = x;
|
||||
if (index >= _length) return 0;
|
||||
#endif
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
if (index >= _length) return 0;
|
||||
return busses.getPixelColor(index);
|
||||
}
|
||||
|
||||
@ -190,13 +188,13 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||
uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y) {
|
||||
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
|
||||
uint16_t width = virtualWidth(); // segment width in logical pixels
|
||||
uint16_t height = virtualHeight(); // segment height in logical pixels
|
||||
return (x%width) + (y%height) * width;
|
||||
}
|
||||
|
||||
void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
|
@ -81,7 +81,7 @@ uint16_t Segment::maxHeight = 1;
|
||||
// copy constructor
|
||||
Segment::Segment(const Segment &orig) {
|
||||
//DEBUG_PRINTLN(F("-- Copy segment constructor --"));
|
||||
memcpy(this, &orig, sizeof(Segment));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
@ -96,7 +96,7 @@ Segment::Segment(const Segment &orig) {
|
||||
// move constructor
|
||||
Segment::Segment(Segment &&orig) noexcept {
|
||||
//DEBUG_PRINTLN(F("-- Move segment constructor --"));
|
||||
memcpy(this, &orig, sizeof(Segment));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
@ -114,7 +114,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
if (leds && !Segment::_globalLeds) free(leds);
|
||||
deallocateData();
|
||||
// copy source
|
||||
memcpy(this, &orig, sizeof(Segment));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
// erase pointers to allocated data
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
@ -138,7 +138,7 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
deallocateData(); // free old runtime data
|
||||
if (_t) delete _t;
|
||||
if (leds && !Segment::_globalLeds) free(leds);
|
||||
memcpy(this, &orig, sizeof(Segment));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
@ -184,7 +184,8 @@ void Segment::deallocateData() {
|
||||
void Segment::resetIfRequired() {
|
||||
if (reset) {
|
||||
if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
|
||||
//if (_t) { delete _t; _t = nullptr; transitional = false; }
|
||||
if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
||||
deallocateData();
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
reset = false; // setOption(SEG_OPTION_RESET, false);
|
||||
}
|
||||
@ -415,6 +416,10 @@ void Segment::set(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t o
|
||||
|
||||
bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || c == colors[slot]) return false;
|
||||
if (!_isRGB && !_hasW) {
|
||||
if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black
|
||||
if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black
|
||||
}
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
||||
colors[slot] = c;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
@ -546,7 +551,9 @@ uint16_t Segment::virtualLength() const {
|
||||
|
||||
void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D
|
||||
int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
|
||||
#endif
|
||||
i &= 0xFFFF;
|
||||
|
||||
if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit
|
||||
@ -686,7 +693,9 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
||||
|
||||
uint32_t Segment::getPixelColor(int i)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D
|
||||
int vStrip = i>>16;
|
||||
#endif
|
||||
i &= 0xFFFF;
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -762,6 +771,7 @@ void Segment::refreshLightCapabilities() {
|
||||
if (segStartIdx > index) segStartIdx = index;
|
||||
if (segStopIdx < index) segStopIdx = index;
|
||||
}
|
||||
if (segStartIdx == segStopIdx) segStopIdx++; // we only have 1 pixel segment
|
||||
}
|
||||
} else {
|
||||
// we are on the strip located after the matrix
|
||||
@ -1043,7 +1053,7 @@ void WS2812FX::finalizeInit(void)
|
||||
Segment::_globalLeds = nullptr;
|
||||
}
|
||||
if (useLedsArray) {
|
||||
size_t arrSize = sizeof(CRGB) * MAX(_length, Segment::maxWidth*Segment::maxHeight);
|
||||
size_t arrSize = sizeof(CRGB) * getLengthTotal();
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound())
|
||||
Segment::_globalLeds = (CRGB*) ps_malloc(arrSize);
|
||||
@ -1117,15 +1127,15 @@ void WS2812FX::service() {
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col)
|
||||
{
|
||||
if (i >= _length) return;
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
if (i >= _length) return;
|
||||
busses.setPixelColor(i, col);
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
{
|
||||
if (i >= _length) return 0;
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
if (i >= _length) return 0;
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
@ -1338,6 +1348,12 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) {
|
||||
return c;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthTotal(void) {
|
||||
uint16_t len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D
|
||||
if (isMatrix && _length > len) len = _length; // for 2D with trailing strip
|
||||
return len;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
uint16_t len = 0;
|
||||
for (size_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
@ -1380,7 +1396,6 @@ void WS2812FX::purgeSegments(bool force) {
|
||||
if (_segments.size() <= 1) return;
|
||||
for (size_t i = _segments.size()-1; i > 0; i--)
|
||||
if (_segments[i].stop == 0 || force) {
|
||||
DEBUG_PRINT(F("Purging segment segment: ")); DEBUG_PRINTLN(i);
|
||||
deleted++;
|
||||
_segments.erase(_segments.begin() + i);
|
||||
}
|
||||
@ -1415,45 +1430,31 @@ void WS2812FX::resetSegments() {
|
||||
}
|
||||
|
||||
void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
if (isMatrix) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// only create 1 2D segment
|
||||
if (forceReset || getSegmentsNum() == 0) resetSegments(); // initialises 1 segment
|
||||
else if (getActiveSegmentsNum() == 1) {
|
||||
size_t i = getLastActiveSegmentId();
|
||||
_segments[i].start = 0;
|
||||
_segments[i].stop = Segment::maxWidth;
|
||||
_segments[i].startY = 0;
|
||||
_segments[i].stopY = Segment::maxHeight;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].spacing = 0;
|
||||
_mainSegment = i;
|
||||
}
|
||||
// do we have LEDs after the matrix? (ignore buses)
|
||||
if (autoSegments && _length > Segment::maxWidth*Segment::maxHeight /*&& getActiveSegmentsNum() == 2*/) {
|
||||
if (_segments.size() == getLastActiveSegmentId()+1U) {
|
||||
_segments.push_back(Segment(Segment::maxWidth*Segment::maxHeight, _length));
|
||||
} else {
|
||||
size_t i = getLastActiveSegmentId() + 1;
|
||||
_segments[i].start = Segment::maxWidth*Segment::maxHeight;
|
||||
_segments[i].stop = _length;
|
||||
_segments[i].startY = 0;
|
||||
_segments[i].stopY = 1;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].spacing = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (autoSegments) { //make one segment per bus
|
||||
if (autoSegments) { //make one segment per bus
|
||||
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
|
||||
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
|
||||
uint8_t s = 0;
|
||||
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
||||
size_t s = 0;
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D segment is the 1st one using entire matrix
|
||||
if (isMatrix) {
|
||||
segStarts[0] = 0;
|
||||
segStops[0] = Segment::maxWidth*Segment::maxHeight;
|
||||
s++;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = s; i < busses.getNumBusses(); i++) {
|
||||
Bus* b = busses.getBus(i);
|
||||
|
||||
segStarts[s] = b->getStart();
|
||||
segStops[s] = segStarts[s] + b->getLength();
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (isMatrix && segStops[s] < Segment::maxWidth*Segment::maxHeight) continue; // ignore buses comprising matrix
|
||||
if (isMatrix && segStarts[s] < Segment::maxWidth*Segment::maxHeight) segStarts[s] = Segment::maxWidth*Segment::maxHeight;
|
||||
#endif
|
||||
|
||||
//check for overlap with previous segments
|
||||
for (size_t j = 0; j < s; j++) {
|
||||
if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
|
||||
@ -1465,24 +1466,40 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
_segments.clear();
|
||||
_segments.reserve(s); // prevent reallocations
|
||||
for (size_t i = 0; i < s; i++) {
|
||||
Segment seg = Segment(segStarts[i], segStops[i]);
|
||||
seg.selected = true;
|
||||
_segments.push_back(seg);
|
||||
// there is always at least one segment (but we need to differentiate between 1D and 2D)
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (isMatrix)
|
||||
_segments.push_back(Segment(0, Segment::maxWidth, 0, Segment::maxHeight));
|
||||
else
|
||||
#endif
|
||||
_segments.push_back(Segment(segStarts[0], segStops[0]));
|
||||
for (size_t i = 1; i < s; i++) {
|
||||
_segments.push_back(Segment(segStarts[i], segStops[i]));
|
||||
}
|
||||
_mainSegment = 0;
|
||||
|
||||
} else {
|
||||
|
||||
if (forceReset || getSegmentsNum() == 0) resetSegments();
|
||||
//expand the main seg to the entire length, but only if there are no other segments, or reset is forced
|
||||
else if (getActiveSegmentsNum() == 1) {
|
||||
size_t i = getLastActiveSegmentId();
|
||||
#ifndef WLED_DISABLE_2D
|
||||
_segments[i].start = 0;
|
||||
_segments[i].stop = Segment::maxWidth;
|
||||
_segments[i].startY = 0;
|
||||
_segments[i].stopY = Segment::maxHeight;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].spacing = 0;
|
||||
#else
|
||||
_segments[i].start = 0;
|
||||
_segments[i].stop = _length;
|
||||
_mainSegment = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
_mainSegment = 0;
|
||||
|
||||
fixInvalidSegments();
|
||||
}
|
||||
@ -1561,7 +1578,8 @@ void WS2812FX::printSize() {
|
||||
DEBUG_PRINTF("Modes: %d*%d=%uB\n", sizeof(mode_ptr), _mode.size(), (_mode.capacity()*sizeof(mode_ptr)));
|
||||
DEBUG_PRINTF("Data: %d*%d=%uB\n", sizeof(const char *), _modeData.size(), (_modeData.capacity()*sizeof(const char *)));
|
||||
DEBUG_PRINTF("Map: %d*%d=%uB\n", sizeof(uint16_t), (int)customMappingSize, customMappingSize*sizeof(uint16_t));
|
||||
if (useLedsArray) DEBUG_PRINTF("Buffer: %d*%d=%uB\n", sizeof(CRGB), (int)_length, _length*sizeof(CRGB));
|
||||
size = getLengthTotal();
|
||||
if (useLedsArray) DEBUG_PRINTF("Buffer: %d*%u=%uB\n", sizeof(CRGB), size, size*sizeof(CRGB));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -361,7 +361,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
uint8_t b = B(c);
|
||||
uint8_t w = W(c);
|
||||
|
||||
_data = bool((r+g+b+w) && _bri) ? 0xFF : 0;
|
||||
_data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) {
|
||||
|
@ -57,39 +57,42 @@ void setRandomColor(byte* rgb)
|
||||
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||
{
|
||||
float h = ((float)hue)/65535.0;
|
||||
float s = ((float)sat)/255.0;
|
||||
byte i = floor(h*6);
|
||||
float f = h * 6-i;
|
||||
float p = 255 * (1-s);
|
||||
float q = 255 * (1-f*s);
|
||||
float t = 255 * (1-(1-f)*s);
|
||||
float h = ((float)hue)/65535.0f;
|
||||
float s = ((float)sat)/255.0f;
|
||||
int i = floorf(h*6);
|
||||
float f = h * 6.0f - i;
|
||||
int p = int(255.0f * (1.0f-s));
|
||||
int q = int(255.0f * (1.0f-f*s));
|
||||
int t = int(255.0f * (1.0f-(1.0f-f)*s));
|
||||
p = constrain(p, 0, 255);
|
||||
q = constrain(q, 0, 255);
|
||||
t = constrain(t, 0, 255);
|
||||
switch (i%6) {
|
||||
case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break;
|
||||
case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break;
|
||||
case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break;
|
||||
case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break;
|
||||
case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
|
||||
case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
|
||||
case 0: rgb[0]=255,rgb[1]=t, rgb[2]=p; break;
|
||||
case 1: rgb[0]=q, rgb[1]=255,rgb[2]=p; break;
|
||||
case 2: rgb[0]=p, rgb[1]=255,rgb[2]=t; break;
|
||||
case 3: rgb[0]=p, rgb[1]=q, rgb[2]=255;break;
|
||||
case 4: rgb[0]=t, rgb[1]=p, rgb[2]=255;break;
|
||||
case 5: rgb[0]=255,rgb[1]=p, rgb[2]=q; break;
|
||||
}
|
||||
}
|
||||
|
||||
//get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc
|
||||
{
|
||||
float r = 0, g = 0, b = 0;
|
||||
float temp = kelvin / 100;
|
||||
if (temp <= 66) {
|
||||
int r = 0, g = 0, b = 0;
|
||||
float temp = kelvin / 100.0f;
|
||||
if (temp <= 66.0f) {
|
||||
r = 255;
|
||||
g = round(99.4708025861 * log(temp) - 161.1195681661);
|
||||
if (temp <= 19) {
|
||||
g = roundf(99.4708025861f * logf(temp) - 161.1195681661f);
|
||||
if (temp <= 19.0f) {
|
||||
b = 0;
|
||||
} else {
|
||||
b = round(138.5177312231 * log((temp - 10)) - 305.0447927307);
|
||||
b = roundf(138.5177312231f * logf((temp - 10.0f)) - 305.0447927307f);
|
||||
}
|
||||
} else {
|
||||
r = round(329.698727446 * pow((temp - 60), -0.1332047592));
|
||||
g = round(288.1221695283 * pow((temp - 60), -0.0755148492));
|
||||
r = roundf(329.698727446f * powf((temp - 60.0f), -0.1332047592f));
|
||||
g = roundf(288.1221695283f * powf((temp - 60.0f), -0.0755148492f));
|
||||
b = 255;
|
||||
}
|
||||
//g += 12; //mod by Aircoookie, a bit less accurate but visibly less pinkish
|
||||
@ -147,9 +150,9 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
|
||||
b = 1.0f;
|
||||
}
|
||||
// Apply gamma correction
|
||||
r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * pow(r, (1.0f / 2.4f)) - 0.055f;
|
||||
g = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * pow(g, (1.0f / 2.4f)) - 0.055f;
|
||||
b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * pow(b, (1.0f / 2.4f)) - 0.055f;
|
||||
r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * powf(r, (1.0f / 2.4f)) - 0.055f;
|
||||
g = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * powf(g, (1.0f / 2.4f)) - 0.055f;
|
||||
b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * powf(b, (1.0f / 2.4f)) - 0.055f;
|
||||
|
||||
if (r > b && r > g) {
|
||||
// red is biggest
|
||||
@ -173,9 +176,9 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
|
||||
b = 1.0f;
|
||||
}
|
||||
}
|
||||
rgb[0] = 255.0*r;
|
||||
rgb[1] = 255.0*g;
|
||||
rgb[2] = 255.0*b;
|
||||
rgb[0] = byte(255.0f*r);
|
||||
rgb[1] = byte(255.0f*g);
|
||||
rgb[2] = byte(255.0f*b);
|
||||
}
|
||||
|
||||
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
|
||||
@ -242,35 +245,13 @@ float maxf (float v, float w)
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
uint32_t colorRGBtoRGBW(uint32_t c)
|
||||
{
|
||||
byte rgb[4];
|
||||
rgb[0] = R(c);
|
||||
rgb[1] = G(c);
|
||||
rgb[2] = B(c);
|
||||
rgb[3] = W(c);
|
||||
colorRGBtoRGBW(rgb);
|
||||
return RGBW32(rgb[0], rgb[1], rgb[2], rgb[3]);
|
||||
}
|
||||
|
||||
void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_MODE_LEGACY)
|
||||
{
|
||||
float low = minf(rgb[0],minf(rgb[1],rgb[2]));
|
||||
float high = maxf(rgb[0],maxf(rgb[1],rgb[2]));
|
||||
if (high < 0.1f) return;
|
||||
float sat = 100.0f * ((high - low) / high); // maximum saturation is 100 (corrected from 255)
|
||||
rgb[3] = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
|
||||
}
|
||||
*/
|
||||
|
||||
byte correctionRGB[4] = {0,0,0,0};
|
||||
uint16_t lastKelvin = 0;
|
||||
|
||||
// adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance)
|
||||
// called from bus manager when color correction is enabled!
|
||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb)
|
||||
{
|
||||
//remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor()
|
||||
static byte correctionRGB[4] = {0,0,0,0};
|
||||
static uint16_t lastKelvin = 0;
|
||||
if (lastKelvin != kelvin) colorKtoRGB(kelvin, correctionRGB); // convert Kelvin to RGB
|
||||
lastKelvin = kelvin;
|
||||
byte rgbw[4];
|
||||
|
@ -404,8 +404,8 @@
|
||||
#define JSON_BUFFER_SIZE 24576
|
||||
#endif
|
||||
|
||||
//#define MIN_HEAP_SIZE (MAX_LED_MEMORY+2048)
|
||||
#define MIN_HEAP_SIZE (8192)
|
||||
//#define MIN_HEAP_SIZE (8k for AsyncWebServer)
|
||||
#define MIN_HEAP_SIZE 8192
|
||||
|
||||
// Maximum size of node map (list of other WLED instances)
|
||||
#ifdef ESP8266
|
||||
|
@ -392,12 +392,16 @@ button {
|
||||
}
|
||||
|
||||
.slider {
|
||||
background-color: var(--c-2);
|
||||
max-width: 300px;
|
||||
min-width: 280px;
|
||||
min-width: 260px;
|
||||
margin: 0 auto; /* add 5px; if you want some vertical space but looks ugly */
|
||||
border-radius: 24px;
|
||||
position: relative;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
#sliders .slider, #info .slider {
|
||||
background-color: var(--c-2);
|
||||
}
|
||||
|
||||
.filter, .option {
|
||||
@ -425,14 +429,14 @@ button {
|
||||
box-shadow: 4px 4px 10px 4px var(--c-1);
|
||||
color: var(--c-f);
|
||||
text-align: center;
|
||||
padding: 5px 10px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
|
||||
/* Position the tooltip text */
|
||||
width: 160px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 100%;
|
||||
bottom: 80%;
|
||||
left: 50%;
|
||||
margin-left: -92px;
|
||||
|
||||
@ -647,7 +651,7 @@ img {
|
||||
#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }
|
||||
|
||||
/* wrapper divs hidden by default */
|
||||
#rgbwrap, #kwrap, #wwrap, #wbal, #qcs-w, #hexw {
|
||||
#rgbwrap, #swrap, #hwrap, #kwrap, #wwrap, #wbal, #qcs-w, #hexw {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -731,7 +735,11 @@ input[type=range]::-moz-range-thumb {
|
||||
|
||||
#Colors .sliderwrap {
|
||||
width: 260px;
|
||||
margin: 10px 0 0;
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
|
||||
#Colors {
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
/* Dynamically hide brightness slider label */
|
||||
@ -744,13 +752,14 @@ input[type=range]::-moz-range-thumb {
|
||||
margin-top: var(--bmt);
|
||||
}
|
||||
|
||||
#picker, #rgbwrap, #kwrap, #wwrap, #wbal, #vwrap, #qcs-w, #hexw, #pall, #ledmap {
|
||||
#picker, #qcs-w, #hexw, #pall, #ledmap {
|
||||
margin: 0 auto;
|
||||
width: 260px;
|
||||
/*background-color: unset;*/
|
||||
}
|
||||
|
||||
#picker {
|
||||
margin-top: 10px;
|
||||
margin-top: -10px !important;
|
||||
}
|
||||
|
||||
/* buttons */
|
||||
@ -1409,6 +1418,9 @@ TD .checkmark, TD .radiomark {
|
||||
.expanded {
|
||||
display: inline-block !important;
|
||||
}
|
||||
.expanded .segin.hide, .expanded .presin.hide, .expanded .sbs.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.m6 {
|
||||
margin: 6px 0;
|
||||
|
@ -88,68 +88,73 @@
|
||||
<div class ="container">
|
||||
<div id="Colors" class="tabcontent">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="hwrap">
|
||||
<!--p class="labels hd">Hue</p-->
|
||||
<div id="hwrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderH" class="noslide" oninput="fromH()" onchange="setColor(0)" max="359" min="0" type="range" value="0" step="any">
|
||||
<div class="sliderdisplay" style="background: linear-gradient(90deg, #f00 2%, #ff0 19%, #0f0 35%, #0ff 52%, #00f 68%, #f0f 85%, #f00)"></div>
|
||||
</div><br>
|
||||
</div>
|
||||
<span class="tooltiptext">Hue</span>
|
||||
</div>
|
||||
<div id="swrap">
|
||||
<!--p class="labels hd">Saturation</p-->
|
||||
<div id="swrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderS" class="noslide" oninput="fromS()" onchange="setColor(0)" max="100" min="0" type="range" value="100" step="any">
|
||||
<div class="sliderdisplay" style="background: linear-gradient(90deg, #aaa 0%, #f00)"></div>
|
||||
</div><br>
|
||||
</div>
|
||||
<span class="tooltiptext">Saturation</span>
|
||||
</div>
|
||||
<div id="vwrap">
|
||||
<!--p class="labels hd">Value</p-->
|
||||
<div id="vwrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderV" class="noslide" oninput="fromV()" onchange="setColor(0)" max="100" min="0" type="range" value="100" step="any" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div><br>
|
||||
</div>
|
||||
<span class="tooltiptext">Value/Brightness</span>
|
||||
</div>
|
||||
<div id="kwrap">
|
||||
<!--p class="labels hd">Temperature</p-->
|
||||
<div id="kwrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderK" class="noslide" oninput="fromK()" onchange="setColor(0)" max="10091" min="1900" type="range" value="6550" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<span class="tooltiptext">Kelvin/Temperature</span>
|
||||
</div>
|
||||
<div id="rgbwrap">
|
||||
<p class="labels hd">RGB color</p>
|
||||
<div id="rwrap" class="il">
|
||||
<!--p class="labels hd">RGB color</p-->
|
||||
<div id="rwrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" class="noslide" oninput="fromRgb()" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<span class="tooltiptext">Red channel</span>
|
||||
</div>
|
||||
<div id="gwrap" class="il">
|
||||
<div id="gwrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" class="noslide" oninput="fromRgb()" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<span class="tooltiptext">Green channel</span>
|
||||
</div>
|
||||
<div id="bwrap" class="il">
|
||||
<div id="bwrap" class="slider">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" class="noslide" oninput="fromRgb()" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<span class="tooltiptext">Blue channel</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wwrap">
|
||||
<p class="labels hd">White channel</p>
|
||||
<div id="wwrap" class="slider">
|
||||
<!--p class="labels hd">White channel</p-->
|
||||
<div id="whibri" class="sliderwrap il">
|
||||
<input id="sliderW" class="noslide" oninput="fromW()" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<span class="tooltiptext">White channel</span>
|
||||
</div>
|
||||
<div id="wbal">
|
||||
<p class="labels hd">White balance</p>
|
||||
<div id="wbal" class="slider">
|
||||
<!--p class="labels hd">White balance</p-->
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderA" class="noslide" onchange="setBalance(this.value)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<span class="tooltiptext">White balance</span>
|
||||
</div>
|
||||
<div id="qcs-w">
|
||||
<div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div>
|
||||
@ -310,7 +315,7 @@
|
||||
<div id="segutil2">
|
||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||
</div>
|
||||
<p>Transition: <input id="tt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7"> s</p>
|
||||
<p>Transition: <input id="tt" type="number" min="0" max="65.5" step="0.1" value="0.7"> s</p>
|
||||
<p id="ledmap" class="hide"></p>
|
||||
</div>
|
||||
|
||||
|
@ -4,6 +4,7 @@ var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, sy
|
||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||
var nlDur = 60, nlTar = 0;
|
||||
var nlMode = false;
|
||||
var segLmax = 0; // size (in pixels) of largest selected segment
|
||||
var selectedFx = 0;
|
||||
var selectedPal = 0;
|
||||
var csel = 0; // selected color slot (0-2)
|
||||
@ -60,13 +61,10 @@ function setCSL(cs)
|
||||
let w = cs.dataset.w ? parseInt(cs.dataset.w) : 0;
|
||||
let hasShadow = getComputedStyle(cs).textShadow !== "none";
|
||||
if (hasRGB && !isRgbBlack(cs.dataset)) {
|
||||
cs.style.backgroundColor = rgbStr(cs.dataset);
|
||||
if (!hasShadow) cs.style.color = rgbBri(cs.dataset) > 127 ? "#000":"#fff"; // if text has no CSS "shadow"
|
||||
if (hasWhite && w > 0) {
|
||||
cs.style.background = `linear-gradient(180deg, ${rgbStr(cs.dataset)} 30%, rgb(${w},${w},${w}))`;
|
||||
}
|
||||
cs.style.background = (hasWhite && w > 0) ? `linear-gradient(180deg, ${rgbStr(cs.dataset)} 30%, rgb(${w},${w},${w}))` : rgbStr(cs.dataset);
|
||||
} else {
|
||||
if (!hasWhite) w = 0;
|
||||
if (hasRGB && !hasWhite) w = 0;
|
||||
cs.style.background = `rgb(${w},${w},${w})`;
|
||||
if (!hasShadow) cs.style.color = w > 127 ? "#000":"#fff";
|
||||
}
|
||||
@ -746,7 +744,7 @@ function populateSegments(s)
|
||||
<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})"></i>
|
||||
${cfg.comp.segpwr?segp:''}
|
||||
<div class="segin" id="seg${i}in">
|
||||
<input type="text" class="ptxt noslide" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>
|
||||
<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>
|
||||
<table class="infot segt">
|
||||
<tr>
|
||||
<td>${isM&&staX<mw*mh?'Start X':'Start LED'}</td>
|
||||
@ -754,24 +752,24 @@ function populateSegments(s)
|
||||
<td>${isM&&staX<mw*mh?'':'Offset'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input class="noslide segn" id="seg${i}s" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="noslide segn" id="seg${i}e" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td style="text-align:revert;">${isM&&staX<mw*mh?miXck+'<br>'+rvXck:''}<input class="noslide segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>
|
||||
<td><input class="segn" id="seg${i}s" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="segn" id="seg${i}e" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td style="text-align:revert;">${isM&&staX<mw*mh?miXck+'<br>'+rvXck:''}<input class="segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>
|
||||
</tr>
|
||||
${isM&&staX<mw*mh ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+
|
||||
'<tr>'+
|
||||
'<td><input class="noslide segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||
'<td><input class="noslide segn" id="seg'+i+'eY" type="number" min="0" max="'+mh+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||
'<td><input class="segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||
'<td><input class="segn" id="seg'+i+'eY" type="number" min="0" max="'+mh+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||
'<td style="text-align:revert;">'+miYck+'<br>'+rvYck+'</td>'+
|
||||
'</tr>':''}
|
||||
<tr>
|
||||
<td>Grouping</td>
|
||||
<td>Spacing</td>
|
||||
<td><!--Apply--></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="noslide segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td style="text-align:revert;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}"></i></button></td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -801,10 +799,13 @@ function populateSegments(s)
|
||||
for (var i = 0; i <= lSeg; i++) {
|
||||
updateLen(i);
|
||||
updateTrail(gId(`seg${i}bri`));
|
||||
gId(`segr${i}`).style.display = "none";
|
||||
gId(`segr${i}`).classList.add("hide");
|
||||
if (!gId(`seg${i}sel`).checked && gId('selall')) gId('selall').checked = false; // uncheck if at least one is unselected.
|
||||
}
|
||||
if (segCount < 2) gId(`segd${lSeg}`).style.display = "none";
|
||||
if (segCount < 2) {
|
||||
gId(`segd${lSeg}`).classList.add("hide");
|
||||
gId(`segp0`).classList.add("hide");
|
||||
}
|
||||
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
|
||||
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
||||
|
||||
@ -852,6 +853,7 @@ function populateEffects()
|
||||
let m = (eP.length<4 || eP[3]==='')?'1':eP[3]; // flags
|
||||
if (id == 0) m = ''; // solid has no flags
|
||||
if (m.length>0) {
|
||||
if (m.includes('0')) nm += "•"; // 0D effects (PWM & On/Off)
|
||||
if (m.includes('1')) nm += "⋮"; // 1D effects
|
||||
if (m.includes('2')) nm += "▦"; // 2D effects
|
||||
if (m.includes('v')) nm += "♪"; // volume effects
|
||||
@ -1165,18 +1167,19 @@ function updateUI()
|
||||
}
|
||||
if (hasWhite) updateTrail(gId('sliderW'));
|
||||
|
||||
gId('wwrap').style.display = (hasWhite) ? "block":"none"; // white channel
|
||||
gId('wbal').style.display = (hasCCT) ? "block":"none"; // white balance
|
||||
var ccfg = cfg.comp.colors;
|
||||
gId('hexw').style.display = ccfg.hex ? "block":"none"; // HEX input
|
||||
gId('picker').style.display = (hasRGB && ccfg.picker) ? "block":"none"; // color picker wheel
|
||||
gId('hwrap').style.display = (hasRGB && !ccfg.picker) ? "block":"none"; // color picker wheel
|
||||
gId('swrap').style.display = (hasRGB && !ccfg.picker) ? "block":"none"; // color picker wheel
|
||||
gId('vwrap').style.display = (hasRGB /*&& ccfg.picker*/) ? "block":"none"; // brightness (value) slider
|
||||
gId('kwrap').style.display = (hasRGB && !hasCCT /*&& ccfg.picker*/) ? "block":"none"; // Kelvin slider
|
||||
gId('rgbwrap').style.display = (hasRGB && ccfg.rgb) ? "block":"none"; // RGB sliders
|
||||
gId('qcs-w').style.display = (hasRGB && ccfg.quick) ? "block":"none"; // quick selection
|
||||
//gId('palw').style.display = hasRGB ? "block":"none"; // palettes
|
||||
gId('wwrap').style.display = (hasWhite) ? "block":"none"; // white channel
|
||||
gId('wbal').style.display = (hasCCT) ? "block":"none"; // white balance
|
||||
gId('hexw').style.display = (ccfg.hex) ? "block":"none"; // HEX input
|
||||
gId('picker').style.display = (hasRGB && ccfg.picker) ? "block":"none"; // color picker wheel
|
||||
gId('hwrap').style.display = (hasRGB && !ccfg.picker) ? "block":"none"; // hue slider
|
||||
gId('swrap').style.display = (hasRGB && !ccfg.picker) ? "block":"none"; // saturation slider
|
||||
gId('vwrap').style.display = (hasRGB) ? "block":"none"; // brightness (value) slider
|
||||
gId('kwrap').style.display = (hasRGB && !hasCCT) ? "block":"none"; // Kelvin slider
|
||||
gId('rgbwrap').style.display = (hasRGB && ccfg.rgb) ? "block":"none"; // RGB sliders
|
||||
gId('qcs-w').style.display = (hasRGB && ccfg.quick) ? "block":"none"; // quick selection
|
||||
//gId('csl').style.display = (hasRGB || hasWhite) ? "block":"none"; // color selectors (hide for On/Off bus)
|
||||
//gId('palw').style.display = (hasRGB) ? "inline-block":"none"; // palettes are shown/hidden in setEffectParameters()
|
||||
|
||||
updatePA();
|
||||
updatePSliders();
|
||||
@ -1221,7 +1224,19 @@ function updateSelectedFx()
|
||||
if (selectedEffect) {
|
||||
selectedEffect.classList.add('selected');
|
||||
setEffectParameters(selectedFx);
|
||||
|
||||
// hide non-0D effects if segment only has 1 pixel (0D)
|
||||
var fxs = parent.querySelectorAll('.lstI');
|
||||
for (const fx of fxs) {
|
||||
let opts = fx.dataset.opt.split(";");
|
||||
if (fx.dataset.id>0) {
|
||||
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
|
||||
else {
|
||||
if (segLmax==1 && (!opts[3] || opts[3].indexOf("0")<0)) fx.classList.add('hide');
|
||||
else fx.classList.remove('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
// hide 2D mapping and/or sound simulation options
|
||||
var selectedName = selectedEffect.querySelector(".lstIname").innerText;
|
||||
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
||||
for (const seg of segs) if (selectedName.indexOf("\u25A6")<0) seg.classList.remove('hide'); else seg.classList.add('hide');
|
||||
@ -1308,6 +1323,7 @@ function readState(s,command=false)
|
||||
var selc=0;
|
||||
var sellvl=0; // 0: selc is invalid, 1: selc is mainseg, 2: selc is first selected
|
||||
hasRGB = hasWhite = hasCCT = false;
|
||||
segLmax = 0;
|
||||
for (let i = 0; i < (s.seg||[]).length; i++)
|
||||
{
|
||||
if (sellvl == 0 && s.seg[i].id == s.mainseg) {
|
||||
@ -1321,6 +1337,8 @@ function readState(s,command=false)
|
||||
hasRGB |= !!(lc & 0x01);
|
||||
hasWhite |= !!(lc & 0x02);
|
||||
hasCCT |= !!(lc & 0x04);
|
||||
let sLen = (s.seg[i].stop - s.seg[i].start)*(s.seg[i].stopY?(s.seg[i].stopY - s.seg[i].startY):1);
|
||||
segLmax = segLmax < sLen ? sLen : segLmax;
|
||||
}
|
||||
}
|
||||
var i=s.seg[selc];
|
||||
@ -1341,7 +1359,7 @@ function readState(s,command=false)
|
||||
cd[e].dataset.r = i.col[e][0];
|
||||
cd[e].dataset.g = i.col[e][1];
|
||||
cd[e].dataset.b = i.col[e][2];
|
||||
if (hasWhite) { cd[e].dataset.w = i.col[e][3]; }
|
||||
if (hasWhite || (!hasRGB && !hasWhite)) { cd[e].dataset.w = i.col[e][3]; }
|
||||
setCSL(cd[e]);
|
||||
}
|
||||
selectSlot(csel);
|
||||
@ -1493,8 +1511,8 @@ function setEffectParameters(idx)
|
||||
var palw = gId("palw"); // wrapper
|
||||
var pall = gId("pall"); // label
|
||||
// if not controlDefined or palette has a value
|
||||
if ((!controlDefined) || (paOnOff.length>0 && paOnOff[0]!="" && isNaN(paOnOff[0]))) {
|
||||
palw.style.display = hasRGB ? "inline-block" : "none";
|
||||
if (hasRGB && ((!controlDefined) || (paOnOff.length>0 && paOnOff[0]!="" && isNaN(paOnOff[0])))) {
|
||||
palw.style.display = "inline-block";
|
||||
if (paOnOff.length>0 && paOnOff[0].indexOf("=")>0) {
|
||||
// embeded default values
|
||||
var dPos = paOnOff[0].indexOf("=");
|
||||
@ -1704,21 +1722,21 @@ function makeSeg()
|
||||
});
|
||||
var cn = `<div class="seg lstI expanded">
|
||||
<div class="segin">
|
||||
<input type="text" class="noslide" id="seg${lu}t" autocomplete="off" maxlength=32 value="" placeholder="New segment ${lu}"/>
|
||||
<input type="text" id="seg${lu}t" autocomplete="off" maxlength=32 value="" placeholder="New segment ${lu}"/>
|
||||
<table class="segt">
|
||||
<tr>
|
||||
<td width="38%">${isM?'Start X':'Start LED'}</td>
|
||||
<td width="38%">${isM?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input class="noslide segn" id="seg${lu}s" type="number" min="0" max="${isM?mw-1:ledCount-1}" value="${ns}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="noslide segn" id="seg${lu}e" type="number" min="0" max="${ct}" value="${ct}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="segn" id="seg${lu}s" type="number" min="0" max="${isM?mw-1:ledCount-1}" value="${ns}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="segn" id="seg${lu}e" type="number" min="0" max="${ct}" value="${ct}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><button class="btn btn-xs" onclick="setSeg(${lu});"><i class="icons bth-icon" id="segc${lu}"></i></button></td>
|
||||
</tr>
|
||||
<tr id="mkSYH" class="${isM?"":"hide"}"><td>Start Y</td><td>${cfg.comp.seglen?'Height':'Stop Y'}</td></tr>
|
||||
<tr id="mkSYD" class="${isM?"":"hide"}">
|
||||
<td><input class="noslide segn" id="seg${lu}sY" type="number" min="0" max="${mh-1}" value="0" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="noslide segn" id="seg${lu}eY" type="number" min="0" max="${mh}" value="${isM?mh:1}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="segn" id="seg${lu}sY" type="number" min="0" max="${mh-1}" value="0" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="segn" id="seg${lu}eY" type="number" min="0" max="${mh}" value="${isM?mh:1}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="h" id="seg${lu}len">${ledCount - ns} LEDs</div>
|
||||
@ -1843,7 +1861,7 @@ function makeP(i,pl)
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<div id="pl${i}o1" style="display:${rep>0?"block":"none"}">
|
||||
<div class="c">Repeat <input class="noslide" type="number" id="pl${i}rp" oninput="plR(${i})" max=127 min=0 value=${rep>0?rep:1}> times</div>
|
||||
<div class="c">Repeat <input type="number" id="pl${i}rp" oninput="plR(${i})" max=127 min=0 value=${rep>0?rep:1}> times</div>
|
||||
<div class="sel">End preset:<br>
|
||||
<div class="sel-p"><select class="sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
||||
<option value="0">None</option>
|
||||
@ -1882,8 +1900,8 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||
}
|
||||
}
|
||||
|
||||
return `<input type="text" class="ptxt noslide ${i==0?'show':''}" id="p${i}txt" autocomplete="off" maxlength=32 value="${(i>0)?pName(i):""}" placeholder="Enter name..."/>
|
||||
<div class="c">Quick load label: <input type="text" class="stxt noslide" maxlength=2 value="${qlName(i)}" id="p${i}ql" autocomplete="off"/></div>
|
||||
return `<input type="text" class="ptxt ${i==0?'show':''}" id="p${i}txt" autocomplete="off" maxlength=32 value="${(i>0)?pName(i):""}" placeholder="Enter name..."/>
|
||||
<div class="c">Quick load label: <input type="text" class="stxt" maxlength=2 value="${qlName(i)}" id="p${i}ql" autocomplete="off"/></div>
|
||||
<div class="h">(leave empty for no Quick load button)</div>
|
||||
<div ${pl&&i==0?"style='display:none'":""}>
|
||||
<label class="check revchkl">
|
||||
@ -1894,9 +1912,9 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="po2" id="p${i}o2">API command<br><textarea class="apitxt noslide" id="p${i}api"></textarea></div>
|
||||
<div class="po2" id="p${i}o2">API command<br><textarea class="apitxt" id="p${i}api"></textarea></div>
|
||||
<div class="po1" id="p${i}o1">${content}</div>
|
||||
<div class="c m6">Save to ID <input class="noslide" id="p${i}id" type="number" oninput="checkUsed(${i})" max=250 min=1 value=${(i>0)?i:getLowestUnusedP()}></div>
|
||||
<div class="c m6">Save to ID <input id="p${i}id" type="number" oninput="checkUsed(${i})" max=250 min=1 value=${(i>0)?i:getLowestUnusedP()}></div>
|
||||
<div class="c">
|
||||
<button class="btn btn-p" onclick="saveP(${i},${pl})"><i class="icons btn-icon"></i>Save</button>
|
||||
${(i>0)?'<button class="btn btn-p" id="p'+i+'del" onclick="delP('+i+')"><i class="icons btn-icon"></i>Delete':'<button class="btn btn-p" onclick="resetPUtil()">Cancel'}</button>
|
||||
@ -1941,8 +1959,8 @@ function makePlEntry(p,i)
|
||||
<td class="c">#${i+1}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="c" width="40%"><input class="noslide segn" type="number" placeholder="Duration" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value="${plJson[p].dur[i]/10.0}">s</td>
|
||||
<td class="c" width="40%"><input class="noslide segn" type="number" placeholder="Transition" max=65.0 min=0.0 step=0.1 oninput="pleTr(${p},${i},this)" value="${plJson[p].transition[i]/10.0}">s</td>
|
||||
<td class="c" width="40%"><input class="segn" type="number" placeholder="Duration" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value="${plJson[p].dur[i]/10.0}">s</td>
|
||||
<td class="c" width="40%"><input class="segn" type="number" placeholder="Transition" max=65.0 min=0.0 step=0.1 oninput="pleTr(${p},${i},this)" value="${plJson[p].transition[i]/10.0}">s</td>
|
||||
<td class="c"><button class="btn btn-pl-del" onclick="delPl(${p},${i})"><i class="icons btn-icon"></i></button></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -2234,7 +2252,7 @@ function setLor(i)
|
||||
function setPreset(i)
|
||||
{
|
||||
var obj = {"ps":i};
|
||||
if (pJson && pJson[i] && (!pJson[i].win || pJson[i].win.indexOf("Please") <= 0)) {
|
||||
if (!isPlaylist(i) && pJson && pJson[i] && (!pJson[i].win || pJson[i].win.indexOf("Please") <= 0)) {
|
||||
// we will send the complete preset content as to avoid delay introduced by
|
||||
// async nature of applyPreset() and having to read the preset from file system.
|
||||
obj = {"pd":i}; // use "pd" instead of "ps" to indicate that we are sending the preset content directly
|
||||
@ -2740,7 +2758,7 @@ function hasIroClass(classList)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//required by rangetouch.js
|
||||
function lock(e)
|
||||
{
|
||||
if (pcMode) return;
|
||||
@ -2754,7 +2772,7 @@ function lock(e)
|
||||
|
||||
_C.classList.toggle('smooth', !(locked = true));
|
||||
}
|
||||
|
||||
//required by rangetouch.js
|
||||
function move(e)
|
||||
{
|
||||
if(!locked || pcMode) return;
|
||||
|
@ -13,6 +13,7 @@
|
||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function fS(){d.Sf.submit();} // <button type=submit> sometimes didn't work
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
@ -294,7 +295,7 @@ Y:<input name="P${i}Y" type="number" min="0" max="255" value="0" oninput="UI()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="toprow">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="fS()">Save</button><hr>
|
||||
</div>
|
||||
<h2>2D setup</h2>
|
||||
Strip or panel:
|
||||
@ -341,7 +342,7 @@ Y:<input name="P${i}Y" type="number" min="0" max="255" value="0" oninput="UI()">
|
||||
A value of -1 means that pixel at that position is missing, a value of 0 means never paint that pixel, and 1 means regular pixel.</i>
|
||||
</div>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="fS()">Save</button>
|
||||
</form>
|
||||
<div id="toast"></div>
|
||||
</body>
|
||||
|
@ -143,7 +143,7 @@
|
||||
|
||||
function UI(change=false)
|
||||
{
|
||||
var isRGBW = false, memu = 0;
|
||||
let isRGBW = false, gRGBW = false, memu = 0;
|
||||
|
||||
gId('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
||||
|
||||
@ -184,7 +184,7 @@
|
||||
if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
|
||||
}
|
||||
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814
|
||||
isRGBW = ((t > 17 && t < 22) || t == 30 || t == 31 || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gRGBW |= isRGBW = ((t > 17 && t < 22) || t == 30 || t == 31 || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"w").style.display = (t == 30 || t == 31) ? "inline":"none"; // show swap channels dropdown
|
||||
if (!(t == 30 || t == 31)) d.getElementsByName("WO"+n)[0].value = 0; // reset swapping
|
||||
@ -197,11 +197,11 @@
|
||||
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
|
||||
}
|
||||
}
|
||||
// display white channel calculation method
|
||||
var myC = d.querySelectorAll('.wc'),
|
||||
l = myC.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
||||
// display global white channel overrides
|
||||
gId("wc").style.display = (gRGBW) ? 'inline':'none';
|
||||
if (!gRGBW) {
|
||||
d.Sf.AW.selectedIndex = 0;
|
||||
d.Sf.CR.checked = false;
|
||||
}
|
||||
// check for pin conflicts
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
@ -660,8 +660,8 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
<option value="3">Sunrise</option>
|
||||
</select>
|
||||
<h3>White management</h3>
|
||||
White Balance correction: <input type="checkbox" name="CCT"> <br>
|
||||
<span class="wc">
|
||||
White Balance correction: <input type="checkbox" name="CCT"><br>
|
||||
<div id="wc">
|
||||
Global override for Auto-calculate white:<br>
|
||||
<select name="AW">
|
||||
<option value=255>Disabled</option>
|
||||
@ -671,9 +671,10 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
<option value=3>Dual</option>
|
||||
<option value=4>Max</option>
|
||||
</select>
|
||||
<br>
|
||||
Calculate CCT from RGB: <input type="checkbox" name="CR"> <br>
|
||||
CCT additive blending: <input type="number" class="s" min="0" max="100" name="CB" required> %</span>
|
||||
<br>
|
||||
Calculate CCT from RGB: <input type="checkbox" name="CR"><br>
|
||||
CCT additive blending: <input type="number" class="s" min="0" max="100" name="CB" required> %
|
||||
</div>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name="PB">
|
||||
|
@ -127,19 +127,19 @@
|
||||
<p class="label h">RGB channels</p>
|
||||
<div id="rwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
|
||||
<input id="sliderR" class="noslide" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div><br>
|
||||
<div id="gwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
|
||||
<input id="sliderG" class="noslide" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div><br>
|
||||
<div id="bwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
|
||||
<input id="sliderB" class="noslide" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div><br>
|
||||
@ -147,14 +147,14 @@
|
||||
<div id="wwrap" class="center">
|
||||
<p class="label h">White channel</p>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderW" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
|
||||
<input id="sliderW" class="noslide" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wbal">
|
||||
<p class="label h">White balance</p>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderA" onchange="setBalance(this.value)" max="255" min="0" type="range" value="128" />
|
||||
<input id="sliderA" class="noslide" onchange="setBalance(this.value)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -551,7 +551,7 @@ function populateSegments(s)
|
||||
<div class="il">
|
||||
<i class="icons slider-icon pwr ${powered[i] ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})" title="${inst.n}"></i>
|
||||
<div id="sliderSeg${i}Bri" class="sliderwrap il">
|
||||
<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />
|
||||
<input id="seg${i}bri" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
@ -1379,7 +1379,7 @@ function hasIroClass(classList)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//required by rangetouch.js
|
||||
function lock(e)
|
||||
{
|
||||
var l = e.target.classList;
|
||||
@ -1392,7 +1392,7 @@ function lock(e)
|
||||
|
||||
_C.classList.toggle('smooth', !(locked = true));
|
||||
}
|
||||
|
||||
//required by rangetouch.js
|
||||
function move(e)
|
||||
{
|
||||
if(!locked) return;
|
||||
|
@ -124,7 +124,7 @@ void handleIR();
|
||||
#include "src/dependencies/json/AsyncJson-v6.h"
|
||||
#include "FX.h"
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
|
||||
bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
|
||||
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
|
||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
||||
|
File diff suppressed because it is too large
Load Diff
1219
wled00/html_simple.h
1219
wled00/html_simple.h
File diff suppressed because it is too large
Load Diff
3864
wled00/html_ui.h
3864
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -14,16 +14,16 @@
|
||||
* JSON API (De)serialization
|
||||
*/
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
{
|
||||
byte id = elem["id"] | it;
|
||||
if (id >= strip.getMaxSegments()) return;
|
||||
if (id >= strip.getMaxSegments()) return false;
|
||||
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
// if using vectors use this code to append segment
|
||||
if (id >= strip.getSegmentsNum()) {
|
||||
if (stop <= 0) return; // ignore empty/inactive segments
|
||||
if (stop <= 0) return false; // ignore empty/inactive segments
|
||||
strip.appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
id = strip.getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
@ -56,7 +56,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
elem["rev"] = !elem["rev"]; // alternate reverse on even/odd segments
|
||||
deserializeSegment(elem, i, presetId); // recursive call with new id
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (elem["n"]) {
|
||||
@ -107,6 +107,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
seg.set(start, stop, grp, spc, of, startY, stopY);
|
||||
|
||||
if (seg.reset && seg.stop == 0) return true; // segment was deleted & is marked for reset, no need to change anything else
|
||||
|
||||
byte segbri = seg.opacity;
|
||||
if (getVal(elem["bri"], &segbri)) {
|
||||
if (segbri > 0) seg.setOpacity(segbri);
|
||||
@ -262,6 +264,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
// send UDP/WS if segment options changed (except selection; will also deselect current preset)
|
||||
if (seg.differs(prev) & 0x7F) stateChanged = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// deserializes WLED state (fileDoc points to doc object if called from web server)
|
||||
@ -377,11 +381,12 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||
}
|
||||
} else {
|
||||
size_t deleted = 0;
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
for (JsonObject elem : segs) {
|
||||
deserializeSegment(elem, it, presetId);
|
||||
it++;
|
||||
if (deserializeSegment(elem, it++, presetId) && !elem["stop"].isNull() && elem["stop"]==0) deleted++;
|
||||
}
|
||||
if (strip.getSegmentsNum() > 3 && deleted >= strip.getSegmentsNum()/2U) strip.purgeSegments(); // batch deleting more than half segments
|
||||
}
|
||||
|
||||
usermods.readFromJsonState(root);
|
||||
|
@ -11,15 +11,15 @@ void _overlayAnalogClock()
|
||||
{
|
||||
_overlayAnalogCountdown(); return;
|
||||
}
|
||||
double hourP = ((double)(hour(localTime)%12))/12;
|
||||
double minuteP = ((double)minute(localTime))/60;
|
||||
hourP = hourP + minuteP/12;
|
||||
double secondP = ((double)second(localTime))/60;
|
||||
int hourPixel = floor(analogClock12pixel + overlaySize*hourP);
|
||||
float hourP = ((float)(hour(localTime)%12))/12.0f;
|
||||
float minuteP = ((float)minute(localTime))/60.0f;
|
||||
hourP = hourP + minuteP/12.0f;
|
||||
float secondP = ((float)second(localTime))/60.0f;
|
||||
int hourPixel = floorf(analogClock12pixel + overlaySize*hourP);
|
||||
if (hourPixel > overlayMax) hourPixel = overlayMin -1 + hourPixel - overlayMax;
|
||||
int minutePixel = floor(analogClock12pixel + overlaySize*minuteP);
|
||||
int minutePixel = floorf(analogClock12pixel + overlaySize*minuteP);
|
||||
if (minutePixel > overlayMax) minutePixel = overlayMin -1 + minutePixel - overlayMax;
|
||||
int secondPixel = floor(analogClock12pixel + overlaySize*secondP);
|
||||
int secondPixel = floorf(analogClock12pixel + overlaySize*secondP);
|
||||
if (secondPixel > overlayMax) secondPixel = overlayMin -1 + secondPixel - overlayMax;
|
||||
if (analogClockSecondsTrail)
|
||||
{
|
||||
@ -36,7 +36,7 @@ void _overlayAnalogClock()
|
||||
{
|
||||
for (byte i = 0; i <= 12; i++)
|
||||
{
|
||||
int pix = analogClock12pixel + round((overlaySize / 12.0) *i);
|
||||
int pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i);
|
||||
if (pix > overlayMax) pix -= overlaySize;
|
||||
strip.setPixelColor(pix, 0x00FFAA);
|
||||
}
|
||||
@ -52,29 +52,29 @@ void _overlayAnalogCountdown()
|
||||
if ((unsigned long)toki.second() < countdownTime)
|
||||
{
|
||||
long diff = countdownTime - toki.second();
|
||||
double pval = 60;
|
||||
float pval = 60.0f;
|
||||
if (diff > 31557600L) //display in years if more than 365 days
|
||||
{
|
||||
pval = 315576000L; //10 years
|
||||
pval = 315576000.0f; //10 years
|
||||
} else if (diff > 2592000L) //display in months if more than a month
|
||||
{
|
||||
pval = 31557600L; //1 year
|
||||
pval = 31557600.0f; //1 year
|
||||
} else if (diff > 604800) //display in weeks if more than a week
|
||||
{
|
||||
pval = 2592000L; //1 month
|
||||
pval = 2592000.0f; //1 month
|
||||
} else if (diff > 86400) //display in days if more than 24 hours
|
||||
{
|
||||
pval = 604800; //1 week
|
||||
pval = 604800.0f; //1 week
|
||||
} else if (diff > 3600) //display in hours if more than 60 minutes
|
||||
{
|
||||
pval = 86400; //1 day
|
||||
pval = 86400.0f; //1 day
|
||||
} else if (diff > 60) //display in minutes if more than 60 seconds
|
||||
{
|
||||
pval = 3600; //1 hour
|
||||
pval = 3600.0f; //1 hour
|
||||
}
|
||||
int overlaySize = overlayMax - overlayMin +1;
|
||||
double perc = (pval-(double)diff)/pval;
|
||||
if (perc > 1.0) perc = 1.0;
|
||||
float perc = (pval-(float)diff)/pval;
|
||||
if (perc > 1.0f) perc = 1.0f;
|
||||
byte pixelCnt = perc*overlaySize;
|
||||
if (analogClock12pixel + pixelCnt > overlayMax)
|
||||
{
|
||||
|
@ -319,8 +319,7 @@ void WLED::setup()
|
||||
DEBUG_PRINT(F("esp8266 "));
|
||||
DEBUG_PRINTLN(ESP.getCoreVersion());
|
||||
#endif
|
||||
DEBUG_PRINT(F("heap "));
|
||||
DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound()) {
|
||||
@ -355,6 +354,8 @@ void WLED::setup()
|
||||
DEBUG_PRINTLN(F("Registering usermods ..."));
|
||||
registerUsermods();
|
||||
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
for (uint8_t i=1; i<WLED_MAX_BUTTONS; i++) btnPin[i] = -1;
|
||||
|
||||
bool fsinit = false;
|
||||
@ -395,10 +396,12 @@ void WLED::setup()
|
||||
|
||||
DEBUG_PRINTLN(F("Initializing strip"));
|
||||
beginStrip();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
DEBUG_PRINTLN(F("Usermods setup"));
|
||||
userSetup();
|
||||
usermods.setup();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
|
||||
showWelcomePage = true;
|
||||
@ -454,7 +457,9 @@ void WLED::setup()
|
||||
#endif
|
||||
|
||||
// HTTP server page init
|
||||
DEBUG_PRINTLN(F("initServer"));
|
||||
initServer();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
enableWatchdog();
|
||||
|
||||
@ -750,6 +755,8 @@ void WLED::handleConnection()
|
||||
DEBUG_PRINTLN(heap);
|
||||
forceReconnect = true;
|
||||
strip.purgeSegments(true); // remove all but one segments from memory
|
||||
} else if (heap < MIN_HEAP_SIZE) {
|
||||
strip.purgeSegments();
|
||||
}
|
||||
lastHeap = heap;
|
||||
heapTime = now;
|
||||
|
@ -111,9 +111,17 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
DEBUG_PRINTF("JSON buffer size: %u for WS request (%u).\n", doc.memoryUsage(), len);
|
||||
|
||||
size_t heap1 = ESP.getFreeHeap();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
#ifdef ESP8266
|
||||
if (len>heap1) {
|
||||
DEBUG_PRINTLN(F("Out of memory (WS)!"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes on ESP8266
|
||||
#ifdef ESP8266
|
||||
size_t heap2 = ESP.getFreeHeap();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
#else
|
||||
size_t heap2 = 0; // ESP32 variants do not have the same issue and will work without checking heap allocation
|
||||
#endif
|
||||
@ -148,11 +156,17 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
AsyncWebSocketClient * wsc = ws.client(wsClient);
|
||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||
|
||||
uint16_t used = strip.getLengthTotal();
|
||||
const uint16_t MAX_LIVE_LEDS_WS = strip.isMatrix ? 1024 : 256;
|
||||
uint16_t n = ((used -1)/MAX_LIVE_LEDS_WS) +1; //only serve every n'th LED if count over MAX_LIVE_LEDS_WS
|
||||
uint16_t pos = (strip.isMatrix ? 4 : 2);
|
||||
uint16_t bufSize = pos + (used/n)*3;
|
||||
size_t used = strip.getLengthTotal();
|
||||
#ifdef ESP8266
|
||||
const size_t MAX_LIVE_LEDS_WS = 256U;
|
||||
#else
|
||||
const size_t MAX_LIVE_LEDS_WS = 1024U;
|
||||
#endif
|
||||
size_t n = ((used -1)/MAX_LIVE_LEDS_WS) +1; //only serve every n'th LED if count over MAX_LIVE_LEDS_WS
|
||||
size_t pos = (strip.isMatrix ? 4 : 2); // start of data
|
||||
size_t bufSize = pos + (used/n)*3;
|
||||
size_t skipLines = 0;
|
||||
|
||||
AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize);
|
||||
if (!wsBuf) return false; //out of memory
|
||||
uint8_t* buffer = wsBuf->get();
|
||||
@ -163,11 +177,25 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
buffer[1] = 2; //version
|
||||
buffer[2] = Segment::maxWidth;
|
||||
buffer[3] = Segment::maxHeight;
|
||||
if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS*4) {
|
||||
buffer[2] = Segment::maxWidth/4;
|
||||
buffer[3] = Segment::maxHeight/4;
|
||||
skipLines = 3;
|
||||
} else if (Segment::maxWidth * Segment::maxHeight > MAX_LIVE_LEDS_WS) {
|
||||
buffer[2] = Segment::maxWidth/2;
|
||||
buffer[3] = Segment::maxHeight/2;
|
||||
skipLines = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint16_t i = 0; pos < bufSize -2; i += n)
|
||||
for (size_t i = 0; pos < bufSize -2; i += n)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (strip.isMatrix && skipLines) {
|
||||
if ((i/Segment::maxWidth)%(skipLines+1)) i += Segment::maxWidth * skipLines;
|
||||
}
|
||||
#endif
|
||||
uint32_t c = strip.getPixelColor(i);
|
||||
buffer[pos++] = qadd8(W(c), R(c)); //R, add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
buffer[pos++] = qadd8(W(c), G(c)); //G
|
||||
|
Loading…
Reference in New Issue
Block a user