Blending
This commit is contained in:
parent
937e3d0b94
commit
9a87a2ff0d
@ -382,10 +382,8 @@ typedef struct Segment {
|
|||||||
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
|
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
|
||||||
|
|
||||||
typedef struct TemporarySegmentData {
|
typedef struct TemporarySegmentData {
|
||||||
|
uint16_t _optionsT;
|
||||||
uint32_t _colorT[NUM_COLORS];
|
uint32_t _colorT[NUM_COLORS];
|
||||||
//uint8_t _opacityT;
|
|
||||||
//uint8_t _cctT; // temporary CCT
|
|
||||||
//uint16_t _optionsT;
|
|
||||||
uint8_t _speedT;
|
uint8_t _speedT;
|
||||||
uint8_t _intensityT;
|
uint8_t _intensityT;
|
||||||
uint8_t _custom1T, _custom2T; // custom FX parameters/sliders
|
uint8_t _custom1T, _custom2T; // custom FX parameters/sliders
|
||||||
@ -560,8 +558,8 @@ typedef struct Segment {
|
|||||||
// transition functions
|
// transition functions
|
||||||
void startTransition(uint16_t dur); // transition has to start before actual segment values change
|
void startTransition(uint16_t dur); // transition has to start before actual segment values change
|
||||||
void handleTransition(void);
|
void handleTransition(void);
|
||||||
void saveSegenv(tmpsegd_t *tmpSegD);
|
void saveSegenv(tmpsegd_t *tmpSegD = nullptr);
|
||||||
void restoreSegenv(tmpsegd_t *tmpSegD);
|
void restoreSegenv(tmpsegd_t *tmpSegD = nullptr);
|
||||||
uint16_t progress(void); //transition progression between 0-65535
|
uint16_t progress(void); //transition progression between 0-65535
|
||||||
uint8_t currentBri(uint8_t briNew, bool useCct = false);
|
uint8_t currentBri(uint8_t briNew, bool useCct = false);
|
||||||
uint8_t currentMode(uint8_t modeNew);
|
uint8_t currentMode(uint8_t modeNew);
|
||||||
|
@ -216,23 +216,27 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
|||||||
y *= groupLength(); // expand to physical pixels
|
y *= groupLength(); // expand to physical pixels
|
||||||
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
|
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
|
||||||
|
|
||||||
|
uint32_t tmpCol = col;
|
||||||
for (int j = 0; j < grouping; j++) { // groupping vertically
|
for (int j = 0; j < grouping; j++) { // groupping vertically
|
||||||
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
||||||
uint16_t xX = (x+g), yY = (y+j);
|
uint16_t xX = (x+g), yY = (y+j);
|
||||||
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
|
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
|
||||||
|
|
||||||
strip.setPixelColorXY(start + xX, startY + yY, col);
|
// if blending modes, blend with underlying pixel
|
||||||
|
if (transitional && _t && currentMode(mode) != _t->_modeT) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, progress(), true);
|
||||||
|
|
||||||
|
strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
|
||||||
|
|
||||||
if (mirror) { //set the corresponding horizontally mirrored pixel
|
if (mirror) { //set the corresponding horizontally mirrored pixel
|
||||||
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
|
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
||||||
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
|
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
||||||
}
|
}
|
||||||
if (mirror_y) { //set the corresponding vertically mirrored pixel
|
if (mirror_y) { //set the corresponding vertically mirrored pixel
|
||||||
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
|
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
||||||
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
|
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
||||||
}
|
}
|
||||||
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||||
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col);
|
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,9 +288,7 @@ void Segment::startTransition(uint16_t dur) {
|
|||||||
_t = new Transition(dur); // no previous transition running
|
_t = new Transition(dur); // no previous transition running
|
||||||
if (!_t) return; // failed to allocate data
|
if (!_t) return; // failed to allocate data
|
||||||
|
|
||||||
DEBUG_PRINT(F("-- Saving transition environment. "));
|
saveSegenv();
|
||||||
DEBUG_PRINTLN(on ? opacity : 0);
|
|
||||||
saveSegenv(&(_t->_tmpSeg));
|
|
||||||
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
||||||
_t->_palT = _palT;
|
_t->_palT = _palT;
|
||||||
_t->_modeT = mode;
|
_t->_modeT = mode;
|
||||||
@ -328,18 +326,14 @@ uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Segment::currentMode(uint8_t newMode) {
|
uint8_t Segment::currentMode(uint8_t newMode) {
|
||||||
uint16_t prog = progress();
|
uint16_t prog = progress(); // implicit check for transitional & _t in progress()
|
||||||
if (prog < 0xFFFFU) { // implicit check for transitional & _t in progress()
|
if (prog < 0xFFFFU) return _t->_modeT;
|
||||||
restoreSegenv(&(_t->_tmpSeg));
|
|
||||||
opacity -= (uint32_t)opacity * prog / 0xFFFFU;
|
|
||||||
return _t->_modeT;
|
|
||||||
}
|
|
||||||
return newMode;
|
return newMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::saveSegenv(tmpsegd_t *tmpSeg) {
|
void Segment::saveSegenv(tmpsegd_t *tmpSeg) {
|
||||||
//tmpSeg._opacityT = on ? opacity : 0;
|
if (tmpSeg == nullptr) { if (_t) tmpSeg = &(_t->_tmpSeg); else return; }
|
||||||
//tmpSeg._optionsT = options;
|
tmpSeg->_optionsT = options;
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) tmpSeg->_colorT[i] = colors[i];
|
for (size_t i=0; i<NUM_COLORS; i++) tmpSeg->_colorT[i] = colors[i];
|
||||||
tmpSeg->_speedT = speed;
|
tmpSeg->_speedT = speed;
|
||||||
tmpSeg->_intensityT = intensity;
|
tmpSeg->_intensityT = intensity;
|
||||||
@ -358,17 +352,19 @@ void Segment::saveSegenv(tmpsegd_t *tmpSeg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Segment::restoreSegenv(tmpsegd_t *tmpSeg) {
|
void Segment::restoreSegenv(tmpsegd_t *tmpSeg) {
|
||||||
if (&(_t->_tmpSeg) != tmpSeg) {
|
if (tmpSeg == nullptr) {
|
||||||
DEBUG_PRINTF("Temp: %p != %p\n", &(_t->_tmpSeg), tmpSeg);
|
if (_t) tmpSeg = &(_t->_tmpSeg);
|
||||||
DEBUG_PRINTLN(F("-- Restoring OLD environment."));
|
else return;
|
||||||
// update possibly changed variables to keep old effect running correctly
|
} else {
|
||||||
_t->_tmpSeg._aux0T = aux0;
|
if (&(_t->_tmpSeg) != tmpSeg) {
|
||||||
_t->_tmpSeg._aux1T = aux1;
|
// update possibly changed variables to keep old effect running correctly
|
||||||
_t->_tmpSeg._stepT = step;
|
_t->_tmpSeg._aux0T = aux0;
|
||||||
_t->_tmpSeg._callT = call;
|
_t->_tmpSeg._aux1T = aux1;
|
||||||
|
_t->_tmpSeg._stepT = step;
|
||||||
|
_t->_tmpSeg._callT = call;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//opacity = tmpSeg._opacityT;
|
options = tmpSeg->_optionsT;
|
||||||
//options = tmpSeg._optionsT;
|
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = tmpSeg->_colorT[i];
|
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = tmpSeg->_colorT[i];
|
||||||
speed = tmpSeg->_speedT;
|
speed = tmpSeg->_speedT;
|
||||||
intensity = tmpSeg->_intensityT;
|
intensity = tmpSeg->_intensityT;
|
||||||
@ -703,6 +699,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
|||||||
}
|
}
|
||||||
i += start; // starting pixel in a group
|
i += start; // starting pixel in a group
|
||||||
|
|
||||||
|
uint32_t tmpCol = col;
|
||||||
// set all the pixels in the group
|
// set all the pixels in the group
|
||||||
for (int j = 0; j < grouping; j++) {
|
for (int j = 0; j < grouping; j++) {
|
||||||
uint16_t indexSet = i + ((reverse) ? -j : j);
|
uint16_t indexSet = i + ((reverse) ? -j : j);
|
||||||
@ -711,11 +708,13 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
|||||||
uint16_t indexMir = stop - indexSet + start - 1;
|
uint16_t indexMir = stop - indexSet + start - 1;
|
||||||
indexMir += offset; // offset/phase
|
indexMir += offset; // offset/phase
|
||||||
if (indexMir >= stop) indexMir -= len; // wrap
|
if (indexMir >= stop) indexMir -= len; // wrap
|
||||||
strip.setPixelColor(indexMir, col);
|
if (transitional && _t && currentMode(mode) != _t->_modeT) tmpCol = color_blend(strip.getPixelColor(indexMir), col, progress(), true);
|
||||||
|
strip.setPixelColor(indexMir, tmpCol);
|
||||||
}
|
}
|
||||||
indexSet += offset; // offset/phase
|
indexSet += offset; // offset/phase
|
||||||
if (indexSet >= stop) indexSet -= len; // wrap
|
if (indexSet >= stop) indexSet -= len; // wrap
|
||||||
strip.setPixelColor(indexSet, col);
|
if (transitional && _t && currentMode(mode) != _t->_modeT) tmpCol = color_blend(strip.getPixelColor(indexSet), col, progress(), true);
|
||||||
|
strip.setPixelColor(indexSet, tmpCol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1176,24 +1175,22 @@ void WS2812FX::service() {
|
|||||||
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
||||||
|
|
||||||
// Effect blending (execute previous effect then new effect while in transition)
|
// Effect blending (execute previous effect then new effect while in transition)
|
||||||
// WARNING: seg.currentMode(mode) (while in transition) will overwrite SEGENV variables!!!
|
// If two effects are being blended (each may have different segment settings), those
|
||||||
// so they need to be saved first and then restored before running new mode.
|
// settings need to be saved first and then restored before running new mode.
|
||||||
|
// The seetings need to be applied from transition buffer for previous effect.
|
||||||
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
||||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||||
// would need to be allocated for each effect and then blended together for each pixel.
|
// would need to be allocated for each effect and then blended together for each pixel.
|
||||||
Segment::tmpsegd_t _tmpSegData;
|
Segment::tmpsegd_t _tmpSegData;
|
||||||
seg.saveSegenv(&_tmpSegData);
|
seg.saveSegenv(&_tmpSegData);
|
||||||
uint8_t newMode = seg.mode;
|
uint8_t tmpMode = seg.currentMode(seg.mode);
|
||||||
uint8_t newOpacity = seg.opacity;
|
if (seg.mode != tmpMode) seg.restoreSegenv(nullptr); // restore transition data (including temporary opacity)
|
||||||
uint8_t tmpMode = seg.currentMode(seg.mode);
|
|
||||||
delay = (*_mode[tmpMode])(); // run old mode
|
delay = (*_mode[tmpMode])(); // run old mode
|
||||||
if (newMode != tmpMode) {
|
if (seg.mode != tmpMode) {
|
||||||
if (tmpMode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
if (tmpMode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||||
seg.restoreSegenv(&_tmpSegData); // restore mode state
|
seg.restoreSegenv(&_tmpSegData); // restore mode state
|
||||||
seg.opacity = (uint32_t)newOpacity * seg.progress() / 0xFFFFU;
|
uint16_t d2 = (*_mode[seg.mode])(); // run new mode
|
||||||
delay += (*_mode[seg.mode])(); // run new mode
|
delay = MIN(delay,d2); // use shortest delay
|
||||||
delay /= 2; // average the delay
|
|
||||||
seg.opacity = newOpacity;
|
|
||||||
}
|
}
|
||||||
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||||
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2308030
|
#define VERSION 2308050
|
||||||
|
|
||||||
//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
|
||||||
|
Loading…
Reference in New Issue
Block a user