Browse Source

garland: unify anim_waves and anim_run to use ColorWave class

pull/2600/head
Dmitry Blinov 5 months ago
parent
commit
3b92cfee02
7 changed files with 117 additions and 136 deletions
  1. +22
    -24
      code/espurna/garland.cpp
  2. +9
    -58
      code/espurna/garland/animations/anim_crossing.h
  3. +11
    -17
      code/espurna/garland/animations/anim_run.h
  4. +11
    -31
      code/espurna/garland/animations/anim_waves.h
  5. +56
    -0
      code/espurna/garland/animations/color_wave.h
  6. +6
    -4
      code/espurna/garland/palette.h
  7. +2
    -2
      code/espurna/garland/scene.h

+ 22
- 24
code/espurna/garland.cpp View File

@ -106,48 +106,48 @@ std::vector<String> _command_sequence;
std::array<Palette, 14> pals {
// palettes below are taken from http://www.color-hex.com/color-palettes/ (and modified)
// RGB: Red,Green,Blue sequence
Palette("RGB", {0xFF0000, 0x00FF00, 0x0000FF}),
Palette("RGB", true, {0xFF0000, 0x00FF00, 0x0000FF}),
// Rainbow: Rainbow colors
Palette("Rainbow", {0xFF0000, 0xFF8000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0x5500AB}),
Palette("Rainbow", true, {0xFF0000, 0xFF8000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0x5500AB}),
// Party: Blue purple ping red orange yellow (and back). Basically, everything but the greens.
// This palette is good for lighting at a club or party.
Palette("Party", {0x5500AB, 0x84007C, 0xB5004B, 0xE5001B, 0xE81700, 0xB84700, 0xAB7700, 0xABAB00,
Palette("Party", false, {0x5500AB, 0x84007C, 0xB5004B, 0xE5001B, 0xE81700, 0xB84700, 0xAB7700, 0xABAB00,
0xAB5500, 0xDD2200, 0xF2000E, 0xC2003E, 0x8F0071, 0x5F00A1, 0x2F00D0, 0x0007F9}),
// Heat: Approximate "black body radiation" palette, akin to the FastLED 'HeatColor' function.
// Recommend that you use values 0-240 rather than the usual 0-255, as the last 15 colors will be
// 'wrapping around' from the hot end to the cold end, which looks wrong.
Palette("Heat", {0x700070, 0xFF0000, 0xFFFF00, 0xFFFFCC}),
Palette("Heat", false, {0x700070, 0xFF0000, 0xFFFF00, 0xFFFFCC}),
// Fire:
Palette("Fire", {0x300000, 0x440000, 0x880000, 0xFF0000, 0xFF6600, 0xFFCC00}),
Palette("Fire", false, {0x300000, 0x440000, 0x880000, 0xFF0000, 0xFF6600, 0xFFCC00}),
// Blue:
Palette("Blue", {0xffffff, 0x0000ff, 0x00ffff}),
Palette("Blue", true, {0xffffff, 0x0000ff, 0x00ffff}),
// Sun: Slice Of The Sun
Palette("Sun", {0xfff95b, 0xffe048, 0xffc635, 0xffad22, 0xff930f}),
Palette("Sun", true, {0xfff95b, 0xffe048, 0xffc635, 0xffad22, 0xff930f}),
// Lime: yellow green mix
Palette("Lime", {0x51f000, 0x6fff00, 0x96ff00, 0xc9ff00, 0xf0ff00}),
Palette("Lime", true, {0x51f000, 0x6fff00, 0x96ff00, 0xc9ff00, 0xf0ff00}),
Palette("Greens", {0xe5f2e5, 0x91f086, 0x48bf53, 0x11823b, 0x008000, 0x004d25, 0x18392b, 0x02231c}),
Palette("Greens", false, {0xe5f2e5, 0x91f086, 0x48bf53, 0x11823b, 0x008000, 0x004d25, 0x18392b, 0x02231c}),
// Pastel: Pastel Fruity Mixture
Palette("Pastel", {0x75aa68, 0x5960ae, 0xe4be6c, 0xca5959, 0x8366ac}),
Palette("Pastel", true, {0x75aa68, 0x5960ae, 0xe4be6c, 0xca5959, 0x8366ac}),
Palette("Summer", {0xb81616, 0xf13057, 0xf68118, 0xf2ab1e, 0xf9ca00, 0xaef133, 0x19ee9f, 0x0ea7b5, 0x0c457d}),
Palette("Summer", true, {0xb81616, 0xf13057, 0xf68118, 0xf2ab1e, 0xf9ca00, 0xaef133, 0x19ee9f, 0x0ea7b5, 0x0c457d}),
Palette("Autumn", {0x8b1509, 0xce7612, 0x11805d, 0x801138, 0x32154b, 0x724c04}),
Palette("Autumn", false, {0x8b1509, 0xce7612, 0x11805d, 0x801138, 0x32154b, 0x724c04}),
Palette("Winter", {0xca9eb8, 0xfeeacf, 0xe0ecf2, 0x89e1c9, 0x72c3c5, 0x92c1ff, 0x3e6589, 0x052542}),
Palette("Winter", true, {0xca9eb8, 0xfeeacf, 0xe0ecf2, 0x89e1c9, 0x72c3c5, 0x92c1ff, 0x3e6589, 0x052542}),
Palette("Gaang", {0xe7a532, 0x46a8ca, 0xaf7440, 0xb4d29d, 0x9f5b72, 0x585c82})
Palette("Gaang", true, {0xe7a532, 0x46a8ca, 0xaf7440, 0xb4d29d, 0x9f5b72, 0x585c82})
};
auto one_color_palette = std::unique_ptr<Palette>(new Palette("White", {0xffffff}));
auto one_color_palette = std::unique_ptr<Palette>(new Palette("White", true, {0xffffff}));
constexpr uint16_t GarlandLeds { GARLAND_LEDS };
constexpr unsigned char GarlandPin { GARLAND_DATA_PIN };
@ -331,7 +331,7 @@ bool executeCommand(const String& command) {
Palette* newPalette = &pals[0];
if (root.containsKey(MQTT_PAYLOAD_PALETTE)) {
if (root.is<int>(MQTT_PAYLOAD_PALETTE)) {
one_color_palette.reset(new Palette("Color", {root[MQTT_PAYLOAD_PALETTE].as<uint32_t>()}));
one_color_palette.reset(new Palette("Color", true, {root[MQTT_PAYLOAD_PALETTE].as<uint32_t>()}));
newPalette = one_color_palette.get();
} else {
auto palette = root[MQTT_PAYLOAD_PALETTE].as<String>();
@ -348,7 +348,7 @@ bool executeCommand(const String& command) {
if (!palette_found) {
const auto result = parseUnsigned(palette);
if (result.ok) {
one_color_palette.reset(new Palette("Color", {result.value}));
one_color_palette.reset(new Palette("Color", true, {result.value}));
newPalette = one_color_palette.get();
}
}
@ -396,14 +396,12 @@ void garlandLoop(void) {
}
if (!scene_setup_done) {
// Anim* newAnim = _currentAnim;
// while (newAnim == _currentAnim) {
// newAnim = anims[secureRandom(START_ANIMATION + 1, anims.size())];
// }
Anim* newAnim = anims[16];
Anim* newAnim = scene.getAnim();
while (newAnim == scene.getAnim()) {
newAnim = anims[secureRandom(START_ANIMATION + 1, anims.size())];
}
Palette* newPalette = &pals[0];
Palette* newPalette = scene.getPalette();
while (newPalette == scene.getPalette()) {
newPalette = &pals[secureRandom(pals.size())];
}


+ 9
- 58
code/espurna/garland/animations/anim_crossing.h View File

@ -3,6 +3,7 @@
#include "../anim.h"
#include "../color.h"
#include "../palette.h"
#include "color_wave.h"
//------------------------------------------------------------------------------
class AnimCrossing : public Anim {
@ -17,7 +18,7 @@ class AnimCrossing : public Anim {
}
void Run() override {
for (int i = 0; i < numLeds; ++i) {
for (auto i = 0; i < numLeds; ++i) {
leds[i] = wave1.getLedColor(i);
leds[i] = leds[i].interpolate(wave2.getLedColor(i), 0.5);
}
@ -27,67 +28,17 @@ class AnimCrossing : public Anim {
}
private:
class ColorWave {
public:
uint16_t numLeds;
Palette* palette;
unsigned int waveLen; // wave length in leds (for clean colors - length of one color), also fade length
bool cleanColors; // if true - use clean colors from palette, else - use interpolated colors
int dir; // moving direction (1 or -1)
float speed; // wave moving speed
byte fade; // wave fade deep - 0 - no fade, 255 - fade to black
ColorWave() = default;
ColorWave(uint16_t _numLeds, Palette* _palette, unsigned int _waveLen, bool _cleanColors, bool _startEmpty, int _dir, float _speed, byte _fade)
: numLeds(_numLeds), palette(_palette), waveLen(_waveLen), cleanColors(_cleanColors), dir(_dir), speed(_speed), fade(_fade) {
if (_startEmpty) {
head = 0;
} else {
head = numLeds - 1;
}
fade_step = fade * 2 / waveLen;
DEBUG_MSG_P(PSTR("[GARLAND] fade_step = %d\n"), fade_step);
}
Color getLedColor(unsigned int ledNum) {
unsigned int real_led_num = dir > 0 ? ledNum : numLeds - ledNum - 1;
// DEBUG_MSG_P(PSTR("[GARLAND] real_led_num = %d, head = %d\n"), real_led_num, (unsigned int)head);
if (real_led_num > head) {
return Color();
}
if (cleanColors) {
unsigned int color_num = (head - real_led_num) / waveLen;
Color c = palette->getCleanColor(color_num);
// DEBUG_MSG_P(PSTR("[GARLAND] color_num = %d, color = %s\n"), color_num, c.to_str().c_str());
return c;
} else {
byte interp_color = (byte)((float)((uint16_t)(head - real_led_num) % numLeds) / (float)numLeds * (float)256);
return palette->getCachedPalColor(interp_color);
}
return Color();
}
void move() {
head = head + speed;
}
private:
float head;
byte fade_step;
};
ColorWave generateWave(int dir) {
unsigned int _waveLen = secureRandom(10, 30);
bool _cleanColors = secureRandom(10) > 5;
bool _startEmpty = secureRandom(10) > 5;
float _speed = secureRandom(5, 20) / 10.0;
byte _fade = secureRandom(0, 256);
unsigned int waveLen = secureRandom(10, 50);
bool cleanColors = secureRandom(10) > 5;
bool startEmpty = secureRandom(10) > 5;
float speed = secureRandom(5, 20) / 10.0;
byte fade = secureRandom(10) > 5 ? 0 : palette->bright() ? secureRandom(180, 220) : 120;
Palette* wavePal = &pals[secureRandom(palsNum)];
DEBUG_MSG_P(PSTR("[GARLAND] Wave created waveLen = %d Pal: %-8s cleanColors = %d startEmpty = %d dir = %d speed = %d fade = %d\n"), _waveLen, wavePal->name(), _cleanColors, _startEmpty, dir, (int)(_speed * 10.0), _fade);
return ColorWave(numLeds, wavePal, _waveLen, _cleanColors, _startEmpty, dir, _speed, _fade);
return ColorWave(numLeds, wavePal, waveLen, cleanColors, fade, speed, dir, startEmpty);
}
ColorWave wave1;


+ 11
- 17
code/espurna/garland/animations/anim_run.h View File

@ -3,6 +3,7 @@
#include "../anim.h"
#include "../color.h"
#include "../palette.h"
#include "color_wave.h"
//------------------------------------------------------------------------------
class AnimRun : public Anim {
@ -11,28 +12,21 @@ class AnimRun : public Anim {
}
void SetupImpl() override {
pos = 0;
inc = 1 + (rngb() >> 5);
if (secureRandom(10) > 5) {
inc = -inc;
}
unsigned int waveLen = secureRandom(10, 30);
bool cleanColors = secureRandom(10) > 7;
byte fade = palette->bright() ? secureRandom(180, 220) : 0;
wave = ColorWave(numLeds, palette, waveLen, cleanColors, fade);
}
void Run() override {
int p = pos;
for (int i = 0; i < numLeds; ++i) {
Color c = palette->getCachedPalColor((byte)p);
leds[i] = c;
p = p + inc;
if (p >= 256) {
p = p - 256;
} else if (p < 0) {
p = p + 256;
}
for (auto i = 0; i < numLeds; ++i) {
leds[i] = wave.getLedColor(i);
}
pos = pos + 1;
wave.move();
}
ColorWave wave;
};
#endif // GARLAND_SUPPORT

+ 11
- 31
code/espurna/garland/animations/anim_waves.h View File

@ -2,54 +2,34 @@
#include "../anim.h"
#include "../palette.h"
#include "color_wave.h"
//------------------------------------------------------------------------------
class AnimWaves : public Anim {
private:
int bra_phase;
int bra_phase_speed;
byte bra_speed;
byte bra_min;
int sign;
public:
AnimWaves() : Anim("Waves") {
}
void SetupImpl() override {
curColor = palette->getRndInterpColor().max_bright();
unsigned int waveLen = secureRandom(50, 100);
bool cleanColors = secureRandom(10) > 7;
byte fade = palette->bright() ? secureRandom(180, 220) : 0;
wave = ColorWave(numLeds, palette, waveLen, cleanColors, fade);
glowSetUp();
sign = braPhaseSpd > 128 ? -1 : 1;
bra_phase = secureRandom(255);
bra_phase_speed = secureRandom(2, 5);
bra_speed = secureRandom(4, 12);
bra_min = secureRandom(20, 30);
}
void Run() override {
int bra = bra_phase;
int8_t bra_inc = -sign * bra_speed;
for (int i = 0; i < numLeds; ++i) {
leds[i] = curColor;
for (auto i = 0; i < numLeds; ++i) {
leds[i] = wave.getLedColor(i);
glowForEachLed(i);
leds[i] = leds[i].brightness((byte)bra);
bra += bra_inc;
if (bra > 255 || bra < bra_min) {
bra_inc = -bra_inc;
bra = bra > 255 ? 255 : bra_min;
}
}
glowRun();
wave.move();
bra_phase += bra_phase_speed;
if (bra_phase > 255 || bra_phase < bra_min) {
bra_phase_speed = -bra_phase_speed;
sign = -sign;
bra_phase = bra_phase > 255 ? 255 : bra_min;
}
glowRun();
}
ColorWave wave;
};
#endif // GARLAND_SUPPORT

+ 56
- 0
code/espurna/garland/animations/color_wave.h View File

@ -0,0 +1,56 @@
#pragma once
class ColorWave {
public:
ColorWave() = default;
/*
_numLeds - number of leds in garland
_palette - palette for wave colors
_waveLen - wave length in leds (for clean colors - length of one color), also fade length
_cleanColors - if true - use clean colors from palette, else - use interpolated colors
_fade - wave fade deep: 0 - no fade, 255 - fade to black
_speed - wave moving speed (0.5 - 2.0)
_dir - moving direction (1 or -1)
_startEmpty - if true - start wave from empty leds, else - start from full leds
*/
ColorWave(uint16_t _numLeds, Palette* _palette, uint16_t _waveLen, bool _cleanColors, byte _fade = 0, float _speed = secureRandom(5, 15) / 10.0, int _dir = secureRandom(10) > 5 ? 1 : -1, bool _startEmpty = false)
: numLeds(_numLeds), palette(_palette), waveLen(_waveLen), cleanColors(_cleanColors), dir(_dir), speed(_speed), fade(_fade) {
DEBUG_MSG_P(PSTR("[GARLAND] Wave: waveLen = %d Pal: %-8s fade = %d cleanColors = %d speed = %d\n"), waveLen, palette->name(), fade, cleanColors, (int)(speed * 10.0));
head = _startEmpty ? 0 : numLeds - 1;
fade_step = fade * 2 / waveLen;
}
Color getLedColor(uint16_t ledNum) {
uint16_t real_led_num = dir > 0 ? ledNum : numLeds - ledNum - 1;
if (real_led_num > head) {
return Color();
}
uint16_t dist_to_head = head - real_led_num;
Color c = cleanColors ? palette->getCleanColor(dist_to_head / waveLen) : palette->getCachedPalColor(dist_to_head * 256 * 20 / waveLen / numLeds);
if (fade_step > 0) {
byte fadeFactor = 255 - abs(waveLen / 2 - (dist_to_head % waveLen)) * fade_step;
c = c.brightness(fadeFactor);
}
return c;
}
void move() {
head += speed;
}
private:
uint16_t numLeds;
Palette* palette;
uint16_t waveLen;
bool cleanColors;
int dir;
float speed;
byte fade;
float head;
byte fade_step;
};

+ 6
- 4
code/espurna/garland/palette.h View File

@ -11,10 +11,11 @@ Inspired by https://github.com/Vasil-Pahomov/ArWs2812 (currently https://github.
class Palette {
public:
Palette(const char* name, std::vector<Color>&& colors) : _name(name), _numColors(colors.size()), _colors(std::move(colors)), _cache(256) {
Palette(const char* name, bool bright, std::vector<Color>&& colors) : _name(name), _bright(bright), _numColors(colors.size()), _colors(std::move(colors)), _cache(256) {
}
const char* name() const { return _name; }
const bool bright() const { return _bright; }
/**
* Get the interpolated color from the palette.
@ -81,7 +82,7 @@ class Palette {
return bestColor;
}
Color getCleanColor(unsigned int i) const {
Color getCleanColor(uint16_t i) const {
return _colors[i % _numColors];
}
@ -89,7 +90,7 @@ class Palette {
int bestDiff = 0;
Color bestColor;
for (unsigned int i = 0; i < _numColors; ++i) {
for (auto i = 0; i < _numColors; ++i) {
Color newColor = _colors[i];
int diff = refColor.howCloseTo(newColor);
if (bestDiff < diff) {
@ -107,7 +108,8 @@ class Palette {
private:
const char* _name;
const unsigned int _numColors;
const bool _bright;
const uint16_t _numColors;
std::vector<Color> _colors;
std::vector<Color> _cache;
};

+ 2
- 2
code/espurna/garland/scene.h View File

@ -44,8 +44,8 @@ public:
byte getBrightness() { return brightness; }
byte getSpeed() { return speed; }
float getCycleFactor(byte speed) { return (float)(GARLAND_SCENE_SPEED_MAX - speed) / GARLAND_SCENE_SPEED_FACTOR; }
const Palette* getPalette() const { return _palette; }
const Anim* getAnim() const { return _anim; }
Palette* getPalette() const { return _palette; }
Anim* getAnim() const { return _anim; }
void setAnim(Anim* anim) { _anim = anim; }
void setPalette(Palette* palette);


Loading…
Cancel
Save