|
|
|
@@ -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); |
|
|
|
} |