diff --git a/usermods/user_fx/README.md b/usermods/user_fx/README.md new file mode 100644 index 0000000000..8dc1d128ef --- /dev/null +++ b/usermods/user_fx/README.md @@ -0,0 +1,4 @@ +# Usermod user FX + +This Usermod is a common place to put various user's LED effects. + diff --git a/usermods/user_fx/library.json b/usermods/user_fx/library.json new file mode 100644 index 0000000000..9420eecdff --- /dev/null +++ b/usermods/user_fx/library.json @@ -0,0 +1,3 @@ +{ + "name": "user_fx" +} diff --git a/usermods/user_fx/user_fx.cpp b/usermods/user_fx/user_fx.cpp new file mode 100644 index 0000000000..7d8fc30808 --- /dev/null +++ b/usermods/user_fx/user_fx.cpp @@ -0,0 +1,116 @@ +#include "wled.h" + +// for information how FX metadata strings work see https://kno.wled.ge/interfaces/json-api/#effect-metadata + +// static effect, used if an effect fails to initialize +static uint16_t mode_static(void) { + SEGMENT.fill(SEGCOLOR(0)); + return strip.isOffRefreshRequired() ? FRAMETIME : 350; +} + +///////////////////////// +// User FX functions // +///////////////////////// + +// Diffusion Fire: fire effect intended for 2D setups smaller than 16x16 +static uint16_t mode_diffusionfire(void) { + if (!strip.isMatrix || !SEGMENT.is2D()) + return mode_static(); // not a 2D set-up + + const int cols = SEG_W; + const int rows = SEG_H; + const auto XY = [&](int x, int y) { return x + y * cols; }; + + const uint8_t refresh_hz = map(SEGMENT.speed, 0, 255, 20, 80); + const unsigned refresh_ms = 1000 / refresh_hz; + const int16_t diffusion = map(SEGMENT.custom1, 0, 255, 0, 100); + const uint8_t spark_rate = SEGMENT.intensity; + const uint8_t turbulence = SEGMENT.custom2; + + unsigned dataSize = SEGMENT.length(); // allocate persistent data for heat value for each pixel + if (!SEGENV.allocateData(dataSize)) + return mode_static(); // allocation failed + + if (SEGENV.call == 0) { + SEGMENT.fill(BLACK); + SEGENV.step = 0; + } + + if ((strip.now - SEGENV.step) >= refresh_ms) { + uint8_t tmp_row[cols]; + SEGENV.step = strip.now; + // scroll up + for (unsigned y = 1; y < rows; y++) + for (unsigned x = 0; x < cols; x++) { + unsigned src = XY(x, y); + unsigned dst = XY(x, y - 1); + SEGMENT.data[dst] = SEGMENT.data[src]; + } + + if (hw_random8() > turbulence) { + // create new sparks at bottom row + for (unsigned x = 0; x < cols; x++) { + uint8_t p = hw_random8(); + if (p < spark_rate) { + unsigned dst = XY(x, rows - 1); + SEGMENT.data[dst] = 255; + } + } + } + + // diffuse + for (unsigned y = 0; y < rows; y++) { + for (unsigned x = 0; x < cols; x++) { + unsigned v = SEGMENT.data[XY(x, y)]; + if (x > 0) { + v += SEGMENT.data[XY(x - 1, y)]; + } + if (x < (cols - 1)) { + v += SEGMENT.data[XY(x + 1, y)]; + } + tmp_row[x] = min(255, (int)(v * 100 / (300 + diffusion))); + } + + for (unsigned x = 0; x < cols; x++) { + SEGMENT.data[XY(x, y)] = tmp_row[x]; + if (SEGMENT.check1) { + uint32_t color = ColorFromPalette(SEGPALETTE, tmp_row[x], 255, LINEARBLEND_NOWRAP); + SEGMENT.setPixelColorXY(x, y, color); + } else { + uint32_t color = SEGCOLOR(0); + SEGMENT.setPixelColorXY(x, y, color_fade(color, tmp_row[x])); + } + } + } + } + return FRAMETIME; +} +static const char _data_FX_MODE_DIFFUSIONFIRE[] PROGMEM = "Diffusion Fire@!,Spark rate,Diffusion Speed,Turbulence,,Use palette;;Color;;2;pal=35"; + + +///////////////////// +// UserMod Class // +///////////////////// + +class UserFxUsermod : public Usermod { + private: + public: + void setup() override { + strip.addEffect(255, &mode_diffusionfire, _data_FX_MODE_DIFFUSIONFIRE); + + //////////////////////////////////////// + // add your effect function(s) here // + //////////////////////////////////////// + + // use id=255 for all custom user FX (the final id is assigned when adding the effect) + + // strip.addEffect(255, &mode_your_effect, _data_FX_MODE_YOUR_EFFECT); + // strip.addEffect(255, &mode_your_effect2, _data_FX_MODE_YOUR_EFFECT2); + // strip.addEffect(255, &mode_your_effect3, _data_FX_MODE_YOUR_EFFECT3); + } + void loop() override {} // nothing to do in the loop + uint16_t getId() override { return USERMOD_ID_USER_FX; } +}; + +static UserFxUsermod user_fx; +REGISTER_USERMOD(user_fx); diff --git a/wled00/const.h b/wled00/const.h index 2b460f3f18..2305eb6a79 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -210,6 +210,7 @@ #define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h" #define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h" #define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" +#define USERMOD_ID_USER_FX 58 //Usermod "user_fx" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot