ソースを参照

Add multi-color support to sparkle effect

Also fix possible crash when changing presets
master
jrhoffa 3年前
コミット
33d64e37e7
3個のファイルの変更57行の追加22行の削除
  1. +2
    -0
      main/main.cpp
  2. +53
    -21
      main/patterns/sparkle.cpp
  3. +2
    -1
      main/presets.json

+ 2
- 0
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");


+ 53
- 21
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);
}

+ 2
- 1
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"]}},


読み込み中…
キャンセル
保存