Add Aurora Borealis effect (#1589)

* Added aurora effect

* Cosmetic changes prior to PR to match some guidelines

* Update FX.cpp

Moved mode_aurora function to end of FX.cpp

* Cosmetic changes prior to PR

- Changed new palette name to have a whitespace
- Undid changes to platformio.ini

* Removed commented out test palette

* Improved memory handling

Use SEGENV to allocate and manage dynamic memory needs of effect.
Only allocate as much memory as needed for current amount of waves set.

* Improvements to Aurora effect

- Smoother on low speed
- CRGB is trivially copiable
- Replaced Red & Blue mode
- Simplified logic and mem use a tiny bit
- Aurora2 palette a bit less yellowish

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
This commit is contained in:
Mazen 2021-01-04 11:11:36 +01:00 committed by GitHub
parent f5ed710c0b
commit af61962314
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 166 additions and 17 deletions

View File

@ -30,7 +30,6 @@
#define IBN 5100
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
/*
* No blinking. Just plain old static light.
*/
@ -1003,14 +1002,6 @@ uint16_t WS2812FX::mode_running_color(void) {
}
/*
* Alternating red/blue pixels running.
*/
uint16_t WS2812FX::mode_running_red_blue(void) {
return running(RED, BLUE);
}
/*
* Alternating red/green pixels running.
*/
@ -3880,3 +3871,153 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
return FRAMETIME;
#endif
}
/*
Aurora effect
*/
//CONFIG
#define BACKLIGHT 5
#define W_MAX_COUNT 20 //Number of simultaneous waves
#define W_MAX_SPEED 6 //Higher number, higher speed
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
class AuroraWave {
private:
uint16_t ttl;
CRGB basecolor;
float basealpha;
uint16_t age;
uint16_t width;
float center;
bool goingleft;
float speed_factor;
bool alive = true;
public:
void init(uint32_t segment_length, CRGB color) {
ttl = random(500, 1501);
basecolor = color;
basealpha = random(60, 101) / (float)100;
age = 0;
width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
if (!width) width = 1;
center = random(101) / (float)100 * segment_length;
goingleft = random(0, 2) == 0;
speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
alive = true;
}
CRGB getColorForLED(int ledIndex) {
if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave
CRGB rgb;
//Offset of this led from center of wave
//The further away from the center, the dimmer the LED
float offset = ledIndex - center;
if (offset < 0) offset = -offset;
float offsetFactor = offset / width;
//The age of the wave determines it brightness.
//At half its maximum age it will be the brightest.
float ageFactor = 0.1;
if((float)age / ttl < 0.5) {
ageFactor = (float)age / (ttl / 2);
} else {
ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
}
//Calculate color based on above factors and basealpha value
float factor = (1 - offsetFactor) * ageFactor * basealpha;
rgb.r = basecolor.r * factor;
rgb.g = basecolor.g * factor;
rgb.b = basecolor.b * factor;
return rgb;
};
//Change position and age of wave
//Determine if its sill "alive"
void update(uint32_t segment_length, uint32_t speed) {
if(goingleft) {
center -= speed_factor * speed;
} else {
center += speed_factor * speed;
}
age++;
if(age > ttl) {
alive = false;
} else {
if(goingleft) {
if(center + width < 0) {
alive = false;
}
} else {
if(center - width > segment_length) {
alive = false;
}
}
}
};
bool stillAlive() {
return alive;
};
};
uint16_t WS2812FX::mode_aurora(void) {
//aux1 = Wavecount
//aux2 = Intensity in last loop
AuroraWave* waves;
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
//Intensity slider changed or first call
SEGENV.aux1 = ((float)SEGMENT.intensity / 255) * W_MAX_COUNT;
SEGENV.aux0 = SEGMENT.intensity;
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) {
return mode_static(); //allocation failed
}
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
for(int i = 0; i < SEGENV.aux1; i++) {
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
}
} else {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
}
for(int i = 0; i < SEGENV.aux1; i++) {
//Update values of wave
waves[i].update(SEGLEN, SEGMENT.speed);
if(!(waves[i].stillAlive())) {
//If a wave dies, reinitialize it starts over.
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
}
}
//Loop through LEDs to determine color
for(int i = 0; i < SEGLEN; i++) {
CRGB mixedRgb = CRGB(BACKLIGHT, BACKLIGHT, BACKLIGHT);
//For each LED we must check each wave if it is "active" at this position.
//If there are multiple waves active on a LED we multiply their values.
for(int j = 0; j < SEGENV.aux1; j++) {
CRGB rgb = waves[j].getColorForLED(i);
if(rgb != CRGB(0)) {
mixedRgb += rgb;
}
}
setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2], BACKLIGHT);
}
return FRAMETIME;
}

View File

@ -119,7 +119,6 @@
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
#define MODE_COUNT 118
#define FX_MODE_STATIC 0
@ -160,7 +159,7 @@
#define FX_MODE_TRAFFIC_LIGHT 35
#define FX_MODE_COLOR_SWEEP_RANDOM 36
#define FX_MODE_RUNNING_COLOR 37
#define FX_MODE_RUNNING_RED_BLUE 38
#define FX_MODE_AURORA 38
#define FX_MODE_RUNNING_RANDOM 39
#define FX_MODE_LARSON_SCANNER 40
#define FX_MODE_COMET 41
@ -389,7 +388,7 @@ class WS2812FX {
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
_mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue;
_mode[FX_MODE_AURORA] = &WS2812FX::mode_aurora;
_mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
@ -603,7 +602,7 @@ class WS2812FX {
mode_colorful(void),
mode_traffic_light(void),
mode_running_color(void),
mode_running_red_blue(void),
mode_aurora(void),
mode_running_random(void),
mode_larson_scanner(void),
mode_comet(void),
@ -764,7 +763,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream",
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
@ -782,7 +781,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
"Aurora","Atlantica","C9 2","C9 New","Temperature"
"Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2"
])=====";
#endif

View File

@ -13,7 +13,7 @@
#ifndef PalettesWLED_h
#define PalettesWLED_h
#define GRADIENT_PALETTE_COUNT 42
#define GRADIENT_PALETTE_COUNT 43
const byte ib_jul01_gp[] PROGMEM = {
0, 194, 1, 1,
@ -631,6 +631,14 @@ const byte temperature_gp[] PROGMEM = {
240, 80, 3, 3,
255, 80, 3, 3};
const byte Aurora2[] PROGMEM = {
0, 17, 177, 13, //Greenish
64, 121, 242, 5, //Greenish
128, 25, 173, 121, //Turquoise
192, 250, 77, 127, //Pink
255, 171, 101, 221 //Purple
};
// Single array of defined cpt-city color palettes.
// This will let us programmatically choose one based on
// a number, rather than having to activate each explicitly
@ -677,7 +685,8 @@ const byte* const gGradientPalettes[] PROGMEM = {
Atlantica_gp, //51-38 Atlantica
C9_2_gp, //52-39 C9 2
C9_new_gp, //53-40 C9 New
temperature_gp //54-41 Temperature
temperature_gp, //54-41 Temperature
Aurora2 //55-42 Aurora 2
};
#endif