First working multisegment transitions

This commit is contained in:
cschwinne 2021-01-09 00:35:48 +01:00
parent 0df6826c91
commit 9551519a35
10 changed files with 220 additions and 103 deletions

View File

@ -63,15 +63,14 @@
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#ifdef ESP8266 #ifdef ESP8266
#define MAX_NUM_SEGMENTS 12 #define MAX_NUM_SEGMENTS 12
/* How many color transitions can run at once */
#define MAX_NUM_TRANSITIONS 8
/* How much data bytes all segments combined may allocate */
#define MAX_SEGMENT_DATA 2048
#else #else
#define MAX_NUM_SEGMENTS 16 #define MAX_NUM_SEGMENTS 16
#endif #define MAX_NUM_TRANSITIONS 16
#define MAX_SEGMENT_DATA 8192
/* How much data bytes all segments combined may allocate */
#ifdef ESP8266
#define MAX_SEGMENT_DATA 2048
#else
#define MAX_SEGMENT_DATA 8192
#endif #endif
#define LED_SKIP_AMOUNT 1 #define LED_SKIP_AMOUNT 1
@ -79,7 +78,7 @@
#define NUM_COLORS 3 /* number of colors per segment */ #define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT _segments[_segment_index] #define SEGMENT _segments[_segment_index]
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x]) #define SEGCOLOR(x) _colors_t[x]
#define SEGENV _segment_runtimes[_segment_index] #define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength #define SEGLEN _virtualSegmentLength
#define SEGACT SEGMENT.stop #define SEGACT SEGMENT.stop
@ -240,12 +239,15 @@
#define FX_MODE_TV_SIMULATOR 116 #define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117 #define FX_MODE_DYNAMIC_SMOOTH 117
class WS2812FX { class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void); typedef uint16_t (WS2812FX::*mode_ptr)(void);
// pre show callback // pre show callback
typedef void (*show_callback) (void); typedef void (*show_callback) (void);
static WS2812FX* instance;
// segment parameters // segment parameters
public: public:
typedef struct Segment { // 24 bytes typedef struct Segment { // 24 bytes
@ -259,14 +261,39 @@ class WS2812FX {
uint8_t grouping, spacing; uint8_t grouping, spacing;
uint8_t opacity; uint8_t opacity;
uint32_t colors[NUM_COLORS]; uint32_t colors[NUM_COLORS];
void setOption(uint8_t n, bool val) bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
if (c == colors[slot]) return false;
ColorTransition::startTransition(opacity, colors[slot], instance->_transitionDur, segn, slot);
colors[slot] = c; return true;
}
void setOpacity(uint8_t o, uint8_t segn) {
if (segn >= MAX_NUM_SEGMENTS) return;
if (opacity == o) return;
ColorTransition::startTransition(o, colors[0], instance->_transitionDur, segn, 0);
opacity = o;
}
uint8_t actualOpacity() { //respects On/Off state
if (!getOption(SEG_OPTION_ON)) return 0;
return opacity;
}
void setOption(uint8_t n, bool val, uint8_t segn = 255)
{ {
bool prevOn = false;
if (n == SEG_OPTION_ON) prevOn = getOption(SEG_OPTION_ON);
if (val) { if (val) {
options |= 0x01 << n; options |= 0x01 << n;
} else } else
{ {
options &= ~(0x01 << n); options &= ~(0x01 << n);
} }
if (n == SEG_OPTION_ON && segn < MAX_NUM_SEGMENTS && getOption(SEG_OPTION_ON) != prevOn) {
if (getOption(SEG_OPTION_ON)) {
ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0);
} else {
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
}
}
} }
bool getOption(uint8_t n) bool getOption(uint8_t n)
{ {
@ -309,10 +336,10 @@ class WS2812FX {
bool allocateData(uint16_t len){ bool allocateData(uint16_t len){
if (data && _dataLen == len) return true; //already allocated if (data && _dataLen == len) return true; //already allocated
deallocateData(); deallocateData();
if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
data = new (std::nothrow) byte[len]; data = new (std::nothrow) byte[len];
if (!data) return false; //allocation failed if (!data) return false; //allocation failed
WS2812FX::_usedSegmentData += len; WS2812FX::instance->_usedSegmentData += len;
_dataLen = len; _dataLen = len;
memset(data, 0, len); memset(data, 0, len);
return true; return true;
@ -320,7 +347,7 @@ class WS2812FX {
void deallocateData(){ void deallocateData(){
delete[] data; delete[] data;
data = nullptr; data = nullptr;
WS2812FX::_usedSegmentData -= _dataLen; WS2812FX::instance->_usedSegmentData -= _dataLen;
_dataLen = 0; _dataLen = 0;
} }
@ -350,7 +377,86 @@ class WS2812FX {
bool _requiresReset = false; bool _requiresReset = false;
} segment_runtime; } segment_runtime;
typedef struct ColorTransition { // 12 bytes
uint32_t colorOld = 0;
uint32_t transitionStart;
uint16_t transitionDur;
uint8_t segment = 0xFF; //lower 6 bits: the segment this transition is for (255 indicates transition not in use/available) upper 2 bits: color channel
uint8_t briOld = 0;
static void startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot) {
Serial.printf("Starting t: Bri %u Col %u Dur %u Seg %u Slot %u\n", oldBri, oldCol, dur, segn, slot);
if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || dur == 0) return;
uint8_t tIndex = 0xFF; //none found
uint16_t tProgression = 0;
uint8_t s = segn + (slot << 6); //merge slot and segment into one byte
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
uint8_t tSeg = instance->transitions[i].segment;
//see if this segment + color already has a running transition
if (tSeg == s) {
tIndex = i; break;
}
if (tSeg == 0xFF) { //free transition
tIndex = i; tProgression = 0xFFFF;
}
}
if (tIndex == 0xFF) { //no slot found yet
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
//find most progressed transition to overwrite
uint16_t prog = instance->transitions[i].progress();
if (prog > tProgression) {
tIndex = i; tProgression = prog;
}
}
}
ColorTransition& t = instance->transitions[tIndex];
if (t.segment == s) //this is an active transition on the same segment+color
{
t.briOld = t.currentBri();
t.colorOld = t.currentColor(oldCol);
} else {
t.briOld = oldBri;
t.colorOld = oldCol;
uint8_t prevSeg = t.segment & 0x3F;
if (prevSeg < MAX_NUM_SEGMENTS) instance->_segments[prevSeg].setOption(SEG_OPTION_TRANSITIONAL, false);
}
t.transitionDur = dur;
t.transitionStart = millis();
t.segment = s;
instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, true);
//Serial.printf("S: %u, TNr: %u, St: %u\n", s, tIndex, t.transitionStart);
//instance->transitions[tIndex] = t;
}
uint16_t progress(bool allowEnd = false) { //transition progression between 0-65535
uint32_t timeNow = millis();
//Serial.printf("ProgressR %u, St: %u, S: %u\n",timeNow - transitionStart, transitionStart, segment);
if (timeNow - transitionStart > transitionDur) return 0xFFFF;
uint32_t elapsed = timeNow - transitionStart;
uint32_t prog = elapsed * 0xFFFF / transitionDur;
//Serial.printf("Progress %u\n",prog);
if (prog > 0xFFFF && allowEnd) {
uint8_t segn = segment & 0x3F;
if (segn < MAX_NUM_SEGMENTS) instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, false);
segment = 0xFF;
}
return (prog > 0xFFFF) ? 0xFFFF : prog;
}
uint32_t currentColor(uint32_t colorNew) {
return instance->color_blend(colorOld, colorNew, progress(true), true);
}
uint8_t currentBri() {
uint8_t segn = segment & 0x3F;
if (segn >= MAX_NUM_SEGMENTS) return 0;
uint8_t briNew = instance->_segments[segn].actualOpacity();
uint32_t prog = progress();
return ((briNew * prog) + (briOld * (0xFFFF - prog))) >> 16;
}
} color_transition;
WS2812FX() { WS2812FX() {
WS2812FX::instance = this;
//assign each member of the _mode[] array to its respective function reference //assign each member of the _mode[] array to its respective function reference
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static; _mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink; _mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
@ -493,6 +599,7 @@ class WS2812FX {
setBrightness(uint8_t b), setBrightness(uint8_t b),
setRange(uint16_t i, uint16_t i2, uint32_t col), setRange(uint16_t i, uint16_t i2, uint32_t col),
setShowCallback(show_callback cb), setShowCallback(show_callback cb),
setTransition(uint16_t t),
setTransitionMode(bool t), setTransitionMode(bool t),
calcGammaTable(float), calcGammaTable(float),
trigger(void), trigger(void),
@ -547,7 +654,8 @@ class WS2812FX {
timebase, timebase,
color_wheel(uint8_t), color_wheel(uint8_t),
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255), color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
color_blend(uint32_t,uint32_t,uint8_t), color_blend(uint32_t,uint32_t,uint16_t,bool b16=false),
currentColor(uint32_t colorNew, uint8_t tNr),
gamma32(uint32_t), gamma32(uint32_t),
getLastShow(void), getLastShow(void),
getPixelColor(uint16_t), getPixelColor(uint16_t),
@ -695,7 +803,8 @@ class WS2812FX {
uint16_t _length, _lengthRaw, _virtualSegmentLength; uint16_t _length, _lengthRaw, _virtualSegmentLength;
uint16_t _rand16seed; uint16_t _rand16seed;
uint8_t _brightness; uint8_t _brightness;
static uint16_t _usedSegmentData; uint16_t _usedSegmentData = 0;
uint16_t _transitionDur = 750;
void load_gradient_palette(uint8_t); void load_gradient_palette(uint8_t);
void handle_palette(void); void handle_palette(void);
@ -735,11 +844,16 @@ class WS2812FX {
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat); CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff); CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend); void
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot);
uint32_t _lastPaletteChange = 0; uint32_t _lastPaletteChange = 0;
uint32_t _lastShow = 0; uint32_t _lastShow = 0;
uint32_t _colors_t[3];
uint8_t _bri_t;
#ifdef WLED_USE_ANALOG_LEDS #ifdef WLED_USE_ANALOG_LEDS
uint32_t _analogLastShow = 0; uint32_t _analogLastShow = 0;
RgbwColor _analogLastColor = 0; RgbwColor _analogLastColor = 0;
@ -755,7 +869,12 @@ class WS2812FX {
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
friend class Segment_runtime; friend class Segment_runtime;
uint16_t realPixelIndex(uint16_t i); ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element
friend class ColorTransition;
uint16_t
realPixelIndex(uint16_t i),
transitionProgress(uint8_t tNr);
}; };
//10 names per line //10 names per line

View File

@ -85,8 +85,8 @@ void WS2812FX::service() {
// segment's buffers are cleared // segment's buffers are cleared
SEGENV.resetIfRequired(); SEGENV.resetIfRequired();
if (SEGMENT.isActive()) if (!SEGMENT.isActive()) continue;
{
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
{ {
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
@ -95,6 +95,15 @@ void WS2812FX::service() {
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
_virtualSegmentLength = SEGMENT.virtualLength(); _virtualSegmentLength = SEGMENT.virtualLength();
_bri_t = SEGMENT.opacity; _colors_t[0] = SEGMENT.colors[0]; _colors_t[1] = SEGMENT.colors[1]; _colors_t[2] = SEGMENT.colors[2];
if (!IS_SEGMENT_ON) _bri_t = 0;
for (uint8_t t = 0; t < MAX_NUM_TRANSITIONS; t++) {
if ((transitions[t].segment & 0x3F) != i) continue;
uint8_t slot = transitions[t].segment >> 6;
if (slot == 0) _bri_t = transitions[t].currentBri();
_colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]);
}
for (uint8_t c = 0; c < 3; c++) _colors_t[c] = gamma32(_colors_t[c]);
handle_palette(); handle_palette();
delay = (this->*_mode[SEGMENT.mode])(); //effect function delay = (this->*_mode[SEGMENT.mode])(); //effect function
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
@ -103,7 +112,6 @@ void WS2812FX::service() {
SEGENV.next_time = nowUp + delay; SEGENV.next_time = nowUp + delay;
} }
} }
}
_virtualSegmentLength = 0; _virtualSegmentLength = 0;
if(doShow) { if(doShow) {
yield(); yield();
@ -165,17 +173,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
if (SEGLEN) {//from segment if (SEGLEN) {//from segment
//color_blend(getpixel, col, SEGMENT.opacity); (pseudocode for future blending of segments) //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
if (IS_SEGMENT_ON) if (_bri_t < 255) {
{ col.R = scale8(col.R, _bri_t);
if (SEGMENT.opacity < 255) { col.G = scale8(col.G, _bri_t);
col.R = scale8(col.R, SEGMENT.opacity); col.B = scale8(col.B, _bri_t);
col.G = scale8(col.G, SEGMENT.opacity); col.W = scale8(col.W, _bri_t);
col.B = scale8(col.B, SEGMENT.opacity);
col.W = scale8(col.W, SEGMENT.opacity);
}
} else {
col = BLACK;
} }
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */ /* Set all the pixels in the group, ensuring _skipFirstMode is honored */
@ -347,7 +350,7 @@ uint8_t WS2812FX::getPaletteCount()
return 13 + GRADIENT_PALETTE_COUNT; return 13 + GRADIENT_PALETTE_COUNT;
} }
//TODO transitions //TODO effect transitions
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) { bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
@ -395,14 +398,15 @@ void WS2812FX::setColor(uint8_t slot, uint32_t c) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{ {
if (_segments[i].isSelected()) { if (_segments[i].isSelected()) {
_segments[i].colors[slot] = c; _segments[i].setColor(slot, c, i);
applied = true; applied = true;
} }
} }
} }
if (!applyToAllSelected || !applied) { if (!applyToAllSelected || !applied) {
_segments[getMainSegmentId()].colors[slot] = c; uint8_t mainseg = getMainSegmentId();
_segments[mainseg].setColor(slot, c, mainseg);
} }
} }
@ -605,6 +609,11 @@ void WS2812FX::setShowCallback(show_callback cb)
_callback = cb; _callback = cb;
} }
void WS2812FX::setTransition(uint16_t t)
{
_transitionDur = t;
}
void WS2812FX::setTransitionMode(bool t) void WS2812FX::setTransitionMode(bool t)
{ {
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
@ -620,24 +629,26 @@ void WS2812FX::setTransitionMode(bool t)
/* /*
* color blend function * color blend function
*/ */
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) { uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
if(blend == 0) return color1; if(blend == 0) return color1;
if(blend == 255) return color2; uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
if(blend == blendmax) return color2;
uint8_t shift = b16 ? 16 : 8;
uint32_t w1 = (color1 >> 24) & 0xff; uint32_t w1 = (color1 >> 24) & 0xFF;
uint32_t r1 = (color1 >> 16) & 0xff; uint32_t r1 = (color1 >> 16) & 0xFF;
uint32_t g1 = (color1 >> 8) & 0xff; uint32_t g1 = (color1 >> 8) & 0xFF;
uint32_t b1 = color1 & 0xff; uint32_t b1 = color1 & 0xFF;
uint32_t w2 = (color2 >> 24) & 0xff; uint32_t w2 = (color2 >> 24) & 0xFF;
uint32_t r2 = (color2 >> 16) & 0xff; uint32_t r2 = (color2 >> 16) & 0xFF;
uint32_t g2 = (color2 >> 8) & 0xff; uint32_t g2 = (color2 >> 8) & 0xFF;
uint32_t b2 = color2 & 0xff; uint32_t b2 = color2 & 0xFF;
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8; uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8; uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8; uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8; uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3)); return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
} }
@ -1044,4 +1055,4 @@ uint32_t WS2812FX::gamma32(uint32_t color)
return ((w << 24) | (r << 16) | (g << 8) | (b)); return ((w << 24) | (r << 16) | (g << 8) | (b));
} }
uint16_t WS2812FX::_usedSegmentData = 0; WS2812FX* WS2812FX::instance = nullptr;

View File

@ -110,7 +110,7 @@ void setValuesFromMainSeg();
void resetTimebase(); void resetTimebase();
void toggleOnOff(); void toggleOnOff();
void setAllLeds(); void setAllLeds();
void setLedsStandard(bool justColors = false); void setLedsStandard();
bool colorChanged(); bool colorChanged();
void colorUpdated(int callMode); void colorUpdated(int callMode);
void updateInterfaces(uint8_t callMode); void updateInterfaces(uint8_t callMode);

View File

@ -23,13 +23,13 @@ void deserializeSegment(JsonObject elem, byte it)
int segbri = elem["bri"] | -1; int segbri = elem["bri"] | -1;
if (segbri == 0) { if (segbri == 0) {
seg.setOption(SEG_OPTION_ON, 0); seg.setOption(SEG_OPTION_ON, 0, id);
} else if (segbri > 0) { } else if (segbri > 0) {
seg.opacity = segbri; seg.setOpacity(segbri, id);
seg.setOption(SEG_OPTION_ON, 1); seg.setOption(SEG_OPTION_ON, 1, id);
} }
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON)); seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id);
JsonArray colarr = elem[F("col")]; JsonArray colarr = elem[F("col")];
if (!colarr.isNull()) if (!colarr.isNull())
@ -45,7 +45,7 @@ void deserializeSegment(JsonObject elem, byte it)
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400 if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
int kelvin = colarr[i] | -1; int kelvin = colarr[i] | -1;
if (kelvin < 0) continue; if (kelvin < 0) continue;
if (kelvin == 0) seg.colors[i] = 0; if (kelvin == 0) seg.setColor(i, 0, id);
if (kelvin > 0) colorKtoRGB(kelvin, brgbw); if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
colValid = true; colValid = true;
} else { //HEX string, e.g. "FFAA00" } else { //HEX string, e.g. "FFAA00"
@ -57,7 +57,7 @@ void deserializeSegment(JsonObject elem, byte it)
if (sz == 0) continue; //do nothing on empty array if (sz == 0) continue; //do nothing on empty array
byte cp = copyArray(colX, rgbw, 4); byte cp = copyArray(colX, rgbw, 4);
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0; if (cp == 1 && rgbw[0] == 0) seg.setColor(i, 0, id);
colValid = true; colValid = true;
} }
@ -66,8 +66,8 @@ void deserializeSegment(JsonObject elem, byte it)
{ {
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];} if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];} if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
} else { //normal case, apply directly to segment (=> no transition!) } else { //normal case, apply directly to segment
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))); seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
} }
} }
@ -168,6 +168,7 @@ bool deserializeState(JsonObject root)
{ {
transitionDelay = tr; transitionDelay = tr;
transitionDelay *= 100; transitionDelay *= 100;
transitionDelayTemp = transitionDelay;
} }
tr = root[F("tt")] | -1; tr = root[F("tt")] | -1;
@ -177,6 +178,7 @@ bool deserializeState(JsonObject root)
transitionDelayTemp *= 100; transitionDelayTemp *= 100;
jsonTransitionOnce = true; jsonTransitionOnce = true;
} }
strip.setTransition(transitionDelayTemp);
int cy = root[F("pl")] | -2; int cy = root[F("pl")] | -2;
if (cy > -2) presetCyclingEnabled = (cy >= 0); if (cy > -2) presetCyclingEnabled = (cy >= 0);

View File

@ -51,24 +51,20 @@ void setAllLeds() {
} }
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
{ {
colorRGBtoRGBW(colT); colorRGBtoRGBW(col);
colorRGBtoRGBW(colSecT); colorRGBtoRGBW(colSec);
}
strip.setColor(0, col[0], col[1], col[2], col[3]);
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
{
col[3] = 0; colSec[3] = 0;
} }
strip.setColor(0, colT[0], colT[1], colT[2], colT[3]);
strip.setColor(1, colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
} }
void setLedsStandard(bool justColors) void setLedsStandard()
{ {
for (byte i=0; i<4; i++)
{
colOld[i] = col[i];
colT[i] = col[i];
colSecOld[i] = colSec[i];
colSecT[i] = colSec[i];
}
if (justColors) return;
briOld = bri; briOld = bri;
briT = bri; briT = bri;
setAllLeds(); setAllLeds();
@ -145,7 +141,7 @@ void colorUpdated(int callMode)
} }
if (briT == 0) if (briT == 0)
{ {
setLedsStandard(true); //do not color transition if starting from off //setLedsStandard(true); //do not color transition if starting from off!
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
} }
@ -160,15 +156,11 @@ void colorUpdated(int callMode)
//set correct delay if not using notification delay //set correct delay if not using notification delay
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
jsonTransitionOnce = false; jsonTransitionOnce = false;
strip.setTransition(transitionDelayTemp);
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;} if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
if (transitionActive) if (transitionActive)
{ {
for (byte i=0; i<4; i++)
{
colOld[i] = colT[i];
colSecOld[i] = colSecT[i];
}
briOld = briT; briOld = briT;
tperLast = 0; tperLast = 0;
} }
@ -177,6 +169,7 @@ void colorUpdated(int callMode)
transitionStartTime = millis(); transitionStartTime = millis();
} else } else
{ {
strip.setTransition(0);
setLedsStandard(); setLedsStandard();
strip.trigger(); strip.trigger();
} }
@ -222,11 +215,6 @@ void handleTransitions()
} }
if (tper - tperLast < 0.004) return; if (tper - tperLast < 0.004) return;
tperLast = tper; tperLast = tper;
for (byte i=0; i<4; i++)
{
colT[i] = colOld[i]+((col[i] - colOld[i])*tper);
colSecT[i] = colSecOld[i]+((colSec[i] - colSecOld[i])*tper);
}
briT = briOld +((bri - briOld )*tper); briT = briOld +((bri - briOld )*tper);
setAllLeds(); setAllLeds();

View File

@ -70,7 +70,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary)
} else { } else {
DEBUG_PRINT(F("LX: segment ")); DEBUG_PRINT(F("LX: segment "));
DEBUG_PRINTLN(segId); DEBUG_PRINTLN(segId);
strip.getSegment(segId).colors[secondary] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))); strip.getSegment(segId).setColor(secondary, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), segId);
} }
} }
} }

View File

@ -244,7 +244,7 @@ bool checkCountdown()
if (countdownMode) localTime = n - countdownTime + utcOffsetSecs; if (countdownMode) localTime = n - countdownTime + utcOffsetSecs;
if (!countdownOverTriggered) if (!countdownOverTriggered)
{ {
if (macroCountdown != 0) applyMacro(macroCountdown); if (macroCountdown != 0) applyPreset(macroCountdown);
countdownOverTriggered = true; countdownOverTriggered = true;
return true; return true;
} }

View File

@ -6,6 +6,7 @@
bool applyPreset(byte index) bool applyPreset(byte index)
{ {
if (index == 0) return false;
if (fileDoc) { if (fileDoc) {
errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD; errorFlag = readObjectFromFileUsingId("/presets.json", index, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
JsonObject fdo = fileDoc->as<JsonObject>(); JsonObject fdo = fileDoc->as<JsonObject>();

View File

@ -541,7 +541,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
strip.applyToAllSelected = true; strip.applyToAllSelected = true;
strip.setColor(2, t[0], t[1], t[2], t[3]); strip.setColor(2, t[0], t[1], t[2], t[3]);
} else { } else {
strip.getSegment(selectedSeg).colors[2] = ((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)); strip.getSegment(selectedSeg).setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg);
} }
} }
@ -667,9 +667,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SB=")); pos = req.indexOf(F("SB="));
if (pos > 0) { if (pos > 0) {
byte segbri = getNumVal(&req, pos); byte segbri = getNumVal(&req, pos);
strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri); strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri, selectedSeg);
if (segbri) { if (segbri) {
strip.getSegment(selectedSeg).opacity = segbri; strip.getSegment(selectedSeg).setOpacity(segbri, selectedSeg);
} }
} }

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2101040 #define VERSION 2101080
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -342,11 +342,7 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
WLED_GLOBAL bool wasConnected _INIT(false); WLED_GLOBAL bool wasConnected _INIT(false);
// color // color
WLED_GLOBAL byte colOld[] _INIT_N(({ 0, 0, 0, 0 })); // color before transition
WLED_GLOBAL byte colT[] _INIT_N(({ 0, 0, 0, 0 })); // color that is currently displayed on the LEDs
WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs
WLED_GLOBAL byte colSecT[] _INIT_N(({ 0, 0, 0, 0 }));
WLED_GLOBAL byte colSecOld[] _INIT_N(({ 0, 0, 0, 0 }));
WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 })); WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 }));
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same