Skip to content

Added new effect usermod - Diffusion Fire #4667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions usermods/user_fx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Usermod user FX

This Usermod is a common place to put various user's LED effects.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some additional info as seen in other usermods. Also don't forget your contact information so users may ask for help.

3 changes: 3 additions & 0 deletions usermods/user_fx/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "user_fx"
}
116 changes: 116 additions & 0 deletions usermods/user_fx/user_fx.cpp
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SEG_W and SEG_H are macros that obscure their meaning. It would be nice to have explanation of their meaning (in comment), i.e. "segment width in pixels" or something similar.

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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also add comment like "when call is 0 (first execution of effect function) clear segment".

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have preferred SEGMENT.color_from_palette() which does what SEGMENT.check1 is used for here.

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);
1 change: 1 addition & 0 deletions wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down