Skip to content

Commit

Permalink
Add Aurora Borealis effect (Aircoookie#1589)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
Mazn1191 and Aircoookie authored Jan 4, 2021
1 parent f5ed710 commit af61962
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 17 deletions.
159 changes: 150 additions & 9 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#define IBN 5100
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)


/*
* No blinking. Just plain old static light.
*/
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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;
}
11 changes: 5 additions & 6 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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",
Expand All @@ -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
13 changes: 11 additions & 2 deletions wled00/palettes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

0 comments on commit af61962

Please sign in to comment.