Optimization: color_blend() (#4245)

Removing the bool saves on code size and makes the function a tiny bit faster. Also this is a cleaner solution IMHO.

-updated blend function to optimized 8bit calculation
- efficient color blend calculation in fews operations possible
- omitting min / max checks makes it faster on average
- using 8bit for "blend" variable does not significantly influence the resulting color, just transition points are slightly shifted but yield very good results (and better than the original 16bit version using the old fastled math with improper rounding)
- updated drawCircle and drawLine to use 8bit directly instead of 16bit with a shift
This commit is contained in:
Damian Schneider 2024-12-19 18:20:56 +01:00 committed by GitHub
parent 217d2aeb7f
commit 26397ee8ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 100 deletions

View File

@ -200,7 +200,7 @@ uint16_t color_wipe(bool rev, bool useRandomColors) {
} else } else
{ {
SEGMENT.setPixelColor(index, back? col0 : col1); SEGMENT.setPixelColor(index, back? col0 : col1);
if (i == ledIndex) SEGMENT.setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, rem)); if (i == ledIndex) SEGMENT.setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, uint8_t(rem)));
} }
} }
return FRAMETIME; return FRAMETIME;
@ -271,7 +271,7 @@ uint16_t mode_random_color(void) {
SEGENV.step = it; SEGENV.step = it;
} }
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), fade)); SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), uint8_t(fade)));
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01"; static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01";
@ -338,7 +338,7 @@ uint16_t mode_breath(void) {
var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170
} }
unsigned lum = 30 + var; uint8_t lum = 30 + var;
for (int i = 0; i < SEGLEN; i++) { for (int i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum));
} }
@ -353,7 +353,7 @@ static const char _data_FX_MODE_BREATH[] PROGMEM = "Breathe@!;!,!;!;01";
*/ */
uint16_t mode_fade(void) { uint16_t mode_fade(void) {
unsigned counter = (strip.now * ((SEGMENT.speed >> 3) +10)); unsigned counter = (strip.now * ((SEGMENT.speed >> 3) +10));
unsigned lum = triwave16(counter) >> 8; uint8_t lum = triwave16(counter) >> 8;
for (int i = 0; i < SEGLEN; i++) { for (int i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum));
@ -421,7 +421,7 @@ uint16_t mode_rainbow(void) {
counter = counter >> 8; counter = counter >> 8;
if (SEGMENT.intensity < 128){ if (SEGMENT.intensity < 128){
SEGMENT.fill(color_blend(SEGMENT.color_wheel(counter),WHITE,128-SEGMENT.intensity)); SEGMENT.fill(color_blend(SEGMENT.color_wheel(counter),WHITE,uint8_t(128-SEGMENT.intensity)));
} else { } else {
SEGMENT.fill(SEGMENT.color_wheel(counter)); SEGMENT.fill(SEGMENT.color_wheel(counter));
} }
@ -523,7 +523,7 @@ static uint16_t running_base(bool saw, bool dual=false) {
unsigned b = (SEGLEN-1-i)*x_scale - counter; unsigned b = (SEGLEN-1-i)*x_scale - counter;
uint8_t t = sin_gap(b); uint8_t t = sin_gap(b);
uint32_t cb = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t); uint32_t cb = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t);
ca = color_blend(ca, cb, 127); ca = color_blend(ca, cb, uint8_t(127));
} }
SEGMENT.setPixelColor(i, ca); SEGMENT.setPixelColor(i, ca);
} }
@ -1336,7 +1336,7 @@ uint16_t gradient_base(bool loading) {
val = min(abs(pp-i),min(abs(p1-i),abs(p2-i))); val = min(abs(pp-i),min(abs(p1-i),abs(p2-i)));
} }
val = (brd > val) ? (val * 255) / brd : 255; val = (brd > val) ? (val * 255) / brd : 255;
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), uint8_t(val)));
} }
return FRAMETIME; return FRAMETIME;
@ -1470,7 +1470,7 @@ uint16_t mode_fairy() {
unsigned globalPeakBri = 255 - ((avgFlasherBri * MAX_SHIMMER) >> 8); //183-255, suitable for 1/5th of LEDs flashers unsigned globalPeakBri = 255 - ((avgFlasherBri * MAX_SHIMMER) >> 8); //183-255, suitable for 1/5th of LEDs flashers
for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) { for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) {
unsigned bri = (flasherBri[f - firstFlasher] * globalPeakBri) / 255; uint8_t bri = (flasherBri[f - firstFlasher] * globalPeakBri) / 255;
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number
unsigned flasherPos = f*flasherDistance; unsigned flasherPos = f*flasherDistance;
SEGMENT.setPixelColor(flasherPos, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0), bri)); SEGMENT.setPixelColor(flasherPos, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0), bri));
@ -1521,7 +1521,7 @@ uint16_t mode_fairytwinkle() {
if (flashers[f].stateOn && flashers[f].stateDur > maxDur) flashers[f].stateDur = maxDur; //react more quickly on intensity change if (flashers[f].stateOn && flashers[f].stateDur > maxDur) flashers[f].stateDur = maxDur; //react more quickly on intensity change
if (stateTime > riseFallTime) stateTime = riseFallTime; //for flasher brightness calculation, fades in first 255 ms of state if (stateTime > riseFallTime) stateTime = riseFallTime; //for flasher brightness calculation, fades in first 255 ms of state
unsigned fadeprog = 255 - ((stateTime * 255) / riseFallTime); unsigned fadeprog = 255 - ((stateTime * 255) / riseFallTime);
unsigned flasherBri = (flashers[f].stateOn) ? 255-gamma8(fadeprog) : gamma8(fadeprog); uint8_t flasherBri = (flashers[f].stateOn) ? 255-gamma8(fadeprog) : gamma8(fadeprog);
unsigned lastR = PRNG16; unsigned lastR = PRNG16;
unsigned diff = 0; unsigned diff = 0;
while (diff < 0x4000) { //make sure colors of two adjacent LEDs differ enough while (diff < 0x4000) { //make sure colors of two adjacent LEDs differ enough
@ -1815,7 +1815,7 @@ uint16_t mode_oscillate(void) {
uint32_t color = BLACK; uint32_t color = BLACK;
for (unsigned j = 0; j < numOscillators; j++) { for (unsigned j = 0; j < numOscillators; j++) {
if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128); color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128));
} }
} }
SEGMENT.setPixelColor(i, color); SEGMENT.setPixelColor(i, color);
@ -2508,7 +2508,7 @@ static uint16_t ripple_base() {
int left = rippleorigin - propI -1; int left = rippleorigin - propI -1;
int right = rippleorigin + propI +2; int right = rippleorigin + propI +2;
for (int v = 0; v < 4; v++) { for (int v = 0; v < 4; v++) {
unsigned mag = scale8(cubicwave8((propF>>2) + v * 64), amp); uint8_t mag = scale8(cubicwave8((propF>>2) + v * 64), amp);
SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO
SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO
} }
@ -2551,7 +2551,7 @@ uint16_t mode_ripple_rainbow(void) {
} else { } else {
SEGENV.aux0--; SEGENV.aux0--;
} }
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235)); SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,uint8_t(235)));
return ripple_base(); return ripple_base();
} }
static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12"; static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12";
@ -2670,7 +2670,7 @@ static uint16_t twinklefox_base(bool cat)
} else if (deltabright > 0) { } else if (deltabright > 0) {
// If the new pixel is just slightly brighter than the background color, // If the new pixel is just slightly brighter than the background color,
// mix a blend of the new color and the background color // mix a blend of the new color and the background color
SEGMENT.setPixelColor(i, color_blend(RGBW32(bg.r,bg.g,bg.b,0), RGBW32(c.r,c.g,c.b,0), deltabright * 8)); SEGMENT.setPixelColor(i, color_blend(RGBW32(bg.r,bg.g,bg.b,0), RGBW32(c.r,c.g,c.b,0), uint8_t(deltabright * 8)));
} else { } else {
// if the new pixel is not at all brighter than the background color, // if the new pixel is not at all brighter than the background color,
// just use the background color. // just use the background color.
@ -2766,7 +2766,7 @@ uint16_t mode_halloween_eyes()
const uint32_t eyeColor = SEGMENT.color_from_palette(data.color, false, false, 0); const uint32_t eyeColor = SEGMENT.color_from_palette(data.color, false, false, 0);
uint32_t c = eyeColor; uint32_t c = eyeColor;
if (fadeInAnimationState < 256u) { if (fadeInAnimationState < 256u) {
c = color_blend(backgroundColor, eyeColor, fadeInAnimationState); c = color_blend(backgroundColor, eyeColor, uint8_t(fadeInAnimationState));
} else if (elapsedTime > minimumOnTimeBegin) { } else if (elapsedTime > minimumOnTimeBegin) {
const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime); const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime);
if (remainingTime > minimumOnTimeEnd) { if (remainingTime > minimumOnTimeEnd) {
@ -2919,7 +2919,7 @@ static uint16_t spots_base(uint16_t threshold)
if (wave > threshold) { if (wave > threshold) {
unsigned index = 0 + pos + i; unsigned index = 0 + pos + i;
unsigned s = (wave - threshold)*255 / (0xFFFF - threshold); unsigned s = (wave - threshold)*255 / (0xFFFF - threshold);
SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255-s)); SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s)));
} }
} }
} }
@ -3365,12 +3365,12 @@ uint16_t candle(bool multi)
} }
if (i > 0) { if (i > 0) {
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), uint8_t(s)));
SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep; SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep;
} else { } else {
for (int j = 0; j < SEGLEN; j++) { for (int j = 0; j < SEGLEN; j++) {
SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), s)); SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), uint8_t(s)));
} }
SEGENV.aux0 = s; SEGENV.aux1 = s_target; SEGENV.step = fadeStep; SEGENV.aux0 = s; SEGENV.aux1 = s_target; SEGENV.step = fadeStep;
@ -3488,7 +3488,7 @@ uint16_t mode_starburst(void) {
float age = it-stars[j].birth; float age = it-stars[j].birth;
if (age < particleIgnition) { if (age < particleIgnition) {
c = CRGB(color_blend(WHITE, RGBW32(c.r,c.g,c.b,0), 254.5f*((age / particleIgnition)))); c = CRGB(color_blend(WHITE, RGBW32(c.r,c.g,c.b,0), uint8_t(254.5f*((age / particleIgnition)))));
} else { } else {
// Figure out how much to fade and shrink the star based on // Figure out how much to fade and shrink the star based on
// its age relative to its lifetime // its age relative to its lifetime
@ -3499,8 +3499,7 @@ uint16_t mode_starburst(void) {
} else { } else {
age -= particleIgnition; age -= particleIgnition;
fade = (age / particleFadeTime); // Fading star fade = (age / particleFadeTime); // Fading star
byte f = 254.5f*fade; c = CRGB(color_blend(RGBW32(c.r,c.g,c.b,0), SEGCOLOR(1), uint8_t(254.5f*fade)));
c = CRGB(color_blend(RGBW32(c.r,c.g,c.b,0), SEGCOLOR(1), f));
} }
} }
@ -3639,9 +3638,9 @@ uint16_t mode_exploding_fireworks(void)
uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0); uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
CRGB c = CRGB::Black; //HeatColor(sparks[i].col); CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
if (prog > 300) { //fade from white to spark color if (prog > 300) { //fade from white to spark color
c = CRGB(color_blend(spColor, WHITE, (prog - 300)*5)); c = CRGB(color_blend(spColor, WHITE, uint8_t((prog - 300)*5)));
} else if (prog > 45) { //fade from spark color to black } else if (prog > 45) { //fade from spark color to black
c = CRGB(color_blend(BLACK, spColor, prog - 45)); c = CRGB(color_blend(BLACK, spColor, uint8_t(prog - 45)));
unsigned cooling = (300 - prog) >> 5; unsigned cooling = (300 - prog) >> 5;
c.g = qsub8(c.g, cooling); c.g = qsub8(c.g, cooling);
c.b = qsub8(c.b, cooling * 2); c.b = qsub8(c.b, cooling * 2);
@ -3701,10 +3700,10 @@ uint16_t mode_drip(void)
drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing) drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing)
} }
SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,SEGCOLOR(0), sourcedrop));// water source SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,SEGCOLOR(0), uint8_t(sourcedrop)));// water source
if (drops[j].colIndex==1) { if (drops[j].colIndex==1) {
if (drops[j].col>255) drops[j].col=255; if (drops[j].col>255) drops[j].col=255;
SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col)); SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,SEGCOLOR(0),uint8_t(drops[j].col)));
drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
@ -3721,11 +3720,11 @@ uint16_t mode_drip(void)
for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
unsigned pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally unsigned pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),uint8_t(drops[j].col/i))); //spread pixel with fade while falling
} }
if (drops[j].colIndex > 2) { // during bounce, some water is on the floor if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(SEGCOLOR(0),BLACK,drops[j].col)); SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(SEGCOLOR(0),BLACK,uint8_t(drops[j].col)));
} }
} else { // we hit bottom } else { // we hit bottom
if (drops[j].colIndex > 2) { // already hit once, so back to forming if (drops[j].colIndex > 2) { // already hit once, so back to forming
@ -3948,7 +3947,7 @@ uint16_t mode_heartbeat(void) {
} }
for (int i = 0; i < SEGLEN; i++) { for (int i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - (SEGENV.aux1 >> 8))); SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255 - (SEGENV.aux1 >> 8))));
} }
return FRAMETIME; return FRAMETIME;
@ -4147,7 +4146,7 @@ static uint16_t phased_base(uint8_t moder) { // We're making si
val += *phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline. val += *phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline.
unsigned b = cubicwave8(val); // Now we make an 8 bit sinewave. unsigned b = cubicwave8(val); // Now we make an 8 bit sinewave.
b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light. b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, false, 0), b)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, false, 0), uint8_t(b)));
index += 256 / SEGLEN; index += 256 / SEGLEN;
if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs
} }
@ -4236,7 +4235,7 @@ uint16_t mode_sinewave(void) { // Adjustable sinewave. By Andrew Tul
unsigned freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal. unsigned 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).. uint8_t 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); //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)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri));
} }
@ -4486,7 +4485,7 @@ uint16_t mode_blends(void) {
unsigned dataSize = sizeof(uint32_t) * (pixelLen + 1); // max segment length of 56 pixels on 16 segment ESP8266 unsigned dataSize = sizeof(uint32_t) * (pixelLen + 1); // max segment length of 56 pixels on 16 segment ESP8266
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data); uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
unsigned blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128); uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
unsigned shift = (strip.now * ((SEGMENT.speed >> 3) +1)) >> 8; unsigned shift = (strip.now * ((SEGMENT.speed >> 3) +1)) >> 8;
for (unsigned i = 0; i < pixelLen; i++) { for (unsigned i = 0; i < pixelLen; i++) {
@ -6325,7 +6324,7 @@ static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale
///////////////////////////////// /////////////////////////////////
uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuline. uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuline.
// This currently has no controls. // This currently has no controls.
#define maxsteps 16 // Case statement wouldn't allow a variable. #define MAXSTEPS 16 // Case statement wouldn't allow a variable.
unsigned maxRipples = 16; unsigned maxRipples = 16;
unsigned dataSize = sizeof(Ripple) * maxRipples; unsigned dataSize = sizeof(Ripple) * maxRipples;
@ -6343,7 +6342,6 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
// printUmData(); // printUmData();
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGENV.aux0 = 255;
SEGMENT.custom1 = *binNum; SEGMENT.custom1 = *binNum;
SEGMENT.custom2 = *maxVol * 2; SEGMENT.custom2 = *maxVol * 2;
} }
@ -6374,17 +6372,17 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
break; break;
case 0: case 0:
SEGMENT.setPixelColor(ripples[i].pos, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0)); SEGMENT.setPixelColor(ripples[i].pos, SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0));
ripples[i].state++; ripples[i].state++;
break; break;
case maxsteps: // At the end of the ripples. 254 is an inactive mode. case MAXSTEPS: // At the end of the ripples. 254 is an inactive mode.
ripples[i].state = 254; ripples[i].state = 254;
break; break;
default: // Middle of the ripples. default: // Middle of the ripples.
SEGMENT.setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2)); SEGMENT.setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), uint8_t(2*255/ripples[i].state)));
SEGMENT.setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2)); SEGMENT.setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), uint8_t(2*255/ripples[i].state)));
ripples[i].state++; // Next step. ripples[i].state++; // Next step.
break; break;
} // switch step } // switch step
@ -6504,8 +6502,8 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
for (int i=0; i<tempsamp; i++) { for (int i=0; i<tempsamp; i++) {
uint8_t index = inoise8(i*segmentSampleAvg+strip.now, 5000+i*segmentSampleAvg); uint8_t index = inoise8(i*segmentSampleAvg+strip.now, 5000+i*segmentSampleAvg);
SEGMENT.setPixelColor(i+SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), segmentSampleAvg*8)); SEGMENT.setPixelColor(i+SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), uint8_t(segmentSampleAvg*8)));
SEGMENT.setPixelColor(SEGLEN/2-i-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), segmentSampleAvg*8)); SEGMENT.setPixelColor(SEGLEN/2-i-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), uint8_t(segmentSampleAvg*8)));
} }
if (tempsamp >= gravcen->topLED) if (tempsamp >= gravcen->topLED)
@ -6597,7 +6595,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
for (int i=0; i<tempsamp; i++) { for (int i=0; i<tempsamp; i++) {
uint8_t index = inoise8(i*segmentSampleAvg+strip.now, 5000+i*segmentSampleAvg); uint8_t index = inoise8(i*segmentSampleAvg+strip.now, 5000+i*segmentSampleAvg);
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), segmentSampleAvg*8)); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), uint8_t(segmentSampleAvg*8)));
} }
if (tempsamp >= gravcen->topLED) if (tempsamp >= gravcen->topLED)
@ -6623,7 +6621,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline.
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
SEGMENT.fade_out(224); // 6.25% SEGMENT.fade_out(224); // 6.25%
unsigned my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); uint8_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0);
for (size_t i=0; i<SEGMENT.intensity/32+1U; i++) { for (size_t i=0; i<SEGMENT.intensity/32+1U; i++) {
// if SEGLEN equals 1, we will always set color to the first and only pixel, but the effect is still good looking // if SEGLEN equals 1, we will always set color to the first and only pixel, but the effect is still good looking
@ -6653,7 +6651,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
if(SEGENV.aux0 != secondHand) { if(SEGENV.aux0 != secondHand) {
SEGENV.aux0 = secondHand; SEGENV.aux0 = secondHand;
int pixBri = volumeRaw * SEGMENT.intensity / 64; uint8_t 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(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri)); SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri));
} }
@ -6773,7 +6771,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
if (SEGENV.aux0 != secondHand) { if (SEGENV.aux0 != secondHand) {
SEGENV.aux0 = secondHand; SEGENV.aux0 = secondHand;
int pixBri = volumeRaw * SEGMENT.intensity / 64; uint8_t pixBri = volumeRaw * SEGMENT.intensity / 64;
SEGMENT.setPixelColor(SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri)); SEGMENT.setPixelColor(SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri));
for (int i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left for (int i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left
@ -6912,7 +6910,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
for (int i=0; i <SEGMENT.intensity/8; i++) { for (int i=0; i <SEGMENT.intensity/8; i++) {
unsigned segLoc = random16(SEGLEN); // 16 bit for larger strands of LED's. unsigned segLoc = random16(SEGLEN); // 16 bit for larger strands of LED's.
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(myVals[i%32]+i*4, false, PALETTE_SOLID_WRAP, 0), volumeSmth)); SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(myVals[i%32]+i*4, false, PALETTE_SOLID_WRAP, 0), uint8_t(volumeSmth)));
} }
return FRAMETIME; return FRAMETIME;
@ -6946,11 +6944,11 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
SEGENV.step += FRAMETIME; SEGENV.step += FRAMETIME;
if (SEGENV.step > SPEED_FORMULA_L) { if (SEGENV.step > SPEED_FORMULA_L) {
unsigned segLoc = random16(SEGLEN); unsigned segLoc = random16(SEGLEN);
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), uint8_t(2*fftResult[SEGENV.aux0%16])));
++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16
SEGENV.step = 1; SEGENV.step = 1;
SEGMENT.blur(SEGMENT.intensity); SEGMENT.blur(SEGMENT.intensity); // note: blur > 210 results in a alternating pattern, this could be fixed by mapping but some may like it (very old bug)
} }
return FRAMETIME; return FRAMETIME;
@ -7013,7 +7011,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN.
unsigned pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. unsigned pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index.
if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow
unsigned bright = (int)my_magnitude; uint8_t bright = (uint8_t)my_magnitude;
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), bright)); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), bright));
@ -7100,7 +7098,7 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow
for (int i=0; i < SEGMENT.intensity/32+1; i++) { for (int i=0; i < SEGMENT.intensity/32+1; i++) {
unsigned locn = random16(0,SEGLEN); unsigned locn = random16(0,SEGLEN);
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude));
} }
return FRAMETIME; return FRAMETIME;
@ -7234,12 +7232,12 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli
unsigned locn = inoise16(strip.now*SEGMENT.speed+i*50000, strip.now*SEGMENT.speed); // Get a new pixel location from moving noise. unsigned locn = inoise16(strip.now*SEGMENT.speed+i*50000, strip.now*SEGMENT.speed); // Get a new pixel location from moving noise.
// if SEGLEN equals 1 locn will be always 0, hence we set the first pixel only // if SEGLEN equals 1 locn will be always 0, hence we set the first pixel only
locn = map(locn, 7500, 58000, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. locn = map(locn, 7500, 58000, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over.
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*64, false, PALETTE_SOLID_WRAP, 0), fftResult[i % 16]*4)); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*64, false, PALETTE_SOLID_WRAP, 0), uint8_t(fftResult[i % 16]*4)));
} }
return FRAMETIME; return FRAMETIME;
} // mode_noisemove() } // mode_noisemove()
static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin movement,Fade rate;!,!;!;01f;m12=0,si=0"; // Pixels, Beatsin static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Move speed,Fade rate;!,!;!;01f;m12=0,si=0"; // Pixels, Beatsin
////////////////////// //////////////////////
@ -7314,7 +7312,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
if (samplePeak) { if (samplePeak) {
SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92)); SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92));
} else { } else {
SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude));
} }
// loop will not execute if SEGLEN equals 1 // loop will not execute if SEGLEN equals 1
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

View File

@ -182,7 +182,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
// if blending modes, blend with underlying pixel // if blending modes, blend with underlying pixel
if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); if (_modeBlend) tmpCol = color_blend16(strip.getPixelColorXY(start + xX, startY + yY), col, uint16_t(0xFFFFU - progress()));
#endif #endif
strip.setPixelColorXY(start + xX, startY + yY, tmpCol); strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
@ -513,25 +513,25 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
unsigned oldFade = 0; unsigned oldFade = 0;
while (x < y) { while (x < y) {
float yf = sqrtf(float(rsq - x*x)); // needs to be floating point float yf = sqrtf(float(rsq - x*x)); // needs to be floating point
unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep uint16_t fade = float(0xFF) * (ceilf(yf) - yf); // how much color to keep
if (oldFade > fade) y--; if (oldFade > fade) y--;
oldFade = fade; oldFade = fade;
setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true)); setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade));
setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true)); setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade));
setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true)); setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade));
setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true)); setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade));
setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true)); setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade));
setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true)); setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade));
setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true)); setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade));
setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true)); setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade));
setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true)); setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade));
setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true)); setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade));
setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true)); setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade));
setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true)); setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade));
setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true)); setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade));
setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true)); setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade));
setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true)); setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade));
setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true)); setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade));
x++; x++;
} }
} else { } else {
@ -608,13 +608,13 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0); float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0);
float intersectY = y0; float intersectY = y0;
for (int x = x0; x <= x1; x++) { for (int x = x0; x <= x1; x++) {
unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep uint8_t keep = float(0xFF) * (intersectY-int(intersectY)); // how much color to keep
unsigned seep = 0xFFFF - keep; // how much background to keep uint8_t seep = 0xFF - keep; // how much background to keep
int y = int(intersectY); int y = int(intersectY);
if (steep) std::swap(x,y); // temporaryly swap if steep if (steep) std::swap(x,y); // temporaryly swap if steep
// pixel coverage is determined by fractional part of y co-ordinate // pixel coverage is determined by fractional part of y co-ordinate
setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true)); setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep));
setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true)); setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep));
intersectY += gradient; intersectY += gradient;
if (steep) std::swap(x,y); // restore if steep if (steep) std::swap(x,y); // restore if steep
} }

View File

@ -406,9 +406,9 @@ uint8_t Segment::currentMode() const {
uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const {
if (slot >= NUM_COLORS) slot = 0; if (slot >= NUM_COLORS) slot = 0;
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; return isInTransition() ? color_blend16(_t->_segT._colorT[slot], colors[slot], progress()) : colors[slot];
#else #else
return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot]; return isInTransition() ? color_blend16(_t->_colorT[slot], colors[slot], progress()) : colors[slot];
#endif #endif
} }
@ -819,14 +819,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
indexMir += offset; // offset/phase indexMir += offset; // offset/phase
if (indexMir >= stop) indexMir -= len; // wrap if (indexMir >= stop) indexMir -= len; // wrap
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true); if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, uint16_t(0xFFFFU - progress()));
#endif #endif
strip.setPixelColor(indexMir, tmpCol); strip.setPixelColor(indexMir, tmpCol);
} }
indexSet += offset; // offset/phase indexSet += offset; // offset/phase
if (indexSet >= stop) indexSet -= len; // wrap if (indexSet >= stop) indexSet -= len; // wrap
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true); if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, uint16_t(0xFFFFU - progress()));
#endif #endif
strip.setPixelColor(indexSet, tmpCol); strip.setPixelColor(indexSet, tmpCol);
} }
@ -1083,6 +1083,7 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
/* /*
* blurs segment content, source: FastLED colorutils.cpp * blurs segment content, source: FastLED colorutils.cpp
* Note: for blur_amount > 215 this function does not work properly (creates alternating pattern)
*/ */
void Segment::blur(uint8_t blur_amount, bool smear) { void Segment::blur(uint8_t blur_amount, bool smear) {
if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur" if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur"

View File

@ -5,30 +5,18 @@
*/ */
/* /*
* color blend function * color blend function, based on FastLED blend function
* the calculation for each color is: result = (A*(amountOfA) + A + B*(amountOfB) + B) / 256 with amountOfA = 255 - amountOfB
*/ */
uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { uint32_t color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
if (blend == 0) return color1; // min / max blend checking is omitted: calls with 0 or 255 are rare, checking lowers overall performance
unsigned blendmax = b16 ? 0xFFFF : 0xFF; uint32_t rb1 = color1 & 0x00FF00FF;
if (blend == blendmax) return color2; uint32_t wg1 = (color1>>8) & 0x00FF00FF;
unsigned shift = b16 ? 16 : 8; uint32_t rb2 = color2 & 0x00FF00FF;
uint32_t wg2 = (color2>>8) & 0x00FF00FF;
uint32_t w1 = W(color1); uint32_t rb3 = ((((rb1 << 8) | rb2) + (rb2 * blend) - (rb1 * blend)) >> 8) & 0x00FF00FF;
uint32_t r1 = R(color1); uint32_t wg3 = ((((wg1 << 8) | wg2) + (wg2 * blend) - (wg1 * blend))) & 0xFF00FF00;
uint32_t g1 = G(color1); return rb3 | wg3;
uint32_t b1 = B(color1);
uint32_t w2 = W(color2);
uint32_t r2 = R(color2);
uint32_t g2 = G(color2);
uint32_t b2 = B(color2);
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
return RGBW32(r3, g3, b3, w3);
} }
/* /*

View File

@ -78,7 +78,8 @@ class NeoGammaWLEDMethod {
}; };
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); [[gnu::hot]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); [[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false);
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);