@@ -4669,7 +4669,8 @@ static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;!;01
46694669
46704670
46714671/*
4672- Aurora effect
4672+ Aurora effect by @Mazen
4673+ improved and converted to integer math by @dedehai
46734674*/
46744675
46754676// CONFIG
@@ -4681,140 +4682,138 @@ static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;!;01
46814682#define W_MAX_SPEED 6 // Higher number, higher speed
46824683#define W_WIDTH_FACTOR 6 // Higher number, smaller waves
46834684
4684- // 24 bytes
4685+ // fixed-point math scaling
4686+ #define AW_SHIFT 16
4687+ #define AW_SCALE (1 << AW_SHIFT) // 65536 representing 1.0
4688+
4689+ // 32 bytes
46854690class AuroraWave {
46864691 private:
4692+ int32_t center; // scaled by AW_SCALE
4693+ uint32_t ageFactor_cached; // cached age factor scaled by AW_SCALE
46874694 uint16_t ttl;
4688- CRGB basecolor;
4689- float basealpha;
46904695 uint16_t age;
46914696 uint16_t width;
4692- float center;
4697+ uint16_t basealpha; // scaled by AW_SCALE
4698+ uint16_t speed_factor; // scaled by AW_SCALE
4699+ int16_t wave_start; // wave start LED index
4700+ int16_t wave_end; // wave end LED index
46934701 bool goingleft;
4694- float speed_factor;
46954702 bool alive = true ;
4703+ CRGBW basecolor;
46964704
46974705 public:
4698- void init (uint32_t segment_length, CRGB color) {
4706+ void init (uint32_t segment_length, CRGBW color) {
46994707 ttl = hw_random16 (500 , 1501 );
47004708 basecolor = color;
4701- basealpha = hw_random8 (60 , 101 ) / ( float ) 100 ;
4709+ basealpha = hw_random8 (60 , 100 ) * AW_SCALE / 100 ; // 0-99% note: if using 100% there is risk of integer overflow
47024710 age = 0 ;
4703- width = hw_random16 (segment_length / 20 , segment_length / W_WIDTH_FACTOR); // half of width to make math easier
4704- if (!width) width = 1 ;
4705- center = hw_random8 (101 ) / (float )100 * segment_length;
4706- goingleft = hw_random8 (0 , 2 ) == 0 ;
4707- speed_factor = (hw_random8 (10 , 31 ) / (float )100 * W_MAX_SPEED / 255 );
4711+ width = hw_random16 (segment_length / 20 , segment_length / W_WIDTH_FACTOR) + 1 ;
4712+ center = (((uint32_t )hw_random8 (101 ) << AW_SHIFT) / 100 ) * segment_length; // 0-100%
4713+ goingleft = hw_random8 () & 0x01 ; // 50/50 chance
4714+ speed_factor = (((uint32_t )hw_random8 (10 , 31 ) * W_MAX_SPEED) << AW_SHIFT) / (100 * 255 );
47084715 alive = true ;
47094716 }
47104717
4711- CRGB getColorForLED (int ledIndex) {
4712- if (ledIndex < center - width || ledIndex > center + width) return 0 ; // Position out of range of this wave
4713-
4714- CRGB rgb;
4715-
4716- // Offset of this led from center of wave
4717- // The further away from the center, the dimmer the LED
4718- float offset = ledIndex - center;
4719- if (offset < 0 ) offset = -offset;
4720- float offsetFactor = offset / width;
4721-
4722- // The age of the wave determines it brightness.
4723- // At half its maximum age it will be the brightest.
4724- float ageFactor = 0.1 ;
4725- if ((float )age / ttl < 0.5 ) {
4726- ageFactor = (float )age / (ttl / 2 );
4718+ void updateCachedValues () {
4719+ uint32_t half_ttl = ttl >> 1 ;
4720+ if (age < half_ttl) {
4721+ ageFactor_cached = ((uint32_t )age << AW_SHIFT) / half_ttl;
47274722 } else {
4728- ageFactor = (float )(ttl - age) / (( float )ttl * 0.5 ) ;
4723+ ageFactor_cached = (( uint32_t )(ttl - age) << AW_SHIFT) / half_ttl ;
47294724 }
4725+ if (ageFactor_cached >= AW_SCALE) ageFactor_cached = AW_SCALE - 1 ; // prevent overflow
4726+
4727+ uint32_t center_led = center >> AW_SHIFT;
4728+ wave_start = (int16_t )center_led - (int16_t )width;
4729+ wave_end = (int16_t )center_led + (int16_t )width;
4730+ }
47304731
4731- // Calculate color based on above factors and basealpha value
4732- float factor = (1 - offsetFactor) * ageFactor * basealpha;
4733- rgb.r = basecolor.r * factor;
4734- rgb.g = basecolor.g * factor;
4735- rgb.b = basecolor.b * factor;
4732+ CRGBW getColorForLED (int ledIndex) {
4733+ // linear brightness falloff from center to edge of wave
4734+ if (ledIndex < wave_start || ledIndex > wave_end) return 0 ;
4735+ int32_t ledIndex_scaled = (int32_t )ledIndex << AW_SHIFT;
4736+ int32_t offset = ledIndex_scaled - center;
4737+ if (offset < 0 ) offset = -offset;
4738+ uint32_t offsetFactor = offset / width; // scaled by AW_SCALE
4739+ if (offsetFactor > AW_SCALE) return 0 ; // outside of wave
4740+ uint32_t brightness_factor = (AW_SCALE - offsetFactor);
4741+ brightness_factor = (brightness_factor * ageFactor_cached) >> AW_SHIFT;
4742+ brightness_factor = (brightness_factor * basealpha) >> AW_SHIFT;
4743+
4744+ CRGBW rgb;
4745+ rgb.r = (basecolor.r * brightness_factor) >> AW_SHIFT;
4746+ rgb.g = (basecolor.g * brightness_factor) >> AW_SHIFT;
4747+ rgb.b = (basecolor.b * brightness_factor) >> AW_SHIFT;
4748+ rgb.w = (basecolor.w * brightness_factor) >> AW_SHIFT;
47364749
47374750 return rgb;
47384751 };
47394752
47404753 // Change position and age of wave
4741- // Determine if its sill "alive"
4754+ // Determine if its still "alive"
47424755 void update (uint32_t segment_length, uint32_t speed) {
4743- if (goingleft) {
4744- center -= speed_factor * speed;
4745- } else {
4746- center += speed_factor * speed;
4747- }
4748-
4756+ int32_t step = speed_factor * speed;
4757+ center += goingleft ? -step : step;
47494758 age++;
47504759
4751- if (age > ttl) {
4760+ if (age > ttl) {
47524761 alive = false ;
47534762 } else {
4754- if (goingleft) {
4755- if (center + width < 0 ) {
4756- alive = false ;
4757- }
4758- } else {
4759- if (center - width > segment_length) {
4760- alive = false ;
4761- }
4762- }
4763+ uint32_t width_scaled = (uint32_t )width << AW_SHIFT;
4764+ uint32_t segment_length_scaled = segment_length << AW_SHIFT;
4765+
4766+ if (goingleft) {
4767+ if (center < - (int32_t )width_scaled) {
4768+ alive = false ;
4769+ }
4770+ } else {
4771+ if (center > (int32_t )segment_length_scaled + (int32_t )width_scaled) {
4772+ alive = false ;
4773+ }
4774+ }
47634775 }
47644776 };
47654777
4766- bool stillAlive () {
4767- return alive;
4768- };
4778+ bool stillAlive () { return alive; }
47694779};
47704780
47714781uint16_t mode_aurora (void ) {
47724782 AuroraWave* waves;
47734783 SEGENV.aux1 = map (SEGMENT.intensity , 0 , 255 , 2 , W_MAX_COUNT); // aux1 = Wavecount
4774- if (!SEGENV.allocateData (sizeof (AuroraWave) * SEGENV.aux1 )) { // 20 on ESP32, 9 on ESP8266
4775- return mode_static (); // allocation failed
4784+ if (!SEGENV.allocateData (sizeof (AuroraWave) * SEGENV.aux1 )) {
4785+ return mode_static ();
47764786 }
47774787 waves = reinterpret_cast <AuroraWave*>(SEGENV.data );
47784788
4779- if (SEGENV.call == 0 ) {
4780- for (int i = 0 ; i < SEGENV.aux1 ; i++) {
4781- waves[i].init (SEGLEN, CRGB (SEGMENT.color_from_palette (hw_random8 (), false , false , hw_random8 (0 , 3 ))));
4782- }
4783- }
4784-
4789+ // note: on first call, SEGENV.data is zero -> all waves are dead and will be initialized
47854790 for (int i = 0 ; i < SEGENV.aux1 ; i++) {
4786- // Update values of wave
47874791 waves[i].update (SEGLEN, SEGMENT.speed );
4788-
4789- if (!(waves[i].stillAlive ())) {
4790- // If a wave dies, reinitialize it starts over.
4791- waves[i].init (SEGLEN, CRGB (SEGMENT.color_from_palette (hw_random8 (), false , false , hw_random8 (0 , 3 ))));
4792+ if (!(waves[i].stillAlive ())) {
4793+ waves[i].init (SEGLEN, SEGMENT.color_from_palette (hw_random8 (), false , false , hw_random8 (0 , 3 )));
47924794 }
4795+ waves[i].updateCachedValues ();
47934796 }
47944797
4795- uint8_t backlight = 1 ; // dimmer backlight if less active colors
4798+ uint8_t backlight = 0 ; // note: original code used 1, with inverse gamma applied background would never be black
47964799 if (SEGCOLOR (0 )) backlight++;
47974800 if (SEGCOLOR (1 )) backlight++;
47984801 if (SEGCOLOR (2 )) backlight++;
4799- // Loop through LEDs to determine color
4800- for (unsigned i = 0 ; i < SEGLEN; i++) {
4801- CRGB mixedRgb = CRGB (backlight, backlight, backlight);
4802+ backlight = gamma8inv (backlight); // preserve backlight when using gamma correction
48024803
4803- // For each LED we must check each wave if it is "active" at this position.
4804- // If there are multiple waves active on a LED we multiply their values.
4805- for (int j = 0 ; j < SEGENV.aux1 ; j++) {
4806- CRGB rgb = waves[j].getColorForLED (i);
4804+ for (unsigned i = 0 ; i < SEGLEN; i++) {
4805+ CRGBW mixedRgb = CRGBW (backlight, backlight, backlight);
48074806
4808- if (rgb != CRGB ( 0 ) ) {
4809- mixedRgb += rgb ;
4810- }
4807+ for ( int j = 0 ; j < SEGENV. aux1 ; j++ ) {
4808+ CRGBW rgb = waves[j]. getColorForLED (i) ;
4809+ mixedRgb = color_add (mixedRgb, rgb); // sum all waves influencing this pixel
48114810 }
48124811
4813- SEGMENT.setPixelColor (i, mixedRgb[ 0 ], mixedRgb[ 1 ], mixedRgb[ 2 ] );
4812+ SEGMENT.setPixelColor (i, mixedRgb);
48144813 }
4815-
48164814 return FRAMETIME;
48174815}
4816+
48184817static const char _data_FX_MODE_AURORA[] PROGMEM = " Aurora@!,!;1,2,3;!;;sx=24,pal=50" ;
48194818
48204819// WLED-SR effects
0 commit comments