Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
dec3fe5
removed fastled dependencies
DedeHai Mar 17, 2025
8ae04c1
added perlin functions from PR, code cleanup. work in progress
DedeHai Mar 18, 2025
e2ce7ad
added hsv2rgb16rainbow function, some cleanup
DedeHai Mar 19, 2025
2618f56
WIP: checking different hsv2RGB_rainbow functions
DedeHai Mar 23, 2025
040cf2f
updated conversion functions (now faster), cleanup, optimizations
DedeHai Mar 25, 2025
8f18ec0
more cleanup
DedeHai Mar 26, 2025
f3aacb8
Merge remote-tracking branch 'upstream/main' into full_fastled_replac…
DedeHai Mar 26, 2025
81708d2
final cleanup
DedeHai Mar 26, 2025
2c69c5e
fixed compiler warnings, removed unused stuff
DedeHai Mar 26, 2025
6894f35
bugfixes
DedeHai Mar 27, 2025
e353448
Merge branch 'main' into full_fastled_replacement
DedeHai Mar 27, 2025
b49fdab
remove unneeded commented function declares
DedeHai Apr 6, 2025
47773b4
code cleanup, moved (most) fastled functions into fastled_fcn.cpp
DedeHai Apr 13, 2025
cb9ba98
Rename PRNG.h to prng.h
DedeHai Apr 15, 2025
62943ec
Merge branch 'main' into full_fastled_replacement
DedeHai Apr 15, 2025
f1cb1ee
remove duplicate line
DedeHai Apr 15, 2025
398fb21
fix coderabbit messup.
DedeHai Apr 16, 2025
a2e343e
fixed prng: it now generates a full sequence of random numbers
DedeHai Apr 18, 2025
b3e389b
Merge branch 'main' into full_fastled_replacement
DedeHai Mar 9, 2026
fcabef7
merge fixes, also fixed out of bounds access in rotary UM
DedeHai Mar 9, 2026
f89e39d
more fixes
DedeHai Mar 9, 2026
7765a46
revert changes to palettes.cpp, fix missing palettes
DedeHai Mar 10, 2026
c7e302f
animartrix library update
softhack007 Mar 10, 2026
0ec06f4
Merge branch 'main' into pr/4615
softhack007 Mar 12, 2026
ffaefe5
fix call to ColorFromPaletteWLED in user_fx.cpp
softhack007 Mar 12, 2026
345d7c3
rename to fastled_slim, add hsv2rgb() convenience aliases, fix FX usage
DedeHai Mar 21, 2026
0e16d96
improve ease8inOutCubic() accuracy
DedeHai Mar 21, 2026
82e29be
fix path, fix flash acces (pgm) for ESP8266
DedeHai Mar 21, 2026
8aeeea7
fix rabbit suggestions, fix indentation
DedeHai Mar 21, 2026
d83cb7a
Merge branch 'main' into full_fastled_replacement
DedeHai Mar 21, 2026
8560609
minor fix in colortwinkle
DedeHai Mar 21, 2026
65e3db9
fix background in twinklefox, minor optimization in PS (always use ga…
DedeHai Mar 21, 2026
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
2 changes: 0 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ upload_speed = 115200
# ------------------------------------------------------------------------------
lib_compat_mode = strict
lib_deps =
fastled/FastLED @ 3.6.0
IRremoteESP8266 @ 2.8.2
https://github.com/Makuna/NeoPixelBus.git#a0919d1c10696614625978dd6fb750a1317a14ce
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2
Expand Down Expand Up @@ -249,7 +248,6 @@ lib_deps_compat =
ESPAsyncTCP @ 1.2.2
ESPAsyncUDP
ESP8266PWM
fastled/FastLED @ 3.6.0
IRremoteESP8266 @ 2.8.2
makuna/NeoPixelBus @ 2.7.9
https://github.com/blazoncek/QuickESPNow.git#optional-debug
Expand Down
2 changes: 1 addition & 1 deletion usermods/Analog_Clock/Analog_Clock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class AnalogClockUsermod : public Usermod {
);
}

static inline uint32_t scale32(uint32_t c, fract8 scale) {
static inline uint32_t scale32(uint32_t c, uint8_t scale) {
return RGBW32(
scale8(R(c), scale),
scale8(G(c), scale),
Expand Down
4 changes: 2 additions & 2 deletions usermods/audioreactive/audio_reactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2008,12 +2008,12 @@ CRGB AudioReactive::getCRGBForBand(int x, int pal) {
case 2:
b = map(x, 0, 255, 0, NUM_GEQ_CHANNELS/2); // convert palette position to lower half of freq band
hsv = CHSV(fftResult[b], 255, x);
Copy link
Member

Choose a reason for hiding this comment

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

should become CHSV32

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

that sure can be arranged. :)

hsv2rgb_rainbow(hsv, value); // convert to R,G,B
value = hsv; // convert to R,G,B
break;
case 1:
b = map(x, 1, 255, 0, 10); // convert palette position to lower half of freq band
hsv = CHSV(fftResult[b], 255, map(fftResult[b], 0, 255, 30, 255)); // pick hue
hsv2rgb_rainbow(hsv, value); // convert to R,G,B
value = hsv; // convert to R,G,B
break;
default:
if (x == 1) {
Expand Down
5 changes: 3 additions & 2 deletions usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class RgbRotaryEncoderUsermod : public Usermod
byte currentColors[3];
byte lastKnownBri = 0;

inline uint32_t colorFromRgb(byte* rgb) { return uint32_t((byte(rgb[0]) << 16) | (byte(rgb[1]) << 8) | (byte(rgb[2]))); }

void initRotaryEncoder()
{
Expand Down Expand Up @@ -79,7 +80,7 @@ class RgbRotaryEncoderUsermod : public Usermod
for (int i = 0; i < currentPos / incrementPerClick - 1; i++) {
ledBus->setPixelColor(i, 0);
}
ledBus->setPixelColor(currentPos / incrementPerClick - 1, colorFromRgbw(currentColors));
ledBus->setPixelColor(currentPos / incrementPerClick - 1, colorFromRgb(currentColors));
for (int i = currentPos / incrementPerClick; i < numLeds; i++) {
ledBus->setPixelColor(i, 0);
}
Expand All @@ -95,7 +96,7 @@ class RgbRotaryEncoderUsermod : public Usermod
if (ledMode == 3) {
hsv2rgb((i) / float(numLeds), 1, .25);
}
ledBus->setPixelColor(i, colorFromRgbw(currentColors));
ledBus->setPixelColor(i, colorFromRgb(currentColors));
}
for (int i = currentPos / incrementPerClick; i < numLeds; i++) {
ledBus->setPixelColor(i, 0);
Expand Down
94 changes: 46 additions & 48 deletions usermods/user_fx/user_fx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static const char _data_FX_MODE_DIFFUSIONFIRE[] PROGMEM = "Diffusion Fire@!,Spar

static void mode_spinning_wheel(void) {
if (SEGLEN < 1) FX_FALLBACK_STATIC;

unsigned strips = SEGMENT.nrOfVStrips();
if (strips == 0) FX_FALLBACK_STATIC;

Expand Down Expand Up @@ -148,15 +148,13 @@ static void mode_spinning_wheel(void) {

// Handle random seeding globally (outside the virtual strip)
if (SEGENV.call == 0) {
random16_set_seed(hw_random16());
SEGENV.aux1 = (255 << 8) / SEGLEN; // Cache the color scaling
}

// Check if settings changed (do this once, not per virtual strip)
uint32_t settingssum = SEGMENT.speed + SEGMENT.intensity + SEGMENT.custom1 + SEGMENT.custom3 + SEGMENT.check1 + SEGMENT.check3;
bool settingsChanged = (SEGENV.aux0 != settingssum);
if (settingsChanged) {
random16_add_entropy(hw_random16());
SEGENV.aux0 = settingssum;
}

Expand All @@ -166,7 +164,7 @@ static void mode_spinning_wheel(void) {
uint8_t spinnerSize = map(SEGMENT.custom1, 0, 255, 1, 10);
uint16_t spin_delay = map(SEGMENT.custom3, 0, 31, 2000, 15000);
uint32_t now = strip.now;

for (unsigned stripNr = 0; stripNr < strips; stripNr += spinnerSize) {
uint32_t* stripState = &state[stripNr * stateVarsPerStrip];
// Check if this spinner is stopped AND has waited its delay
Expand Down Expand Up @@ -211,23 +209,23 @@ static void mode_spinning_wheel(void) {
// Initialize or restart
if (needsReset && SEGMENT.check1) { // spin the spinner(s) only if the "Spin me!" checkbox is enabled
state[CUR_POS_IDX] = 0;

// Set velocity
uint16_t speed = map(SEGMENT.speed, 0, 255, 300, 800);
if (speed == 300) { // random speed (user selected 0 on speed slider)
state[VELOCITY_IDX] = random16(200, 900) * 655; // fixed-point velocity scaling (approx. 65536/100)
state[VELOCITY_IDX] = hw_random16(200, 900) * 655; // fixed-point velocity scaling (approx. 65536/100)
} else {
state[VELOCITY_IDX] = random16(speed - 100, speed + 100) * 655;
state[VELOCITY_IDX] = hw_random16(speed - 100, speed + 100) * 655;
}

// Set slowdown start time
uint16_t slowdown = map(SEGMENT.intensity, 0, 255, 3000, 5000);
if (slowdown == 3000) { // random slowdown start time (user selected 0 on intensity slider)
state[SLOWDOWN_TIME_IDX] = now + random16(2000, 6000);
state[SLOWDOWN_TIME_IDX] = now + hw_random16(2000, 6000);
} else {
state[SLOWDOWN_TIME_IDX] = now + random16(slowdown - 1000, slowdown + 1000);
state[SLOWDOWN_TIME_IDX] = now + hw_random16(slowdown - 1000, slowdown + 1000);
}

state[PHASE_IDX] = 0;
state[STOP_TIME_IDX] = 0;
state[WOBBLE_STEP_IDX] = 0;
Expand All @@ -250,10 +248,10 @@ static void mode_spinning_wheel(void) {
// Slowing phase - apply deceleration
uint32_t decel = velocity / 80;
if (decel < 100) decel = 100;

velocity = (velocity > decel) ? velocity - decel : 0;
state[VELOCITY_IDX] = velocity;

// Check if stopped
if (velocity < 2000) {
velocity = 0;
Expand All @@ -270,7 +268,7 @@ static void mode_spinning_wheel(void) {
uint32_t wobble_step = state[WOBBLE_STEP_IDX];
uint16_t stop_pos = state[STOP_POS_IDX];
uint32_t elapsed = now - state[WOBBLE_TIME_IDX];

if (wobble_step == 0 && elapsed >= 200) {
// Move back one LED from stop position
uint16_t back_pos = (stop_pos == 0) ? SEGLEN - 1 : stop_pos - 1;
Expand All @@ -291,13 +289,13 @@ static void mode_spinning_wheel(void) {
state[STOP_TIME_IDX] = now;
}
}

// Update position (phases 0 and 1 only)
if (phase == 0 || phase == 1) {
pos_fixed += velocity;
state[CUR_POS_IDX] = pos_fixed;
}

// Draw LED for all phases
uint16_t pos = (pos_fixed >> 16) % SEGLEN;

Expand All @@ -314,14 +312,14 @@ static void mode_spinning_wheel(void) {
hue = (SEGENV.aux1 * pos) >> 8;
}

uint32_t color = ColorFromPaletteWLED(SEGPALETTE, hue, 255, LINEARBLEND);
uint32_t color = ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND);

// Draw the spinner with configurable size (1-10 LEDs)
for (int8_t x = 0; x < spinnerSize; x++) {
for (uint8_t y = 0; y < spinnerSize; y++) {
uint16_t drawPos = (pos + y) % SEGLEN;
int16_t drawStrip = stripNr + x;

// Wrap horizontally if needed, or skip if out of bounds
if (drawStrip >= 0 && drawStrip < strips) {
SEGMENT.setPixelColor(indexToVStrip(drawPos, drawStrip), color);
Expand Down Expand Up @@ -370,7 +368,7 @@ typedef struct LavaParticle {

static void mode_2D_lavalamp(void) {
if (!strip.isMatrix || !SEGMENT.is2D()) FX_FALLBACK_STATIC; // not a 2D set-up

const uint16_t cols = SEG_W;
const uint16_t rows = SEG_H;
constexpr float MAX_BLOB_RADIUS = 20.0f; // cap to prevent frame rate drops on large matrices
Expand Down Expand Up @@ -405,7 +403,7 @@ static void mode_2D_lavalamp(void) {

uint8_t size = currentSize;
uint8_t numParticles = currentNumParticles;

// blob size based on matrix width
const float minSize = cols * 0.15f; // Minimum 15% of width
const float maxSize = cols * 0.4f; // Maximum 40% of width
Expand All @@ -427,7 +425,7 @@ static void mode_2D_lavalamp(void) {
lavaParticles[i].y = rows - 1;
lavaParticles[i].vx = (hw_random16(7) - 3) / 250.0f;
lavaParticles[i].vy = -(hw_random16(20) + 10) / 100.0f * 0.3f;

lavaParticles[i].size = minSize + (float)hw_random16(rangeInt);
if (lavaParticles[i].size > MAX_BLOB_RADIUS) lavaParticles[i].size = MAX_BLOB_RADIUS;

Expand All @@ -444,7 +442,7 @@ static void mode_2D_lavalamp(void) {

// Fade background slightly for trailing effect
SEGMENT.fadeToBlackBy(40);

// Update and draw particles
int activeCount = 0;
unsigned long currentMillis = strip.now;
Expand All @@ -460,21 +458,21 @@ static void mode_2D_lavalamp(void) {
}

LavaParticle *p = &lavaParticles[i];

// Physics update
p->x += p->vx;
p->y += p->vy;

// Optional particle/blob attraction
if (SEGMENT.check2) {
for (int j = 0; j < MAX_LAVA_PARTICLES; j++) {
if (i == j || !lavaParticles[j].active) continue;

LavaParticle *other = &lavaParticles[j];

// Skip attraction if moving in same vertical direction (both up or both down)
if ((p->vy < 0 && other->vy < 0) || (p->vy > 0 && other->vy > 0)) continue;

float dx = other->x - p->x;
float dy = other->y - p->y;

Expand Down Expand Up @@ -580,7 +578,7 @@ static void mode_2D_lavalamp(void) {
// Get color
uint32_t color;
color = SEGMENT.color_from_palette(p->hue, true, PALETTE_SOLID_WRAP, 0);

// Extract RGB and apply life/opacity
uint8_t w = (W(color) * 255) >> 8;
uint8_t r = (R(color) * 255) >> 8;
Expand All @@ -600,7 +598,7 @@ static void mode_2D_lavalamp(void) {
for (int dx = -(int)p->size - 1; dx <= (int)p->size + 1; dx++) {
int px = centerX + dx;
int py = centerY + dy;

if (px < 0 || px >= cols || py < 0 || py >= rows) continue;

// Sub-pixel distance: measure from true float center to pixel center
Expand Down Expand Up @@ -667,62 +665,62 @@ static void drawMagma(const uint16_t width, const uint16_t height, float *ff_y,
static void drawLavaBombs(const uint16_t width, const uint16_t height, float *particleData, float gravity, uint8_t particleCount) {
for (uint16_t i = 0; i < particleCount; i++) {
uint16_t idx = i * 4;

particleData[idx + 3] -= gravity;
particleData[idx + 0] += particleData[idx + 2];
particleData[idx + 1] += particleData[idx + 3];

float posX = particleData[idx + 0];
float posY = particleData[idx + 1];

if (posY > height + height / 4) {
particleData[idx + 3] = -particleData[idx + 3] * 0.8f;
}

if (posY < (float)(height / 8) - 1.0f || posX < 0 || posX >= width) {
particleData[idx + 0] = hw_random(0, width * 100) / 100.0f;
particleData[idx + 1] = hw_random(0, height * 25) / 100.0f;
particleData[idx + 2] = hw_random(-75, 75) / 100.0f;

float baseVelocity = hw_random(60, 120) / 100.0f;
if (hw_random8() < 50) {
baseVelocity *= 1.6f;
}
particleData[idx + 3] = baseVelocity;
continue;
}

int16_t xi = (int16_t)posX;
int16_t yi = (int16_t)posY;

if (xi >= 0 && xi < width && yi >= 0 && yi < height) {
// Get a random color from the current palette
uint8_t randomIndex = hw_random8(64, 128);
CRGB pcolor = ColorFromPaletteWLED(SEGPALETTE, randomIndex, 255, LINEARBLEND);
CRGB pcolor = ColorFromPalette(SEGPALETTE, randomIndex, 255, LINEARBLEND);

// Pre-calculate anti-aliasing weights
float xf = posX - xi;
float yf = posY - yi;
float ix = 1.0f - xf;
float iy = 1.0f - yf;

uint8_t w0 = 255 * ix * iy;
uint8_t w1 = 255 * xf * iy;
uint8_t w2 = 255 * ix * yf;
uint8_t w3 = 255 * xf * yf;

int16_t yFlipped = height - 1 - yi; // Flip Y coordinate

SEGMENT.addPixelColorXY(xi, yFlipped, pcolor.scale8(w0));
if (xi + 1 < width)
SEGMENT.addPixelColorXY(xi + 1, yFlipped, pcolor.scale8(w1));
if (yFlipped - 1 >= 0)
SEGMENT.addPixelColorXY(xi, yFlipped - 1, pcolor.scale8(w2));
if (xi + 1 < width && yFlipped - 1 >= 0)
if (xi + 1 < width && yFlipped - 1 >= 0)
SEGMENT.addPixelColorXY(xi + 1, yFlipped - 1, pcolor.scale8(w3));
}
}
}
}

static void mode_2D_magma(void) {
if (!strip.isMatrix || !SEGMENT.is2D()) FX_FALLBACK_STATIC; // not a 2D set-up
Expand All @@ -746,7 +744,7 @@ static void mode_2D_magma(void) {
uint32_t settingsKey = (uint32_t)SEGMENT.speed | ((uint32_t)SEGMENT.intensity << 8) |
((uint32_t)SEGMENT.custom1 << 16) | ((uint32_t)SEGMENT.custom2 << 24);
bool settingsChanged = (*settingsSumPtr != settingsKey);

if (SEGENV.call == 0 || settingsChanged) {
// Intensity slider controls magma height
uint16_t intensity = SEGMENT.intensity;
Expand All @@ -772,7 +770,7 @@ static void mode_2D_magma(void) {
particleData[idx + 0] = hw_random(0, width * 100) / 100.0f;
particleData[idx + 1] = hw_random(0, height * 25) / 100.0f;
particleData[idx + 2] = hw_random(-75, 75) / 100.0f;

float baseVelocity = hw_random(60, 120) / 100.0f;
if (hw_random8() < 50) {
baseVelocity *= 1.6f;
Expand All @@ -793,7 +791,7 @@ static void mode_2D_magma(void) {

// Gravity control
float gravity = map(SEGMENT.custom2, 0, 255, 5, 20) / 100.0f;

// Number of particles (lava bombs)
uint8_t particleCount = map(SEGMENT.custom1, 0, 255, 0, MAGMA_MAX_PARTICLES);
particleCount = constrain(particleCount, 0, MAGMA_MAX_PARTICLES);
Expand Down Expand Up @@ -1035,7 +1033,7 @@ static const char _data_FX_MODE_ANTS[] PROGMEM = "Ants@Ant speed,# of ants,Ant s
// Build morse code pattern into a buffer
static void build_morsecode_pattern(const char *morse_code, uint8_t *pattern, uint8_t *wordIndex, uint16_t &index, uint8_t currentWord, int maxSize) {
const char *c = morse_code;

// Build the dots and dashes into pattern array
while (*c != '\0') {
// it's a dot which is 1 pixel
Expand Down Expand Up @@ -1082,7 +1080,7 @@ static void build_morsecode_pattern(const char *morse_code, uint8_t *pattern, ui

static void mode_morsecode(void) {
if (SEGLEN < 1) FX_FALLBACK_STATIC;

// A-Z in Morse Code
static const char * letters[] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
"-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."};
Expand Down Expand Up @@ -1286,7 +1284,7 @@ class UserFxUsermod : public Usermod {
// strip.addEffect(255, &mode_your_effect3, _data_FX_MODE_YOUR_EFFECT3);
}


///////////////////////////////////////////////////////////////////////////////////////////////
// If you want configuration options in the usermod settings page, implement these methods //
///////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading
Loading