API change.

New SR effects.
Bugfixes.
This commit is contained in:
Blaz Kristan 2022-05-10 00:35:26 +02:00
parent adb7726974
commit c9bdecdb69
4 changed files with 540 additions and 196 deletions

View File

@ -1102,6 +1102,7 @@ uint16_t WS2812FX::mode_comet(void) {
*/
uint16_t WS2812FX::mode_fireworks() {
fade_out(0);
if (SEGENV.call == 0) {
SEGENV.aux0 = UINT16_MAX;
SEGENV.aux1 = UINT16_MAX;
@ -1857,13 +1858,6 @@ uint16_t WS2812FX::mode_fire_2012()
byte* heat = SEGENV.data;
if (SEGENV.call == 0) {
DEBUG_PRINTLN(nFlames);
DEBUG_PRINTLN(SEGLEN);
DEBUG_PRINTLN(nFlames*SEGLEN);
DEBUG_PRINTLN(q);
}
if (it != SEGENV.step) {
SEGENV.step = it;
uint8_t ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels
@ -4248,8 +4242,8 @@ uint16_t WS2812FX::mode_aurora(void) {
///////////////////////////////////////////////////////////////////////////////
//*************************** 2D routines ***********************************
// sample 2D routine
uint16_t WS2812FX::mode_2DBlackHole_A() { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline
// Black hole
uint16_t WS2812FX::mode_2DBlackHole(void) { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * w * h;
@ -4262,24 +4256,24 @@ uint16_t WS2812FX::mode_2DBlackHole_A() { // By: Stepko https://edito
// initialize on first call
if (SEGENV.call == 0) {
for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
leds[x + y * w] = CRGB::Black;
leds[XY(x,y)] = CRGB::Black;
}
}
fadeToBlackBy(32, leds); // create fading trails
fadeToBlackBy(leds, 32); // create fading trails
float t = (float)(millis())/128;
for (byte i = 0; i < 8; i++) {
x = beatsin8(SEGMENT.c1x>>3, 0, w - 1, 0, ((i % 2) ? 128 : 0) + t * i);
y = beatsin8(10 , 0, h - 1, 0, ((i % 2) ? 192 : 64) + t * i);
leds[x + y * w] += CHSV(i*32, 255, 255);
leds[XY(x,y)] += CHSV(i*32, 255, 255);
}
for (byte i = 0; i < 8; i++) {
x = beatsin8(SEGMENT.c2x>>3, w/4, w - 1 - w/4, 0, ((i % 2) ? 128 : 0) + t * i);
y = beatsin8(SEGMENT.c3x>>3, h/4, h - 1 - h/4, 0, ((i % 2) ? 192 : 64) + t * i);
leds[x + y * w] += CHSV(i*32, 255, 255);
leds[XY(x,y)] += CHSV(i*32, 255, 255);
}
leds[w/2 * (1 + h)] = CHSV(0,0,255);
blur2d(16, leds);
leds[XY(w/2,h/2)] = CHSV(0,0,255);
blur2d(leds, 16);
for (y = 0; y < h; y++) for (x = 0; x < w; x++) {
uint16_t o = x + y * w;
@ -4288,26 +4282,356 @@ uint16_t WS2812FX::mode_2DBlackHole_A() { // By: Stepko https://edito
return FRAMETIME;
} // mode_2DBlackHole()
// same as above not using leds[]
uint16_t WS2812FX::mode_2DBlackHole_B() { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
uint16_t x, y;
/////////////////////
// 2D DNA //
/////////////////////
uint16_t WS2812FX::mode_2Ddna(void) { // dna originally by by ldirko at https://pastebin.com/pCkkkzcs. Updated by Preyy. WLED conversion by Andrew Tuline.
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
fade_out2D(32); // create fading trails
float t = (float)(millis())/128;
for (byte i = 0; i < 8; i++) {
x = beatsin8(SEGMENT.c1x>>3, 0, w - 1, 0, ((i % 2) ? 128 : 0) + t * i);
y = beatsin8(10 , 0, h - 1, 0, ((i % 2) ? 192 : 64) + t * i);
setPixelColorXY(x, y, col_to_crgb(getPixelColorXY(x,y)) + CHSV(i*32, 255, 255));
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
fadeToBlackBy(leds, 64);
for(int i = 0; i < width; i++) { // change to height if you want to re-orient, and swap the 4 lines below.
leds[XY(i, beatsin8(SEGMENT.speed/8, 0, height-1, 0, i*4))] = ColorFromPalette(currentPalette, i*5+millis()/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND);
leds[XY(i, beatsin8(SEGMENT.speed/8, 0, height-1, 0, i*4+128))] = ColorFromPalette(currentPalette,i*5+128+millis()/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND); // 180 degrees (128) out of phase
}
for (byte i = 0; i < 8; i++) {
x = beatsin8(SEGMENT.c2x>>3, w/4, w - 1 - w/4, 0, ((i % 2) ? 128 : 0) + t * i);
y = beatsin8(SEGMENT.c3x>>3, h/4, h - 1 - h/4, 0, ((i % 2) ? 192 : 64) + t * i);
setPixelColorXY(x, y, col_to_crgb(getPixelColorXY(x,y)) + CHSV(i*32, 255, 255));
}
setPixelColorXY(w/2, h/2, WHITE);
//blur2d(16);
blur2d(leds, SEGMENT.intensity/8);
setPixels(leds);
return FRAMETIME;
} // mode_2DBlackHole()
} // mode_2Ddna()
/////////////////////////
// 2D DNA Spiral //
/////////////////////////
uint16_t WS2812FX::mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , modified by: Andrew Tuline
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
uint8_t speeds = SEGMENT.speed/2;
uint8_t freq = SEGMENT.intensity/8;
static byte hue = 0;
uint32_t ms = millis() / 20;
nscale8(leds, 120);
for (uint16_t i = 0; i < height; i++) {
uint16_t x = beatsin8(speeds, 0, width - 1, 0, i * freq) + beatsin8(speeds - 7, 0, width - 1, 0, i * freq + 128);
uint16_t x1 = beatsin8(speeds, 0, width - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, width - 1, 0, 128 + 64 + i * freq);
hue = i * 128 / width + ms; //ewowi20210629: not width - 1 to avoid crash if width = 1
if ((i + ms / 8) & 3) {
x = x / 2; x1 = x1 / 2;
byte steps = abs8(x - x1) + 1;
for (byte k = 1; k <= steps; k++) {
byte dx = lerp8by8(x, x1, k * 255 / steps);
uint16_t index = XY(dx, i);
leds[index] += ColorFromPalette(currentPalette, hue, 255, LINEARBLEND);
leds[index] %= (k * 255 / steps); //for draw gradient line
}
leds[XY(x, i)] += CRGB::DarkSlateGray;
leds[XY(x1, i)] += CRGB::White;
}
}
setPixels(leds); // Use this ONLY if we're going to display via leds[x] method.
return FRAMETIME;
} // mode_2DDNASpiral()
/////////////////////////
// 2D Drift //
/////////////////////////
uint16_t WS2812FX::mode_2DDrift() { // By: Stepko https://editor.soulmatelights.com/gallery/884-drift , Modified by: Andrew Tuline
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
#define CenterX ((width / 2) - 0.5)
#define CenterY ((height / 2) - 0.5)
const byte maxDim = max(width, height);
fadeToBlackBy(leds, 128);
unsigned long t = millis() / (32 - SEGMENT.speed/8);
for (float i = 1; i < maxDim / 2; i += 0.25) {
float angle = radians(t * (maxDim / 2 - i));
uint16_t myX = (uint16_t)(CenterX + sin_t(angle) * i);
uint16_t myY = (uint16_t)(CenterY + cos_t(angle) * i);
leds[XY( myX, myY)] += ColorFromPalette(currentPalette, (i * 20) + (t / 20), 255, LINEARBLEND);
}
blur2d(leds, SEGMENT.intensity/8);
setPixels(leds); // Use this ONLY if we're going to display via leds[x] method.
return FRAMETIME;
} // mode_2DDrift()
//////////////////////////
// 2D Firenoise //
//////////////////////////
uint16_t WS2812FX::mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline. Yet another short routine.
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
uint16_t xscale = SEGMENT.intensity*4;
uint32_t yscale = SEGMENT.speed*8;
uint8_t indexx = 0;
currentPalette = CRGBPalette16( CRGB(0,0,0), CRGB(0,0,0), CRGB(0,0,0), CRGB(0,0,0),
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::DarkOrange,
CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange,
CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow);
for (uint16_t j=0; j < width; j++) {
for (uint16_t i=0; i < height; i++) {
indexx = inoise8(j*yscale*height/255, i*xscale+millis()/4); // We're moving along our Perlin map.
leds[XY(j,i)] = ColorFromPalette(currentPalette, min(i*(indexx)>>4, 255), i*255/width, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
} // for i
} // for j
setPixels(leds);
return FRAMETIME;
} // mode_2Dfirenoise()
//////////////////////////////
// 2D Frizzles //
//////////////////////////////
uint16_t WS2812FX::mode_2DFrizzles(void) { // By: Stepko https://editor.soulmatelights.com/gallery/640-color-frizzles , Modified by: Andrew Tuline
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
fadeToBlackBy(leds, 16);
for (byte i = 8; i > 0; i--) {
leds[XY(beatsin8(SEGMENT.speed/8 + i, 0, width - 1), beatsin8(SEGMENT.intensity/8 - i, 0, height - 1))] += ColorFromPalette(currentPalette, beatsin8(12, 0, 255), 255, LINEARBLEND);
}
blur2d(leds, 16);
setPixels(leds);
return FRAMETIME;
} // mode_2DFrizzles()
///////////////////////////////////////////
// 2D Cellular Automata Game of life //
///////////////////////////////////////////
/////////////////////////
// 2D Hiphotic //
/////////////////////////
uint16_t WS2812FX::mode_2DHiphotic() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , Modified by: Andrew Tuline
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
uint32_t a = millis() / 8;
for (uint16_t x = 0; x < width; x++) {
for (uint16_t y = 0; y < height; y++) {
leds[XY(x,y)] = ColorFromPalette(currentPalette, sin8(cos8(x * SEGMENT.speed/16 + a / 3) + sin8(y * SEGMENT.intensity/16 + a / 4) + a), 255, LINEARBLEND);
}
}
setPixels(leds); // Use this ONLY if we're going to display via leds[x] method.
return FRAMETIME;
} // mode_2DHiphotic()
/////////////////////////
// 2D Julia //
/////////////////////////
//////////////////////////////
// 2D Lissajous //
//////////////////////////////
uint16_t WS2812FX::mode_2DLissajous(void) { // By: Andrew Tuline
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
fadeToBlackBy(leds, SEGMENT.intensity);
for (int i=0; i < 256; i ++) {
uint8_t xlocn = sin8(millis()/2+i*SEGMENT.speed/64);
uint8_t ylocn = cos8(millis()/2+i*128/64);
xlocn = map(xlocn,0,255,0,width-1);
ylocn = map(ylocn,0,255,0,height-1);
leds[XY(xlocn,ylocn)] = ColorFromPalette(currentPalette, millis()/100+i, 255, LINEARBLEND);
}
setPixels(leds);
return FRAMETIME;
} // mode_2DLissajous()
///////////////////////
// 2D Matrix //
///////////////////////
uint16_t WS2812FX::mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams. Adapted by Andrew Tuline & improved by merkisoft and ewowi.
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t dataSize = sizeof(CRGB) * width * height;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
if (SEGENV.call == 0) fill_solid(leds, 0);
uint8_t fade = map(SEGMENT.c1x, 0, 255, 50, 250); // equals trail size
uint8_t speed = (256-SEGMENT.speed) >> map(MIN(height, 150), 0, 150, 0, 3); // slower speeds for small displays
CRGB spawnColor;
CRGB trailColor;
if (SEGMENT.c2x > 128) {
spawnColor = SEGCOLOR(0);
trailColor = SEGCOLOR(1);
} else {
spawnColor = CRGB(175,255,175);
trailColor = CRGB(27,130,39);
}
if (millis() - SEGENV.step >= speed) {
SEGENV.step = millis();
for (int16_t row=height-1; row>=0; row--) {
for (int16_t col=0; col<width; col++) {
if (leds[XY(col, row)] == spawnColor) {
leds[XY(col, row)] = trailColor; // create trail
if (row < height-1) leds[XY(col, row+1)] = spawnColor;
}
}
}
// fade all leds
for (int x=0; x<width; x++) for (int y=0; y<height; y++) {
if (leds[XY(x,y)] != spawnColor) leds[XY(x,y)].nscale8(fade); // only fade trail
}
// check for empty screen to ensure code spawn
bool emptyScreen = true;
for (uint16_t x=0; x<width; x++) for (uint16_t y=0; y<height; y++) {
if (leds[XY(x,y)]) {
emptyScreen = false;
break;
}
}
// spawn new falling code
if (random8() < SEGMENT.intensity || emptyScreen) {
uint8_t spawnX = random8(width);
leds[XY(spawnX, 0)] = spawnColor;
}
setPixels(leds);
} // if millis
return FRAMETIME;
} // mode_2Dmatrix()
uint16_t WS2812FX::mode_2DAkemi(void) {
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint16_t counter = (now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF;
counter = counter >> 8;
//Akemi
uint8_t akemi[32][32]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,2,2,3,3,3,3,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,2,3,3,0,0,0,0,0,0,3,3,2,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,2,3,0,0,0,6,5,5,4,0,0,0,3,2,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,2,3,0,0,6,6,5,5,5,5,4,4,0,0,3,2,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,3,2,0,6,5,5,5,5,5,5,5,5,5,5,4,0,2,3,0,0,0,0,0,0,0},
{0,0,0,0,0,0,3,2,3,6,5,5,7,7,5,5,5,5,7,7,5,5,4,3,2,3,0,0,0,0,0,0},
{0,0,0,0,0,2,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,2,0,0,0,0,0},
{0,0,0,0,0,8,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,8,9,0,0,0,0},
{0,0,0,0,0,8,3,1,3,6,5,5,1,1,5,5,5,5,1,1,5,5,4,3,1,3,8,0,0,0,0,0},
{0,0,0,0,0,2,3,1,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,1,3,2,0,0,0,0,0},
{0,0,0,0,0,0,3,2,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,2,3,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,7,7,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,2},
{0,2,2,2,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,2,2,2,0},
{0,0,0,3,2,0,0,0,6,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,2,2,0,0,0},
{0,0,0,3,2,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,2,3,0,0,0},
{0,0,0,0,3,2,0,0,0,0,3,3,0,3,3,0,0,3,3,0,3,3,0,0,0,0,2,2,0,0,0,0},
{0,0,0,0,3,2,0,0,0,0,3,2,0,3,2,0,0,3,2,0,3,2,0,0,0,0,2,3,0,0,0,0},
{0,0,0,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,2,3,0,0,0,0,0},
{0,0,0,0,0,3,2,2,2,2,0,0,0,3,2,0,0,3,2,0,0,0,3,2,2,2,3,0,0,0,0,0},
{0,0,0,0,0,0,3,3,3,0,0,0,0,3,2,0,0,3,2,0,0,0,0,3,3,3,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};
//draw and color Akemi
for (uint16_t y=0; y < height; y++) for (uint16_t x=0; x < width; x++) {
CRGB color = BLACK;
CRGB faceColor = color_wheel(counter);
CRGB armsAndLegsColor = SEGCOLOR(1) > 0 ? SEGCOLOR(1) : 0xFFE0A0; //default warmish white 0xABA8FF; //0xFF52e5;//
CRGB soundColor = ORANGE;
float lightFactor = 0.15;
float normalFactor = 0.4;
float base = 0.0; //fftResult[0]/255.0;
switch (akemi[(y * 32)/height][(x * 32)/width]) {
case 0: color = BLACK; break;
case 3: armsAndLegsColor.r *= lightFactor; armsAndLegsColor.g *= lightFactor; armsAndLegsColor.b *= lightFactor; color = armsAndLegsColor; break; //light arms and legs 0x9B9B9B
case 2: armsAndLegsColor.r *= normalFactor; armsAndLegsColor.g *= normalFactor; armsAndLegsColor.b *= normalFactor; color = armsAndLegsColor; break; //normal arms and legs 0x888888
case 1: color = armsAndLegsColor; break; //dark arms and legs 0x686868
case 6: faceColor.r *= lightFactor; faceColor.g *= lightFactor; faceColor.b *= lightFactor; color=faceColor; break; //light face 0x31AAFF
case 5: faceColor.r *= normalFactor; faceColor.g *= normalFactor; faceColor.b *= normalFactor; color=faceColor; break; //normal face 0x0094FF
case 4: color = faceColor; break; //dark face 0x007DC6
case 7: color = SEGCOLOR(2) > 0 ? SEGCOLOR(2) : 0xFFFFFF; break; //eyes and mouth default white
case 8: if (base > 0.4) {soundColor.r *= base; soundColor.g *= base; soundColor.b *= base; color=soundColor;} else color = armsAndLegsColor; break;
default: color = BLACK;
}
if (SEGMENT.intensity > 128 /*&& fftResult[0] > 128*/) { //dance if base is high
setPixelColorXY(x, 0, BLACK);
setPixelColorXY(x, y+1, color);
} else
setPixelColorXY(x, y, color);
}
//add geq left and right
/*
for (uint16_t x=0; x < width/8; x++) {
uint16_t band = x * width/8;
uint16_t barHeight = map(fftResult[band], 0, 255, 0, 17*height/32);
CRGB color = color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0);
for (uint16_t y=0; y < barHeight; y++) {
setPixelColorXY(x, height/2-y, color);
setPixelColorXY(width-1-x, height/2-y, color);
}
}
*/
return FRAMETIME;
} // mode_2DAkemi

View File

@ -120,8 +120,6 @@
#define REVERSE (uint8_t)0x002
#define SELECTED (uint8_t)0x001
#define MODE_COUNT 120
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
#define FX_MODE_BREATH 2
@ -240,8 +238,18 @@
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
#define FX_MODE_BLACK_HOLE_A 118
#define FX_MODE_BLACK_HOLE_B 119
#define FX_MODE_BLACK_HOLE 118
#define FX_MODE_DNA 119
#define FX_MODE_DNA_SPIRAL 120
#define FX_MODE_DRIFT 121
#define FX_MODE_FIRENOISE 122
#define FX_MODE_FRIZZLES 123
#define FX_MODE_HIPNOTIC 124
#define FX_MODE_LISSAJOUS 125
#define FX_MODE_MATRIX 126
#define FX_MODE_AKEMI 127
#define MODE_COUNT 128
class WS2812FX {
@ -606,8 +614,16 @@ class WS2812FX {
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
_mode[FX_MODE_BLACK_HOLE_A] = &WS2812FX::mode_2DBlackHole_A;
_mode[FX_MODE_BLACK_HOLE_B] = &WS2812FX::mode_2DBlackHole_B;
_mode[FX_MODE_BLACK_HOLE] = &WS2812FX::mode_2DBlackHole;
_mode[FX_MODE_DNA] = &WS2812FX::mode_2Ddna;
_mode[FX_MODE_DNA_SPIRAL] = &WS2812FX::mode_2DDNASpiral;
_mode[FX_MODE_DRIFT] = &WS2812FX::mode_2DDrift;
_mode[FX_MODE_FIRENOISE] = &WS2812FX::mode_2Dfirenoise;
_mode[FX_MODE_FRIZZLES] = &WS2812FX::mode_2DFrizzles;
_mode[FX_MODE_HIPNOTIC] = &WS2812FX::mode_2DHiphotic;
_mode[FX_MODE_LISSAJOUS] = &WS2812FX::mode_2DLissajous;
_mode[FX_MODE_MATRIX] = &WS2812FX::mode_2Dmatrix;
_mode[FX_MODE_AKEMI] = &WS2812FX::mode_2DAkemi;
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@ -863,30 +879,37 @@ class WS2812FX {
void
setUpMatrix(),
setPixelColorXY(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
fill2D(uint32_t),
blur1d(fract8 blur_amount, CRGB* leds=nullptr),
blur2d(fract8 blur_amount, CRGB* leds=nullptr),
blurRows(fract8 blur_amount, CRGB* leds=nullptr),
blurColumns(fract8 blur_amount, CRGB* leds=nullptr),
fill_solid(const struct CRGB& color, CRGB* leds=nullptr),
fade_out2D(uint8_t r),
fadeToBlackBy(uint8_t fadeBy, CRGB* leds=nullptr),
nscale8(uint8_t scale, CRGB* leds=nullptr),
blur1d(CRGB* leds, fract8 blur_amount),
blur2d(CRGB* leds, fract8 blur_amount),
blurRow(uint16_t row, fract8 blur_amount, CRGB* leds=nullptr),
blurCol(uint16_t col, fract8 blur_amount, CRGB* leds=nullptr),
fill_solid(CRGB* leds, const struct CRGB& color),
fadeToBlackBy(CRGB* leds, uint8_t fadeBy),
nscale8(CRGB* leds, uint8_t scale),
setPixels(CRGB* leds);
inline void setPixelColorXY(uint16_t x, uint16_t y, uint32_t c) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); }
inline void setPixelColorXY(uint16_t x, uint16_t y, CRGB &c) { setPixelColorXY(x, y, c.red, c.green, c.blue); }
uint16_t
XY(uint16_t x, uint16_t y, uint8_t seg=255);
XY(uint16_t, uint16_t),
getPixelIndex(uint16_t x, uint16_t y, uint8_t seg=255);
uint32_t
getPixelColorXY(uint16_t, uint16_t);
// 2D modes
uint16_t
mode_2DBlackHole_A(),
mode_2DBlackHole_B();
mode_2DBlackHole(void),
mode_2Ddna(void),
mode_2DDNASpiral(void),
mode_2DDrift(void),
mode_2Dfirenoise(void),
mode_2DFrizzles(void),
mode_2DHiphotic(void),
mode_2DLissajous(void),
mode_2Dmatrix(void),
mode_2DAkemi(void);
// end 2D support
@ -922,6 +945,7 @@ class WS2812FX {
color_wipe(bool, bool),
dynamic(bool),
scan(bool),
fireworks_base(CRGB*),
running_base(bool,bool),
larson_scanner(bool),
sinelon_base(bool,bool),

View File

@ -106,13 +106,20 @@ void WS2812FX::setUpMatrix() {
}
}
// XY(x,y,seg) - returns an index of segment pixel in a matrix layout
// XY(x,y) - gets pixel index within current segment
uint16_t IRAM_ATTR WS2812FX::XY(uint16_t x, uint16_t y) {
uint16_t width = SEGMENT.virtualWidth(); // segment width in logical pixels
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
return x + y * width;
}
// getPixelIndex(x,y,seg) - returns an index of segment pixel in a matrix layout
// index still needs to undergo ledmap processing to represent actual physical pixel
// matrix is always organized by matrixHeight number of matrixWidth pixels from top to bottom, left to right
// so: pixel at XY(5,6) in a 2D segment with [start=10, stop=19, startY=20, stopY=29 : 10x10 pixels]
// so: pixel at getPixelIndex(5,6) in a 2D segment with [start=10, stop=19, startY=20, stopY=29 : 10x10 pixels]
// corresponds to pixel with logical index of 847 (0 based) if a 2D segment belongs to a 32x32 matrix.
// math: (matrixWidth * (startY + y)) + start + x => (32 * (20+6)) + 10 + 5 = 847
uint16_t IRAM_ATTR WS2812FX::XY(uint16_t x, uint16_t y, uint8_t seg) {
uint16_t IRAM_ATTR WS2812FX::getPixelIndex(uint16_t x, uint16_t y, uint8_t seg) {
if (seg == 255) seg = _segment_index;
x %= _segments[seg].width(); // just in case constrain x (wrap around)
y %= _segments[seg].height(); // just in case constrain y (wrap around)
@ -122,8 +129,8 @@ uint16_t IRAM_ATTR WS2812FX::XY(uint16_t x, uint16_t y, uint8_t seg) {
void IRAM_ATTR WS2812FX::setPixelColorXY(uint16_t x, uint16_t y, byte r, byte g, byte b, byte w)
{
if (!isMatrix) return; // not a matrix set-up
uint8_t segIdx = SEGLEN ? _segment_index : _mainSegment;
if (SEGLEN && _bri_t < 255) {
if (_bri_t < 255) {
r = scale8(r, _bri_t);
g = scale8(g, _bri_t);
b = scale8(b, _bri_t);
@ -131,33 +138,33 @@ void IRAM_ATTR WS2812FX::setPixelColorXY(uint16_t x, uint16_t y, byte r, byte g,
}
uint32_t col = RGBW32(r, g, b, w);
uint16_t width = _segments[segIdx].virtualWidth(); // segment width in logical pixels (includes grouping, spacing, mirror & transposed)
uint16_t height = _segments[segIdx].virtualHeight(); // segment height in logical pixels (includes grouping, spacing, mirror & transposed)
if (_segments[segIdx].getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
uint16_t width = SEGMENT.virtualWidth(); // segment width in logical pixels (includes grouping, spacing, mirror & transposed)
uint16_t height = SEGMENT.virtualHeight(); // segment height in logical pixels (includes grouping, spacing, mirror & transposed)
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= _segments[segIdx].groupLength();
y *= _segments[segIdx].groupLength();
x *= SEGMENT.groupLength();
y *= SEGMENT.groupLength();
if (x >= width || y >= height) return; // if pixel would fall out of segment just exit
for (uint8_t j = 0; j < _segments[segIdx].grouping; j++) { // groupping vertically
for (uint8_t g = 0; g < _segments[segIdx].grouping; g++) { // groupping horizontally
for (uint8_t j = 0; j < SEGMENT.grouping; j++) { // groupping vertically
for (uint8_t g = 0; g < SEGMENT.grouping; g++) { // groupping horizontally
uint16_t index, xX = (x+g), yY = (y+j);
if (xX >= width || yY >= height) continue; // we have reached one dimension's end
if (xX >= SEGMENT.width() || yY >= SEGMENT.height()) continue; // we have reached one dimension's end
if (_segments[segIdx].getOption(SEG_OPTION_REVERSED) ) xX = width - xX - 1;
if (_segments[segIdx].getOption(SEG_OPTION_REVERSED_Y)) yY = height - yY - 1;
if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) xX = width - xX - 1;
if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) yY = height - yY - 1;
index = XY(xX, yY, segIdx);
index = getPixelIndex(xX, yY);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
if (_segments[segIdx].getOption(SEG_OPTION_MIRROR)) { //set the corresponding horizontally mirrored pixel
index = XY(_segments[segIdx].width() - xX - 1, yY, segIdx);
if (SEGMENT.getOption(SEG_OPTION_MIRROR)) { //set the corresponding horizontally mirrored pixel
index = getPixelIndex(SEGMENT.width() - xX - 1, yY);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
}
if (_segments[segIdx].getOption(SEG_OPTION_MIRROR_Y)) { //set the corresponding vertically mirrored pixel
index = XY(xX, _segments[segIdx].height() - yY - 1, segIdx);
if (SEGMENT.getOption(SEG_OPTION_MIRROR_Y)) { //set the corresponding vertically mirrored pixel
index = getPixelIndex(xX, SEGMENT.height() - yY - 1);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
}
@ -168,74 +175,70 @@ void IRAM_ATTR WS2812FX::setPixelColorXY(uint16_t x, uint16_t y, byte r, byte g,
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y)
{
uint8_t segIdx = _segment_index;
uint16_t width = _segments[segIdx].virtualWidth(); // segment width in logical pixels
uint16_t height = _segments[segIdx].virtualHeight(); // segment height in logical pixels
if (_segments[segIdx].getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
uint16_t width = SEGMENT.virtualWidth(); // segment width in logical pixels
uint16_t height = SEGMENT.virtualHeight(); // segment height in logical pixels
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= _segments[segIdx].groupLength();
y *= _segments[segIdx].groupLength();
if (x >= width || y >= height) return 0;
x *= SEGMENT.groupLength();
y *= SEGMENT.groupLength();
if (x >= SEGMENT.width() || y >= SEGMENT.height()) return 0;
if (_segments[segIdx].getOption(SEG_OPTION_REVERSED) ) x = width - x - 1;
if (_segments[segIdx].getOption(SEG_OPTION_REVERSED_Y)) y = height - y - 1;
if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) x = width - x - 1;
if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) y = height - y - 1;
uint16_t index = XY(x, y, segIdx);
uint16_t index = getPixelIndex(x, y);
if (index < customMappingSize) index = customMappingTable[index];
return busses.getPixelColor(index);
}
// blurRows: perform a blur1d on every row of a rectangular matrix
void WS2812FX::blurRows(fract8 blur_amount, CRGB* leds)
void WS2812FX::blurRow(uint16_t y, fract8 blur_amount, CRGB* leds)
{
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint16_t y = 0; y < height; y++) for (uint16_t x = 0; x < width; x++) {
CRGB cur = leds ? leds[x + y * width] : col_to_crgb(getPixelColorXY(x,y));
for (uint16_t x = 0; x < width; x++) {
CRGB cur = leds ? leds[XY(x,y)] : col_to_crgb(getPixelColorXY(x,y));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (x) {
if (leds) leds[(x-1) + y * width] += part;
if (leds) leds[XY((x-1),y)] += part;
else setPixelColorXY(x-1, y, col_to_crgb(getPixelColorXY(x-1, y)) + part);
}
if (leds) leds[x + y * width] = cur;
if (leds) leds[XY(x,y)] = cur;
else setPixelColorXY(x, y, cur);
carryover = part;
}
}
// blurColumns: perform a blur1d on each column of a rectangular matrix
void WS2812FX::blurColumns(fract8 blur_amount, CRGB* leds)
void WS2812FX::blurCol(uint16_t x, fract8 blur_amount, CRGB* leds)
{
uint16_t width = SEGMENT.virtualWidth();
uint16_t height = SEGMENT.virtualHeight();
// blur columns
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
for ( uint16_t x = 0; x < width; x++) {
CRGB carryover = CRGB::Black;
for ( uint16_t y = 0; y < height; y++) {
CRGB cur = leds ? leds[x + y * width] : col_to_crgb(getPixelColorXY(x,y));
CRGB cur = leds ? leds[XY(x,y)] : col_to_crgb(getPixelColorXY(x,y));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (y) {
if (leds) leds[x + (y-1) * width] += part;
if (leds) leds[XY(x,(y-1))] += part;
else setPixelColorXY(x, y-1, col_to_crgb(getPixelColorXY(x,y-1)) + part);
}
if (leds) leds[x + y * width] = cur;
if (leds) leds[XY(x,y)] = cur;
else setPixelColorXY(x, y, cur);
carryover = part;
}
}
}
// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
@ -251,86 +254,66 @@ void WS2812FX::blurColumns(fract8 blur_amount, CRGB* leds)
// eventually all the way to black; this is by design so that
// it can be used to (slowly) clear the LEDs to black.
void WS2812FX::blur1d(fract8 blur_amount, CRGB* leds)
void WS2812FX::blur1d(CRGB* leds, fract8 blur_amount)
{
blurRows(blur_amount, leds);
uint16_t height = SEGMENT.virtualHeight();
for ( uint16_t y = 0; y < height; y++)
blurRow(y, blur_amount, leds);
}
void WS2812FX::blur2d(fract8 blur_amount, CRGB* leds)
void WS2812FX::blur2d(CRGB* leds, fract8 blur_amount)
{
blurRows(blur_amount, leds);
blurColumns(blur_amount, leds);
uint16_t w = SEGMENT.virtualWidth(); // same as SEGLEN
uint16_t h = SEGMENT.virtualHeight();
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
for (uint16_t k = 0; k < h; k++) {
CRGB carryover = CRGB::Black;
for(uint16_t i = 0; i < w; i++) {
CRGB cur = leds ? leds[XY(i,k)] : col_to_crgb(getPixelColorXY(i, k));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (i > 0) {
CRGB c = leds ? leds[XY(i,k)] : col_to_crgb(getPixelColorXY(i-1, k));
c += part;
if (leds) leds[XY(i-1,k)] = c;
else setPixelColorXY(i-1, k, c.red, c.green, c.blue);
}
// seep from previous row
if (k > 0) {
CRGB c = col_to_crgb(getPixelColorXY(i, k-1));
c.nscale8(seep);
cur += c;
}
if (leds) leds[XY(i,k)] = cur;
else setPixelColorXY(i, k, cur.red, cur.green, cur.blue);
carryover = part;
}
}
}
//ewowi20210628: new functions moved from colorutils: add segment awareness
/*
* Fills segment with color
*/
void WS2812FX::fill2D(uint32_t c) {
void WS2812FX::fill_solid(CRGB* leds, const struct CRGB& color) {
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
for(uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) {
setPixelColorXY(x, y, c);
}
}
void WS2812FX::fill_solid(const struct CRGB& color, CRGB* leds) {
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
for(uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) {
if (leds) leds[x + y * w] = color;
if (leds) leds[XY(x,y)] = color;
else setPixelColorXY(x, y, color);
}
}
/*
* fade out function, higher rate = quicker fade
* TODO: may be better to use approach of nscale8()
*/
void WS2812FX::fade_out2D(uint8_t rate) {
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1;
uint32_t color = SEGCOLOR(1); // target color
int w2 = W(color);
int r2 = R(color);
int g2 = G(color);
int b2 = B(color);
for(uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) {
color = getPixelColorXY(x, y);
int w1 = W(color);
int r1 = R(color);
int g1 = G(color);
int b1 = B(color);
int wdelta = (w2 - w1) / mappedRate;
int rdelta = (r2 - r1) / mappedRate;
int gdelta = (g2 - g1) / mappedRate;
int bdelta = (b2 - b1) / mappedRate;
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
setPixelColorXY(x, y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
}
void WS2812FX::fadeToBlackBy(CRGB* leds, uint8_t fadeBy) {
nscale8(leds, 255 - fadeBy);
}
void WS2812FX::fadeToBlackBy(uint8_t fadeBy, CRGB* leds) {
nscale8(255 - fadeBy, leds);
}
void WS2812FX::nscale8(uint8_t scale, CRGB* leds) {
void WS2812FX::nscale8(CRGB* leds, uint8_t scale) {
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
for(uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) {
if (leds) leds[x + y * w].nscale8(scale);
if (leds) leds[XY(x,y)].nscale8(scale);
else setPixelColorXY(x, y, col_to_crgb(getPixelColorXY(x, y)).nscale8(scale));
}
}
@ -338,5 +321,5 @@ void WS2812FX::nscale8(uint8_t scale, CRGB* leds) {
void WS2812FX::setPixels(CRGB* leds) {
uint16_t w = SEGMENT.virtualWidth();
uint16_t h = SEGMENT.virtualHeight();
for (uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) setPixelColorXY(x, y, leds[x + y*w]);
for (uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) setPixelColorXY(x, y, leds[XY(x,y)]);
}

View File

@ -185,12 +185,11 @@ void WS2812FX::service() {
void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
{
uint8_t segIdx = SEGLEN ? _segment_index : _mainSegment;
if (isMatrix) {
if (isMatrix && SEGLEN) {
// map linear pixel into 2D segment area (even for 1D segments, expanding vertically)
uint16_t h = _segments[segIdx].height(); // segment height in logical pixels
uint8_t l = _segments[segIdx].groupLength();
for (uint16_t y = 0; y < h; y += l) { // expand 1D effect vertically
setPixelColorXY(i, y, r, g, b, w);
uint16_t h = _segments[segIdx].virtualHeight(); // segment height in logical pixels
for (uint16_t y = 0; y < h; y++) { // expand 1D effect vertically
setPixelColorXY(i, y * _segments[segIdx].groupLength(), r, g, b, w);
}
return;
}
@ -711,9 +710,9 @@ void WS2812FX::resetSegments() {
_segments[0].setOption(SEG_OPTION_ON, 1);
_segments[0].opacity = 255;
_segments[0].cct = 127;
_segments[0].c1x = 0;
_segments[0].c2x = 0;
_segments[0].c3x = 0;
_segments[0].c1x = DEFAULT_C1;
_segments[0].c2x = DEFAULT_C2;
_segments[0].c3x = DEFAULT_C3;
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++)
{
@ -724,9 +723,9 @@ void WS2812FX::resetSegments() {
_segments[i].cct = 127;
_segments[i].speed = DEFAULT_SPEED;
_segments[i].intensity = DEFAULT_INTENSITY;
_segments[i].c1x = 0;
_segments[i].c2x = 0;
_segments[i].c3x = 0;
_segments[i].c1x = DEFAULT_C1;
_segments[i].c2x = DEFAULT_C2;
_segments[i].c3x = DEFAULT_C3;
_segment_runtimes[i].markForReset();
}
_segment_runtimes[0].markForReset();
@ -891,8 +890,11 @@ uint32_t IRAM_ATTR WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint1
* Fills segment with color
*/
void WS2812FX::fill(uint32_t c) {
for(uint16_t i = 0; i < SEGLEN; i++) {
setPixelColor(i, c);
uint16_t w = SEGMENT.virtualWidth(); // same as SEGLEN
uint16_t h = SEGMENT.virtualHeight();
for(uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) {
if (isMatrix) setPixelColorXY(x, y, c);
else setPixelColor(x, c);
}
}
@ -908,6 +910,8 @@ void WS2812FX::blendPixelColor(uint16_t n, uint32_t color, uint8_t blend)
* fade out function, higher rate = quicker fade
*/
void WS2812FX::fade_out(uint8_t rate) {
uint16_t w = SEGMENT.virtualWidth(); // same as SEGLEN
uint16_t h = SEGMENT.virtualHeight();
rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1;
@ -917,8 +921,8 @@ void WS2812FX::fade_out(uint8_t rate) {
int g2 = G(color);
int b2 = B(color);
for(uint16_t i = 0; i < SEGLEN; i++) {
color = getPixelColor(i);
for(uint16_t y = 0; y < h; y++) for (uint16_t x = 0; x < w; x++) {
color = isMatrix ? getPixelColorXY(x, y) : getPixelColor(x);
int w1 = W(color);
int r1 = R(color);
int g1 = G(color);
@ -935,7 +939,8 @@ void WS2812FX::fade_out(uint8_t rate) {
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
setPixelColor(i, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
if (isMatrix) setPixelColorXY(x, y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
else setPixelColor(x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
}
}
@ -1427,8 +1432,16 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Blends@Shift speed,Blend speed;1,2,3,!",
"TV Simulator",
"Dynamic Smooth",
"2D Black Hole A@!,!,C1,C2,C3;!;!",
"2D Black Hole B@!,!,C1,C2,C3;!;!"
"2D Black Hole@!,!,Inner X,Outer X,Outer Y;!,!,!;!",
"2D DNA",
"2D DNA Spiral",
"2D Drift",
"2D Firenoise",
"2D Frizzles",
"2D Hipnotic",
"2D Lissajous",
"2D Matrix@!,!,Fade,Matrix?;!,!,!;!",
"2D Akemi@!,!;!,!;!"
])=====";
const char JSON_palette_names[] PROGMEM = R"=====([