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:
parent
f5ed710c0b
commit
af61962314
159
wled00/FX.cpp
159
wled00/FX.cpp
@ -30,7 +30,6 @@
|
|||||||
#define IBN 5100
|
#define IBN 5100
|
||||||
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
|
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No blinking. Just plain old static light.
|
* 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.
|
* Alternating red/green pixels running.
|
||||||
*/
|
*/
|
||||||
@ -3880,3 +3871,153 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
#endif
|
#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;
|
||||||
|
}
|
11
wled00/FX.h
11
wled00/FX.h
@ -119,7 +119,6 @@
|
|||||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||||
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
||||||
|
|
||||||
|
|
||||||
#define MODE_COUNT 118
|
#define MODE_COUNT 118
|
||||||
|
|
||||||
#define FX_MODE_STATIC 0
|
#define FX_MODE_STATIC 0
|
||||||
@ -160,7 +159,7 @@
|
|||||||
#define FX_MODE_TRAFFIC_LIGHT 35
|
#define FX_MODE_TRAFFIC_LIGHT 35
|
||||||
#define FX_MODE_COLOR_SWEEP_RANDOM 36
|
#define FX_MODE_COLOR_SWEEP_RANDOM 36
|
||||||
#define FX_MODE_RUNNING_COLOR 37
|
#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_RUNNING_RANDOM 39
|
||||||
#define FX_MODE_LARSON_SCANNER 40
|
#define FX_MODE_LARSON_SCANNER 40
|
||||||
#define FX_MODE_COMET 41
|
#define FX_MODE_COMET 41
|
||||||
@ -389,7 +388,7 @@ class WS2812FX {
|
|||||||
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
|
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
|
||||||
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
|
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
|
||||||
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
|
_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_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
|
||||||
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
|
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
|
||||||
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
|
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
|
||||||
@ -603,7 +602,7 @@ class WS2812FX {
|
|||||||
mode_colorful(void),
|
mode_colorful(void),
|
||||||
mode_traffic_light(void),
|
mode_traffic_light(void),
|
||||||
mode_running_color(void),
|
mode_running_color(void),
|
||||||
mode_running_red_blue(void),
|
mode_aurora(void),
|
||||||
mode_running_random(void),
|
mode_running_random(void),
|
||||||
mode_larson_scanner(void),
|
mode_larson_scanner(void),
|
||||||
mode_comet(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",
|
"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",
|
"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",
|
"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",
|
"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",
|
"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",
|
"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",
|
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
|
||||||
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
|
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
|
||||||
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
|
"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
|
#endif
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#ifndef PalettesWLED_h
|
#ifndef PalettesWLED_h
|
||||||
#define PalettesWLED_h
|
#define PalettesWLED_h
|
||||||
|
|
||||||
#define GRADIENT_PALETTE_COUNT 42
|
#define GRADIENT_PALETTE_COUNT 43
|
||||||
|
|
||||||
const byte ib_jul01_gp[] PROGMEM = {
|
const byte ib_jul01_gp[] PROGMEM = {
|
||||||
0, 194, 1, 1,
|
0, 194, 1, 1,
|
||||||
@ -631,6 +631,14 @@ const byte temperature_gp[] PROGMEM = {
|
|||||||
240, 80, 3, 3,
|
240, 80, 3, 3,
|
||||||
255, 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.
|
// Single array of defined cpt-city color palettes.
|
||||||
// This will let us programmatically choose one based on
|
// This will let us programmatically choose one based on
|
||||||
// a number, rather than having to activate each explicitly
|
// a number, rather than having to activate each explicitly
|
||||||
@ -677,7 +685,8 @@ const byte* const gGradientPalettes[] PROGMEM = {
|
|||||||
Atlantica_gp, //51-38 Atlantica
|
Atlantica_gp, //51-38 Atlantica
|
||||||
C9_2_gp, //52-39 C9 2
|
C9_2_gp, //52-39 C9 2
|
||||||
C9_new_gp, //53-40 C9 New
|
C9_new_gp, //53-40 C9 New
|
||||||
temperature_gp //54-41 Temperature
|
temperature_gp, //54-41 Temperature
|
||||||
|
Aurora2 //55-42 Aurora 2
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user