diff --git a/main/main.cpp b/main/main.cpp index 9755e9e..e738b0a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -131,6 +131,8 @@ extern "C" void app_main(void) { LEDStrip *LEDs = new SPI_LEDs(39); //new TerminalLEDs(); while (true) { + // Trash the old preset in case we can't find the set effect + LEDs->setPattern(NULL); Presets::reload(); ESP_LOGI(TAG, "Configuring LEDs"); diff --git a/main/patterns/sparkle.cpp b/main/patterns/sparkle.cpp index 66188e2..951641a 100644 --- a/main/patterns/sparkle.cpp +++ b/main/patterns/sparkle.cpp @@ -9,18 +9,27 @@ static const char *TAG = "random"; #include "presets.hpp" #include "utils.hpp" - +/* static const int8_t ndist[64] = {-127, -104, -92, -84, -77, -72, -67, -62, -58, -55, -51, -48, -45, -42, -39, -37, -34, -32, -29, -27, -25, -22, -20, -18, -16, -14, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 14, 16, 18, 20, 22, 25, 27, 29, 32, 34, 37, 39, 42, 45, 48, 51, 55, 58, 62, 67, 72, 77, 84, 92, 104, 127}; int norm(int mean) { return (mean * 128) / ndist[esp_random() % 64]; } +*/ + +static inline Color fade(Color c, unsigned int i) { + return { + (uint8_t)((c.r * i) / 255), + (uint8_t)((c.g * i) / 255), + (uint8_t)((c.b * i) / 255) + }; +} struct Sparkle { Sparkle() : start_us(0), end_us(0), pos(0) {} - Sparkle(int64_t time_us, int mean_dur_us, int len): + Sparkle(Color _color, int64_t time_us, int mean_dur_us, int len): start_us(time_us), end_us(time_us + (mean_dur_us)), - pos(esp_random() % len) {} + pos(esp_random() % len), color(_color) {} bool expired(int64_t time_us) { return time_us >= end_us; } @@ -31,18 +40,16 @@ struct Sparkle { return (((time_us - start_us) * 255) * 2) / (end_us - start_us); } + Color color_at(int64_t time_us) { + return fade(color, intensity_at(time_us)); + } + int64_t start_us; int64_t end_us; int pos; + Color color; }; -Color fade(Color c, unsigned int i) { - return { - (uint8_t)((c.r * i) / 255), - (uint8_t)((c.g * i) / 255), - (uint8_t)((c.b * i) / 255) - }; -} class SparklePattern : public Pattern { private: @@ -55,51 +62,71 @@ private: }; public: - SparklePattern(Color _color, int _duration_ms, int _delay_ms, int _density) : - color(_color), duration_us(_duration_ms * 1000), + SparklePattern(const Color *_colors, int _n_colors, int _duration_ms, int _delay_ms, int _density) : + n_colors(_n_colors), colors(_colors), + duration_us(_duration_ms * 1000), delay_us(_delay_ms * 1000), density(_density) {} + ~SparklePattern() { if (colors) delete[] colors; } State* start(int len) const { return new State((len / density) + 1); } - void step(Color colors[], int len, Pattern::State *_state) const { + void step(Color pixels[], int len, Pattern::State *_state) const { State *state = (State*)_state; int64_t now_us = time_us(); - memset(colors, 0, sizeof(*colors) * len); + memset(pixels, 0, sizeof(*pixels) * len); int64_t start_us = now_us; - for (int i = 0; i < state->n_sparkles; ++i, start_us += delay_us) { + for (int i = 0; i < state->n_sparkles; ++i, start_us += delay_us / state->n_sparkles) { Sparkle &sparkle = state->sparkles[i]; if (sparkle.expired(now_us)) { - sparkle = Sparkle(start_us, duration_us, len); + sparkle = Sparkle( + colors[esp_random() % n_colors], + start_us, duration_us, len + ); } else { - colors[sparkle.pos] = fade(color, sparkle.intensity_at(now_us)); + pixels[sparkle.pos] = sparkle.color_at(now_us); } } } private: - Color color; + int n_colors; + const Color* colors; int duration_us; int delay_us; int density; }; -Pattern* json_sparkle_pattern(cJSON *pattern, const Presets::ColorMap &colors) { +Pattern* json_sparkle_pattern(cJSON *pattern, const Presets::ColorMap &colormap) { int duration_ms = 250; int delay_ms = 3000; int density = 10; - Color color = {255, 255, 255}; + int n_colors = 0; + Color *colors = NULL; if (pattern->type != cJSON_Object) { ESP_LOGE(TAG, "Not an object: %s", pattern->type); return NULL; } + cJSON *jcolors = cJSON_GetObjectItem(pattern, "colors"); + if (!jcolors || jcolors->type != cJSON_Array) { + ESP_LOGW(TAG, "No colors in %s", pattern->string); + } else { + n_colors = cJSON_GetArraySize(jcolors); + colors = new Color[n_colors]; + int i = 0; + cJSON *jcolor; + cJSON_ArrayForEach(jcolor, jcolors) { + colors[i++] = Presets::json_color(jcolor, colormap); + } + } + cJSON *jnum = cJSON_GetObjectItem(pattern, "delay"); if (jnum) { if (jnum->type != cJSON_Number) { @@ -127,5 +154,10 @@ Pattern* json_sparkle_pattern(cJSON *pattern, const Presets::ColorMap &colors) { } } - return new SparklePattern(color, duration_ms, delay_ms, density); + if (n_colors == 0) { + n_colors = 1; + colors = new Color{255,255,255}; + } + + return new SparklePattern(colors, n_colors, duration_ms, delay_ms, density); } diff --git a/main/presets.json b/main/presets.json index 5f44977..3f0ea55 100644 --- a/main/presets.json +++ b/main/presets.json @@ -6,7 +6,8 @@ "peacock": {"gradient": {"colors": ["purple", "blue", "teal", "black"]}}, "pusheen": {"gradient": {"colors": ["teal", "pink"]}}, "random": {"random": {"gap": 1, "delay": 0.5}}, -"snow": {"sparkle": {"color": "white", "duration": 0.25, "delay": 3, "density": 10}}, +"stars": {"sparkle": {"colors": ["white"], "duration": 0.25, "delay": 3, "density": 20}}, +"pride": {"sparkle": {"colors": ["red", "orange", "yellow", "green", "blue", "purple"], "duration": 0.25, "delay": 3, "density": 1}}, "love": {"gradient": {"colors": ["pink", "black", "red", "black"]}}, "irish": {"gradient": {"colors": ["dark_green", "black", "green", "black"]}},