mirror of
https://github.com/wled/WLED.git
synced 2025-07-19 16:56:35 +00:00
Merge branch 'main' into parallel-I2S
This commit is contained in:
commit
24082d169b
@ -173,7 +173,7 @@
|
|||||||
- v0.15.0-b2
|
- v0.15.0-b2
|
||||||
- WS2805 support (RGB + WW + CW, 600kbps)
|
- WS2805 support (RGB + WW + CW, 600kbps)
|
||||||
- Unified PSRAM use
|
- Unified PSRAM use
|
||||||
- NeoPixelBus v2.7.9
|
- NeoPixelBus v2.7.9 (for future WS2805 support)
|
||||||
- Ubiquitous PSRAM mode for all variants of ESP32
|
- Ubiquitous PSRAM mode for all variants of ESP32
|
||||||
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
|
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
|
||||||
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
|
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
|
||||||
|
@ -9,7 +9,7 @@ Very loosely based on the existing usermod "seven segment display".
|
|||||||
|
|
||||||
Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`.
|
Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`.
|
||||||
|
|
||||||
For the auto brightness option, the usermod SN_Photoresistor has to be installed as well. See SN_Photoresistor/readme.md for instructions.
|
For the auto brightness option, the usermod SN_Photoresistor or BH1750_V2 has to be installed as well. See SN_Photoresistor/readme.md or BH1750_V2/readme.md for instructions.
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
All settings can be controlled via the usermod settings page.
|
All settings can be controlled via the usermod settings page.
|
||||||
@ -28,10 +28,10 @@ Enables the blinking colon(s) if they are defined
|
|||||||
Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`)
|
Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`)
|
||||||
|
|
||||||
### enable-auto-brightness
|
### enable-auto-brightness
|
||||||
Enables the auto brightness feature. Can be used only when the usermod SN_Photoresistor is installed.
|
Enables the auto brightness feature. Can be used only when the usermods SN_Photoresistor or BH1750_V2 are installed.
|
||||||
|
|
||||||
### auto-brightness-min / auto-brightness-max
|
### auto-brightness-min / auto-brightness-max
|
||||||
The lux value calculated from usermod SN_Photoresistor will be mapped to the values defined here.
|
The lux value calculated from usermod SN_Photoresistor or BH1750_V2 will be mapped to the values defined here.
|
||||||
The mapping, 0 - 1000 lux, will be mapped to auto-brightness-min and auto-brightness-max
|
The mapping, 0 - 1000 lux, will be mapped to auto-brightness-min and auto-brightness-max
|
||||||
|
|
||||||
WLED current protection will override the calculated value if it is too high.
|
WLED current protection will override the calculated value if it is too high.
|
||||||
|
@ -97,6 +97,11 @@ private:
|
|||||||
#else
|
#else
|
||||||
void* ptr = nullptr;
|
void* ptr = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USERMOD_BH1750
|
||||||
|
Usermod_BH1750* bh1750 = nullptr;
|
||||||
|
#else
|
||||||
|
void* bh1750 = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
void _overlaySevenSegmentDraw() {
|
void _overlaySevenSegmentDraw() {
|
||||||
int displayMaskLen = static_cast<int>(umSSDRDisplayMask.length());
|
int displayMaskLen = static_cast<int>(umSSDRDisplayMask.length());
|
||||||
@ -387,6 +392,9 @@ public:
|
|||||||
#ifdef USERMOD_SN_PHOTORESISTOR
|
#ifdef USERMOD_SN_PHOTORESISTOR
|
||||||
ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR);
|
ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USERMOD_BH1750
|
||||||
|
bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750);
|
||||||
|
#endif
|
||||||
DEBUG_PRINTLN(F("Setup done"));
|
DEBUG_PRINTLN(F("Setup done"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,6 +418,20 @@ public:
|
|||||||
umSSDRLastRefresh = millis();
|
umSSDRLastRefresh = millis();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USERMOD_BH1750
|
||||||
|
if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime)) {
|
||||||
|
if (bh1750 != nullptr) {
|
||||||
|
float lux = bh1750->getIlluminance();
|
||||||
|
uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax);
|
||||||
|
if (bri != brightness) {
|
||||||
|
DEBUG_PRINTF("Adjusting brightness based on lux value: %.2f lx, new brightness: %d\n", lux, brightness);
|
||||||
|
bri = brightness;
|
||||||
|
stateUpdated(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
umSSDRLastRefresh = millis();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleOverlayDraw() {
|
void handleOverlayDraw() {
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file allows you to add own functionality to WLED more easily
|
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
|
||||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in wled_eeprom.h)
|
|
||||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
|
||||||
|
|
||||||
byte wipeState = 0; //0: inactive 1: wiping 2: solid
|
|
||||||
unsigned long timeStaticStart = 0;
|
|
||||||
uint16_t previousUserVar0 = 0;
|
|
||||||
|
|
||||||
//comment this out if you want the turn off effect to be just fading out instead of reverse wipe
|
|
||||||
#define STAIRCASE_WIPE_OFF
|
|
||||||
|
|
||||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
|
||||||
void userSetup()
|
|
||||||
{
|
|
||||||
//setup PIR sensor here, if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
|
||||||
void userConnected()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
|
||||||
void userLoop()
|
|
||||||
{
|
|
||||||
//userVar0 (U0 in HTTP API):
|
|
||||||
//has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266
|
|
||||||
//has to be set to 2 if movement is detected on the PIR that is the opposite side
|
|
||||||
//can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds)
|
|
||||||
|
|
||||||
if (userVar0 > 0)
|
|
||||||
{
|
|
||||||
if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered
|
|
||||||
previousUserVar0 = userVar0;
|
|
||||||
|
|
||||||
if (wipeState == 0) {
|
|
||||||
startWipe();
|
|
||||||
wipeState = 1;
|
|
||||||
} else if (wipeState == 1) { //wiping
|
|
||||||
uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time)
|
|
||||||
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
|
|
||||||
effectCurrent = FX_MODE_STATIC;
|
|
||||||
timeStaticStart = millis();
|
|
||||||
colorUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
wipeState = 2;
|
|
||||||
}
|
|
||||||
} else if (wipeState == 2) { //static
|
|
||||||
if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered
|
|
||||||
{
|
|
||||||
if (millis() - timeStaticStart > userVar1*1000) wipeState = 3;
|
|
||||||
}
|
|
||||||
} else if (wipeState == 3) { //switch to wipe off
|
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
|
||||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
|
||||||
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
|
|
||||||
colorUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
wipeState = 4;
|
|
||||||
#else
|
|
||||||
turnOff();
|
|
||||||
#endif
|
|
||||||
} else { //wiping off
|
|
||||||
if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wipeState = 0; //reset for next time
|
|
||||||
if (previousUserVar0) {
|
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
|
||||||
userVar0 = previousUserVar0;
|
|
||||||
wipeState = 3;
|
|
||||||
#else
|
|
||||||
turnOff();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
previousUserVar0 = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void startWipe()
|
|
||||||
{
|
|
||||||
bri = briLast; //turn on
|
|
||||||
transitionDelayTemp = 0; //no transition
|
|
||||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
|
||||||
strip.resetTimebase(); //make sure wipe starts from beginning
|
|
||||||
|
|
||||||
//set wipe direction
|
|
||||||
Segment& seg = strip.getSegment(0);
|
|
||||||
bool doReverse = (userVar0 == 2);
|
|
||||||
seg.setOption(1, doReverse);
|
|
||||||
|
|
||||||
colorUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void turnOff()
|
|
||||||
{
|
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
|
||||||
transitionDelayTemp = 0; //turn off immediately after wipe completed
|
|
||||||
#else
|
|
||||||
transitionDelayTemp = 4000; //fade out slowly
|
|
||||||
#endif
|
|
||||||
bri = 0;
|
|
||||||
stateUpdated(CALL_MODE_NOTIFICATION);
|
|
||||||
wipeState = 0;
|
|
||||||
userVar0 = 0;
|
|
||||||
previousUserVar0 = 0;
|
|
||||||
}
|
|
@ -5446,15 +5446,15 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have
|
|||||||
// and add them together with weightening
|
// and add them together with weightening
|
||||||
unsigned dx = abs(x - x1);
|
unsigned dx = abs(x - x1);
|
||||||
unsigned dy = abs(y - y1);
|
unsigned dy = abs(y - y1);
|
||||||
unsigned dist = 2 * sqrt16((dx * dx) + (dy * dy));
|
unsigned dist = 2 * sqrt32_bw((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
dx = abs(x - x2);
|
dx = abs(x - x2);
|
||||||
dy = abs(y - y2);
|
dy = abs(y - y2);
|
||||||
dist += sqrt16((dx * dx) + (dy * dy));
|
dist += sqrt32_bw((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
dx = abs(x - x3);
|
dx = abs(x - x3);
|
||||||
dy = abs(y - y3);
|
dy = abs(y - y3);
|
||||||
dist += sqrt16((dx * dx) + (dy * dy));
|
dist += sqrt32_bw((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
// inverse result
|
// inverse result
|
||||||
int color = dist ? 1000 / dist : 255;
|
int color = dist ? 1000 / dist : 255;
|
||||||
@ -6094,13 +6094,23 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
if (!strlen(text)) { // fallback if empty segment name: display date and time
|
if (!strlen(text)) { // fallback if empty segment name: display date and time
|
||||||
sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||||
} else {
|
} else {
|
||||||
|
if (text[0] == '#') for (auto &c : text) c = std::toupper(c);
|
||||||
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime));
|
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
|
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
||||||
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
|
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), AmPmHour);
|
else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf (text, zero? ("%02d") : ("%d"), AmPmHour);
|
||||||
else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), minute(localTime));
|
else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf (text, zero? ("%02d") : ("%d"), minute(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#SS"),3)) sprintf (text, ("%02d") , second(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DD"),3)) sprintf (text, zero? ("%02d") : ("%d"), day(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DAY"),4)) sprintf (text, ("%s") , dayShortStr(day(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DDDD"),5)) sprintf (text, ("%s") , dayStr(day(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MO"),3)) sprintf (text, zero? ("%02d") : ("%d"), month(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MON"),4)) sprintf (text, ("%s") , monthShortStr(month(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MMMM"),5)) sprintf (text, ("%s") , monthStr(month(localTime)));
|
||||||
|
else if (!strncmp_P(text,PSTR("#YY"),3)) sprintf (text, ("%02d") , year(localTime)%100);
|
||||||
|
else if (!strncmp_P(text,PSTR("#YYYY"),5)) sprintf_P(text, zero?PSTR("%04d") : ("%d"), year(localTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
const int numberOfLetters = strlen(text);
|
const int numberOfLetters = strlen(text);
|
||||||
|
38
wled00/FX.h
38
wled00/FX.h
@ -326,6 +326,30 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
|
|||||||
|
|
||||||
#define MODE_COUNT 187
|
#define MODE_COUNT 187
|
||||||
|
|
||||||
|
|
||||||
|
#define BLEND_STYLE_FADE 0x00 // universal
|
||||||
|
#define BLEND_STYLE_FAIRY_DUST 0x01 // universal
|
||||||
|
#define BLEND_STYLE_SWIPE_RIGHT 0x02 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_SWIPE_LEFT 0x03 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_PINCH_OUT 0x04 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_INSIDE_OUT 0x05 // 1D or 2D
|
||||||
|
#define BLEND_STYLE_SWIPE_UP 0x06 // 2D
|
||||||
|
#define BLEND_STYLE_SWIPE_DOWN 0x07 // 2D
|
||||||
|
#define BLEND_STYLE_OPEN_H 0x08 // 2D
|
||||||
|
#define BLEND_STYLE_OPEN_V 0x09 // 2D
|
||||||
|
// as there are many push variants to optimise if statements they are groupped together
|
||||||
|
#define BLEND_STYLE_PUSH_RIGHT 0x10 // 1D or 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_LEFT 0x11 // 1D or 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_UP 0x12 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_DOWN 0x13 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_TL 0x14 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_TR 0x15 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_BR 0x16 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_BL 0x17 // 2D (& 0b00010000)
|
||||||
|
#define BLEND_STYLE_PUSH_MASK 0x10
|
||||||
|
#define BLEND_STYLE_COUNT 18
|
||||||
|
|
||||||
|
|
||||||
typedef enum mapping1D2D {
|
typedef enum mapping1D2D {
|
||||||
M12_Pixels = 0,
|
M12_Pixels = 0,
|
||||||
M12_pBar = 1,
|
M12_pBar = 1,
|
||||||
@ -334,7 +358,7 @@ typedef enum mapping1D2D {
|
|||||||
M12_sPinwheel = 4
|
M12_sPinwheel = 4
|
||||||
} mapping1D2D_t;
|
} mapping1D2D_t;
|
||||||
|
|
||||||
// segment, 80 bytes
|
// segment, 68 bytes
|
||||||
typedef struct Segment {
|
typedef struct Segment {
|
||||||
public:
|
public:
|
||||||
uint16_t start; // start index / start X coordinate 2D (left)
|
uint16_t start; // start index / start X coordinate 2D (left)
|
||||||
@ -437,6 +461,9 @@ typedef struct Segment {
|
|||||||
static uint16_t _transitionprogress; // current transition progress 0 - 0xFFFF
|
static uint16_t _transitionprogress; // current transition progress 0 - 0xFFFF
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
static bool _modeBlend; // mode/effect blending semaphore
|
static bool _modeBlend; // mode/effect blending semaphore
|
||||||
|
// clipping
|
||||||
|
static uint16_t _clipStart, _clipStop;
|
||||||
|
static uint8_t _clipStartY, _clipStopY;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
|
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
|
||||||
@ -447,6 +474,7 @@ typedef struct Segment {
|
|||||||
#else
|
#else
|
||||||
uint32_t _colorT[NUM_COLORS];
|
uint32_t _colorT[NUM_COLORS];
|
||||||
#endif
|
#endif
|
||||||
|
uint8_t _palTid; // previous palette
|
||||||
uint8_t _briT; // temporary brightness
|
uint8_t _briT; // temporary brightness
|
||||||
uint8_t _cctT; // temporary CCT
|
uint8_t _cctT; // temporary CCT
|
||||||
CRGBPalette16 _palT; // temporary palette
|
CRGBPalette16 _palT; // temporary palette
|
||||||
@ -611,6 +639,10 @@ typedef struct Segment {
|
|||||||
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) const { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) const { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
||||||
inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
static inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; };
|
||||||
|
#endif
|
||||||
|
bool isPixelClipped(int i) const;
|
||||||
[[gnu::hot]] uint32_t getPixelColor(int i) const;
|
[[gnu::hot]] uint32_t getPixelColor(int i) const;
|
||||||
// 1D support functions (some implement 2D as well)
|
// 1D support functions (some implement 2D as well)
|
||||||
void blur(uint8_t, bool smear = false);
|
void blur(uint8_t, bool smear = false);
|
||||||
@ -657,6 +689,7 @@ typedef struct Segment {
|
|||||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
|
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
|
||||||
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
|
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||||
#endif
|
#endif
|
||||||
|
[[gnu::hot]] bool isPixelXYClipped(int x, int y) const;
|
||||||
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
|
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
|
||||||
// 2D support functions
|
// 2D support functions
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
||||||
@ -694,6 +727,7 @@ typedef struct Segment {
|
|||||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
|
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
|
||||||
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
|
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||||
#endif
|
#endif
|
||||||
|
inline bool isPixelXYClipped(int x, int y) { return isPixelClipped(x); }
|
||||||
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
||||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||||
@ -738,7 +772,6 @@ class WS2812FX { // 96 bytes
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
WS2812FX() :
|
WS2812FX() :
|
||||||
paletteFade(0),
|
|
||||||
paletteBlend(0),
|
paletteBlend(0),
|
||||||
now(millis()),
|
now(millis()),
|
||||||
timebase(0),
|
timebase(0),
|
||||||
@ -827,7 +860,6 @@ class WS2812FX { // 96 bytes
|
|||||||
inline void resume() { _suspend = false; } // will resume strip.service() execution
|
inline void resume() { _suspend = false; } // will resume strip.service() execution
|
||||||
|
|
||||||
bool
|
bool
|
||||||
paletteFade,
|
|
||||||
checkSegmentAlignment() const,
|
checkSegmentAlignment() const,
|
||||||
hasRGBWBus() const,
|
hasRGBWBus() const,
|
||||||
hasCCTBus() const,
|
hasCCTBus() const,
|
||||||
|
@ -160,7 +160,7 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint
|
|||||||
const int baseY = startY + y;
|
const int baseY = startY + y;
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
// if blending modes, blend with underlying pixel
|
// if blending modes, blend with underlying pixel
|
||||||
if (_modeBlend) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
|
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColorXY(baseX, baseY, col);
|
strip.setPixelColorXY(baseX, baseY, col);
|
||||||
|
|
||||||
@ -179,14 +179,57 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false)
|
||||||
|
// if clipping start > stop the clipping range is inverted
|
||||||
|
// _modeBlend==true -> old effect during transition
|
||||||
|
// _modeBlend==false -> new effect during transition
|
||||||
|
bool IRAM_ATTR_YN Segment::isPixelXYClipped(int x, int y) const {
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
if (_clipStart != _clipStop && blendingStyle != BLEND_STYLE_FADE) {
|
||||||
|
const bool invertX = _clipStart > _clipStop;
|
||||||
|
const bool invertY = _clipStartY > _clipStopY;
|
||||||
|
const int startX = invertX ? _clipStop : _clipStart;
|
||||||
|
const int stopX = invertX ? _clipStart : _clipStop;
|
||||||
|
const int startY = invertY ? _clipStopY : _clipStartY;
|
||||||
|
const int stopY = invertY ? _clipStartY : _clipStopY;
|
||||||
|
if (blendingStyle == BLEND_STYLE_FAIRY_DUST) {
|
||||||
|
const unsigned width = stopX - startX; // assumes full segment width (faster than virtualWidth())
|
||||||
|
const unsigned len = width * (stopY - startY); // assumes full segment height (faster than virtualHeight())
|
||||||
|
if (len < 2) return false;
|
||||||
|
const unsigned shuffled = hashInt(x + y * width) % len;
|
||||||
|
const unsigned pos = (shuffled * 0xFFFFU) / len;
|
||||||
|
return progress() > pos;
|
||||||
|
}
|
||||||
|
bool xInside = (x >= startX && x < stopX); if (invertX) xInside = !xInside;
|
||||||
|
bool yInside = (y >= startY && y < stopY); if (invertY) yInside = !yInside;
|
||||||
|
const bool clip = (invertX && invertY) ? !_modeBlend : _modeBlend;
|
||||||
|
if (xInside && yInside) return clip; // covers window & corners (inverted)
|
||||||
|
return !clip;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const
|
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const
|
||||||
{
|
{
|
||||||
if (!isActive()) return; // not active
|
if (!isActive()) return; // not active
|
||||||
|
|
||||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||||
// negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH
|
|
||||||
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
if (!prog && !_modeBlend && (blendingStyle & BLEND_STYLE_PUSH_MASK)) {
|
||||||
|
unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF;
|
||||||
|
unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x += dX;
|
||||||
|
else x -= dX;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY;
|
||||||
|
else y += dY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (x >= vW || y >= vH || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit
|
||||||
|
|
||||||
// if color is unscaled
|
// if color is unscaled
|
||||||
if (!_colorScaled) col = color_fade(col, _segBri);
|
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||||
@ -259,9 +302,24 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) const
|
|||||||
// returns RGBW values of pixel
|
// returns RGBW values of pixel
|
||||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||||
if (!isActive()) return 0; // not active
|
if (!isActive()) return 0; // not active
|
||||||
|
|
||||||
const int vW = vWidth();
|
const int vW = vWidth();
|
||||||
const int vH = vHeight();
|
const int vH = vHeight();
|
||||||
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit
|
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
if (!prog && !_modeBlend && (blendingStyle & BLEND_STYLE_PUSH_MASK)) {
|
||||||
|
unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF;
|
||||||
|
unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x -= dX;
|
||||||
|
else x += dX;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY;
|
||||||
|
else y += dY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (x >= vW || y >= vH || x<0 || y<0 || isPixelXYClipped(x,y)) return 0; // if pixel would fall out of virtual segment just exit
|
||||||
|
|
||||||
if (reverse ) x = vW - x - 1;
|
if (reverse ) x = vW - x - 1;
|
||||||
if (reverse_y) y = vH - y - 1;
|
if (reverse_y) y = vH - y - 1;
|
||||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||||
|
@ -84,6 +84,10 @@ uint16_t Segment::_transitionprogress = 0xFFFF;
|
|||||||
|
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
bool Segment::_modeBlend = false;
|
bool Segment::_modeBlend = false;
|
||||||
|
uint16_t Segment::_clipStart = 0;
|
||||||
|
uint16_t Segment::_clipStop = 0;
|
||||||
|
uint8_t Segment::_clipStartY = 0;
|
||||||
|
uint8_t Segment::_clipStopY = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// copy constructor
|
// copy constructor
|
||||||
@ -258,24 +262,21 @@ void Segment::startTransition(uint16_t dur) {
|
|||||||
|
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t);
|
//DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t);
|
||||||
loadPalette(_t->_palT, palette);
|
loadPalette(_t->_palT, palette);
|
||||||
|
_t->_palTid = palette;
|
||||||
_t->_briT = on ? opacity : 0;
|
_t->_briT = on ? opacity : 0;
|
||||||
_t->_cctT = cct;
|
_t->_cctT = cct;
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending) {
|
swapSegenv(_t->_segT);
|
||||||
swapSegenv(_t->_segT);
|
_t->_modeT = mode;
|
||||||
_t->_modeT = mode;
|
_t->_segT._dataLenT = 0;
|
||||||
_t->_segT._dataLenT = 0;
|
_t->_segT._dataT = nullptr;
|
||||||
_t->_segT._dataT = nullptr;
|
if (_dataLen > 0 && data) {
|
||||||
if (_dataLen > 0 && data) {
|
_t->_segT._dataT = (byte *)malloc(_dataLen);
|
||||||
_t->_segT._dataT = (byte *)malloc(_dataLen);
|
if (_t->_segT._dataT) {
|
||||||
if (_t->_segT._dataT) {
|
//DEBUG_PRINTF_P(PSTR("-- Allocated duplicate data (%d) for %p: %p\n"), _dataLen, this, _t->_segT._dataT);
|
||||||
//DEBUG_PRINTF_P(PSTR("-- Allocated duplicate data (%d) for %p: %p\n"), _dataLen, this, _t->_segT._dataT);
|
memcpy(_t->_segT._dataT, data, _dataLen);
|
||||||
memcpy(_t->_segT._dataT, data, _dataLen);
|
_t->_segT._dataLenT = _dataLen;
|
||||||
_t->_segT._dataLenT = _dataLen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_segT._colorT[i] = colors[i];
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
||||||
@ -381,28 +382,52 @@ void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) {
|
|||||||
|
|
||||||
uint8_t Segment::currentBri(bool useCct) const {
|
uint8_t Segment::currentBri(bool useCct) const {
|
||||||
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
||||||
if (prog < 0xFFFFU) { // progress() < 0xFFFF implies that _t is a valid pointer
|
uint32_t curBri = useCct ? cct : (on ? opacity : 0);
|
||||||
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
|
if (prog < 0xFFFFU) {
|
||||||
curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog);
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
uint8_t tmpBri = useCct ? _t->_cctT : (_t->_segT._optionsT & 0x0004 ? _t->_briT : 0);
|
||||||
|
// _modeBlend==true -> old effect
|
||||||
|
if (blendingStyle != BLEND_STYLE_FADE) return _modeBlend ? tmpBri : curBri; // not fade/blend transition, each effect uses its brightness
|
||||||
|
#else
|
||||||
|
uint8_t tmpBri = useCct ? _t->_cctT : _t->_briT;
|
||||||
|
#endif
|
||||||
|
curBri *= prog;
|
||||||
|
curBri += tmpBri * (0xFFFFU - prog);
|
||||||
return curBri / 0xFFFFU;
|
return curBri / 0xFFFFU;
|
||||||
}
|
}
|
||||||
return (useCct ? cct : (on ? opacity : 0));
|
return curBri;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Segment::currentMode() const {
|
uint8_t Segment::currentMode() const {
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
unsigned prog = isInTransition() ? progress() : 0xFFFFU;
|
||||||
if (modeBlending && prog < 0xFFFFU) return _t->_modeT; // progress() < 0xFFFF implies that _t is a valid pointer
|
if (prog == 0xFFFFU) return mode;
|
||||||
#endif
|
if (blendingStyle != BLEND_STYLE_FADE) {
|
||||||
|
// workaround for on/off transition to respect blending style
|
||||||
|
uint8_t modeT = (bri != briT) && bri ? FX_MODE_STATIC : _t->_modeT; // On/Off transition active (bri!=briT) and final bri>0 : old mode is STATIC
|
||||||
|
uint8_t modeS = (bri != briT) && !bri ? FX_MODE_STATIC : mode; // On/Off transition active (bri!=briT) and final bri==0 : new mode is STATIC
|
||||||
|
return _modeBlend ? modeT : modeS; // _modeBlend==true -> old effect
|
||||||
|
}
|
||||||
|
return _modeBlend ? _t->_modeT : mode; // _modeBlend==true -> old effect
|
||||||
|
#else
|
||||||
return mode;
|
return mode;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Segment::currentColor(uint8_t slot) const {
|
uint32_t Segment::currentColor(uint8_t slot) const {
|
||||||
if (slot >= NUM_COLORS) slot = 0;
|
if (slot >= NUM_COLORS) slot = 0;
|
||||||
|
unsigned prog = progress();
|
||||||
|
if (prog == 0xFFFFU) return colors[slot];
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
return isInTransition() ? color_blend16(_t->_segT._colorT[slot], colors[slot], progress()) : colors[slot];
|
if (blendingStyle != BLEND_STYLE_FADE) {
|
||||||
|
// workaround for on/off transition to respect blending style
|
||||||
|
uint32_t colT = (bri != briT) && bri ? BLACK : _t->_segT._colorT[slot]; // On/Off transition active (bri!=briT) and final bri>0 : old color is BLACK
|
||||||
|
uint32_t colS = (bri != briT) && !bri ? BLACK : colors[slot]; // On/Off transition active (bri!=briT) and final bri==0 : new color is BLACK
|
||||||
|
return _modeBlend ? colT : colS; // _modeBlend==true -> old effect
|
||||||
|
}
|
||||||
|
return color_blend16(_t->_segT._colorT[slot], colors[slot], prog);
|
||||||
#else
|
#else
|
||||||
return isInTransition() ? color_blend16(_t->_colorT[slot], colors[slot], progress()) : colors[slot];
|
return color_blend16(_t->_colorT[slot], colors[slot], prog);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,32 +449,37 @@ void Segment::beginDraw() {
|
|||||||
}
|
}
|
||||||
// load palette into _currentPalette
|
// load palette into _currentPalette
|
||||||
loadPalette(_currentPalette, palette);
|
loadPalette(_currentPalette, palette);
|
||||||
if (strip.paletteFade && prog < 0xFFFFU) {
|
if (prog < 0xFFFFU) {
|
||||||
// blend palettes
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
|
if (blendingStyle > BLEND_STYLE_FADE) {
|
||||||
// minimum blend time is 100ms maximum is 65535ms
|
//if (_modeBlend) loadPalette(_currentPalette, _t->_palTid); // not fade/blend transition, each effect uses its palette
|
||||||
unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
|
if (_modeBlend) _currentPalette = _t->_palT; // not fade/blend transition, each effect uses its palette
|
||||||
for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48);
|
} else
|
||||||
_currentPalette = _t->_palT; // copy transitioning/temporary palette
|
#endif
|
||||||
|
{
|
||||||
|
// blend palettes
|
||||||
|
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
|
||||||
|
// minimum blend time is 100ms maximum is 65535ms
|
||||||
|
unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
|
||||||
|
for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48);
|
||||||
|
_currentPalette = _t->_palT; // copy transitioning/temporary palette
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// relies on WS2812FX::service() to call it for each frame
|
// relies on WS2812FX::service() to call it for each frame
|
||||||
void Segment::handleRandomPalette() {
|
void Segment::handleRandomPalette() {
|
||||||
// is it time to generate a new palette?
|
// is it time to generate a new palette?
|
||||||
if ((uint16_t)((uint16_t)(millis() / 1000U) - _lastPaletteChange) > randomPaletteChangeTime){
|
if ((uint16_t)(millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) {
|
||||||
_newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
|
_newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
|
||||||
_lastPaletteChange = (uint16_t)(millis() / 1000U);
|
_lastPaletteChange = (uint16_t)(millis()/1000U);
|
||||||
_lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately
|
_lastPaletteBlend = (uint16_t)(millis())-512; // starts blending immediately
|
||||||
}
|
}
|
||||||
|
|
||||||
// if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls)
|
// assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
|
||||||
if (strip.paletteFade) {
|
// in reality there need to be 255 blends to fully blend two entirely different palettes
|
||||||
// assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
|
if ((uint16_t)millis() - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
|
||||||
// in reality there need to be 255 blends to fully blend two entirely different palettes
|
_lastPaletteBlend = (uint16_t)millis();
|
||||||
if ((uint16_t)((uint16_t)millis() - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
|
|
||||||
_lastPaletteBlend = (uint16_t)millis();
|
|
||||||
}
|
|
||||||
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +554,8 @@ Segment &Segment::setColor(uint8_t slot, uint32_t c) {
|
|||||||
if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black
|
if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black
|
||||||
if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black
|
if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black
|
||||||
}
|
}
|
||||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
//DEBUG_PRINTF_P(PSTR("- Starting color transition: %d [0x%X]\n"), slot, c);
|
||||||
|
startTransition(strip.getTransition()); // start transition prior to change
|
||||||
colors[slot] = c;
|
colors[slot] = c;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
return *this;
|
return *this;
|
||||||
@ -537,7 +568,7 @@ Segment &Segment::setCCT(uint16_t k) {
|
|||||||
k = (k - 1900) >> 5;
|
k = (k - 1900) >> 5;
|
||||||
}
|
}
|
||||||
if (cct != k) {
|
if (cct != k) {
|
||||||
//DEBUGFX_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k);
|
//DEBUG_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k);
|
||||||
startTransition(strip.getTransition()); // start transition prior to change
|
startTransition(strip.getTransition()); // start transition prior to change
|
||||||
cct = k;
|
cct = k;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
@ -547,7 +578,7 @@ Segment &Segment::setCCT(uint16_t k) {
|
|||||||
|
|
||||||
Segment &Segment::setOpacity(uint8_t o) {
|
Segment &Segment::setOpacity(uint8_t o) {
|
||||||
if (opacity != o) {
|
if (opacity != o) {
|
||||||
//DEBUGFX_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o);
|
//DEBUG_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o);
|
||||||
startTransition(strip.getTransition()); // start transition prior to change
|
startTransition(strip.getTransition()); // start transition prior to change
|
||||||
opacity = o;
|
opacity = o;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
@ -557,7 +588,7 @@ Segment &Segment::setOpacity(uint8_t o) {
|
|||||||
|
|
||||||
Segment &Segment::setOption(uint8_t n, bool val) {
|
Segment &Segment::setOption(uint8_t n, bool val) {
|
||||||
bool prevOn = on;
|
bool prevOn = on;
|
||||||
if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
|
if (n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
|
||||||
if (val) options |= 0x01 << n;
|
if (val) options |= 0x01 << n;
|
||||||
else options &= ~(0x01 << n);
|
else options &= ~(0x01 << n);
|
||||||
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
|
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
|
||||||
@ -571,7 +602,8 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
// if we have a valid mode & is not reserved
|
// if we have a valid mode & is not reserved
|
||||||
if (fx != mode) {
|
if (fx != mode) {
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
//DEBUG_PRINTF_P(PSTR("- Starting effect transition: %d\n"), fx);
|
||||||
|
startTransition(strip.getTransition()); // set effect transitions
|
||||||
#endif
|
#endif
|
||||||
mode = fx;
|
mode = fx;
|
||||||
int sOpt;
|
int sOpt;
|
||||||
@ -606,7 +638,8 @@ Segment &Segment::setPalette(uint8_t pal) {
|
|||||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes
|
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes
|
||||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes
|
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes
|
||||||
if (pal != palette) {
|
if (pal != palette) {
|
||||||
if (strip.paletteFade) startTransition(strip.getTransition());
|
//DEBUG_PRINTF_P(PSTR("- Starting palette transition: %d\n"), pal);
|
||||||
|
startTransition(strip.getTransition());
|
||||||
palette = pal;
|
palette = pal;
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
}
|
}
|
||||||
@ -692,7 +725,7 @@ uint16_t Segment::virtualLength() const {
|
|||||||
vLen = max(vW,vH); // get the longest dimension
|
vLen = max(vW,vH); // get the longest dimension
|
||||||
break;
|
break;
|
||||||
case M12_pArc:
|
case M12_pArc:
|
||||||
vLen = sqrt16(vH*vH + vW*vW); // use diagonal
|
vLen = sqrt32_bw(vH*vH + vW*vW); // use diagonal
|
||||||
break;
|
break;
|
||||||
case M12_sPinwheel:
|
case M12_sPinwheel:
|
||||||
vLen = getPinwheelLength(vW, vH);
|
vLen = getPinwheelLength(vW, vH);
|
||||||
@ -710,6 +743,33 @@ uint16_t Segment::virtualLength() const {
|
|||||||
return vLength;
|
return vLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false)
|
||||||
|
// if clipping start > stop the clipping range is inverted
|
||||||
|
// _modeBlend==true -> old effect during transition
|
||||||
|
// _modeBlend==false -> new effect during transition
|
||||||
|
bool IRAM_ATTR_YN Segment::isPixelClipped(int i) const {
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) {
|
||||||
|
bool invert = _clipStart > _clipStop; // ineverted start & stop
|
||||||
|
int start = invert ? _clipStop : _clipStart;
|
||||||
|
int stop = invert ? _clipStart : _clipStop;
|
||||||
|
if (blendingStyle == BLEND_STYLE_FAIRY_DUST) {
|
||||||
|
unsigned len = stop - start;
|
||||||
|
if (len < 2) return false;
|
||||||
|
unsigned shuffled = hashInt(i) % len;
|
||||||
|
unsigned pos = (shuffled * 0xFFFFU) / len;
|
||||||
|
return (progress() <= pos) ^ _modeBlend;
|
||||||
|
}
|
||||||
|
const bool iInside = (i >= start && i < stop);
|
||||||
|
//if (!invert && iInside) return _modeBlend;
|
||||||
|
//if ( invert && !iInside) return _modeBlend;
|
||||||
|
//return !_modeBlend;
|
||||||
|
return !iInside ^ invert ^ _modeBlend; // thanks @willmmiles (https://github.com/Aircoookie/WLED/pull/3877#discussion_r1554633876)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
|
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
|
||||||
{
|
{
|
||||||
if (!isActive() || i < 0) return; // not active or invalid index
|
if (!isActive() || i < 0) return; // not active or invalid index
|
||||||
@ -842,6 +902,18 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
// if we blend using "push" style we need to "shift" new mode to left or right
|
||||||
|
if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) {
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
unsigned dI = prog * vL / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI;
|
||||||
|
else i += dI;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (i >= vL || i < 0 || isPixelClipped(i)) return; // handle clipping on 1D
|
||||||
|
|
||||||
unsigned len = length();
|
unsigned len = length();
|
||||||
// if color is unscaled
|
// if color is unscaled
|
||||||
if (!_colorScaled) col = color_fade(col, _segBri);
|
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||||
@ -867,14 +939,16 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
|
|||||||
indexMir += offset; // offset/phase
|
indexMir += offset; // offset/phase
|
||||||
if (indexMir >= stop) indexMir -= len; // wrap
|
if (indexMir >= stop) indexMir -= len; // wrap
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, uint16_t(0xFFFFU - progress()));
|
// _modeBlend==true -> old effect
|
||||||
|
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, 0xFFFFU - progress());
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColor(indexMir, tmpCol);
|
strip.setPixelColor(indexMir, tmpCol);
|
||||||
}
|
}
|
||||||
indexSet += offset; // offset/phase
|
indexSet += offset; // offset/phase
|
||||||
if (indexSet >= stop) indexSet -= len; // wrap
|
if (indexSet >= stop) indexSet -= len; // wrap
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, uint16_t(0xFFFFU - progress()));
|
// _modeBlend==true -> old effect
|
||||||
|
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, 0xFFFFU - progress());
|
||||||
#endif
|
#endif
|
||||||
strip.setPixelColor(indexSet, tmpCol);
|
strip.setPixelColor(indexSet, tmpCol);
|
||||||
}
|
}
|
||||||
@ -920,6 +994,9 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
{
|
{
|
||||||
if (!isActive()) return 0; // not active
|
if (!isActive()) return 0; // not active
|
||||||
|
|
||||||
|
int vL = vLength();
|
||||||
|
if (i >= vL || i < 0) return 0;
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (is2D()) {
|
if (is2D()) {
|
||||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||||
@ -935,7 +1012,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
break; }
|
break; }
|
||||||
case M12_pArc:
|
case M12_pArc:
|
||||||
if (i >= vW && i >= vH) {
|
if (i >= vW && i >= vH) {
|
||||||
unsigned vI = sqrt16(i*i/2);
|
unsigned vI = sqrt32_bw(i*i/2);
|
||||||
return getPixelColorXY(vI,vI); // use diagonal
|
return getPixelColorXY(vI,vI); // use diagonal
|
||||||
}
|
}
|
||||||
case M12_pCorner:
|
case M12_pCorner:
|
||||||
@ -976,7 +1053,18 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (reverse) i = vLength() - i - 1;
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) {
|
||||||
|
unsigned prog = 0xFFFF - progress();
|
||||||
|
unsigned dI = prog * vL / 0xFFFF;
|
||||||
|
if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI;
|
||||||
|
else i += dI;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (i >= vL || i < 0 || isPixelClipped(i)) return 0; // handle clipping on 1D
|
||||||
|
|
||||||
|
if (reverse) i = vL - i - 1;
|
||||||
i *= groupLength();
|
i *= groupLength();
|
||||||
i += start;
|
i += start;
|
||||||
// offset/phase
|
// offset/phase
|
||||||
@ -1209,7 +1297,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
|
|||||||
if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
|
if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
|
||||||
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
||||||
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||||
CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
CRGBW palcol = ColorFromPaletteWLED(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||||
palcol.w = W(color);
|
palcol.w = W(color);
|
||||||
|
|
||||||
return palcol.color32;
|
return palcol.color32;
|
||||||
@ -1418,21 +1506,78 @@ void WS2812FX::service() {
|
|||||||
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
||||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||||
// would need to be allocated for each effect and then blended together for each pixel.
|
// would need to be allocated for each effect and then blended together for each pixel.
|
||||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
|
||||||
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (modeBlending && seg.mode != tmpMode) {
|
Segment::setClippingRect(0, 0); // disable clipping (just in case)
|
||||||
|
if (seg.isInTransition()) {
|
||||||
|
// set clipping rectangle
|
||||||
|
// new mode is run inside clipping area and old mode outside clipping area
|
||||||
|
unsigned p = seg.progress();
|
||||||
|
unsigned w = seg.is2D() ? Segment::vWidth() : Segment::vLength();
|
||||||
|
unsigned h = Segment::vHeight();
|
||||||
|
unsigned dw = p * w / 0xFFFFU + 1;
|
||||||
|
unsigned dh = p * h / 0xFFFFU + 1;
|
||||||
|
unsigned orgBS = blendingStyle;
|
||||||
|
if (w*h == 1) blendingStyle = BLEND_STYLE_FADE; // disable belending for single pixel segments (use fade instead)
|
||||||
|
switch (blendingStyle) {
|
||||||
|
case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped())
|
||||||
|
Segment::setClippingRect(0, w, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_RIGHT: // left-to-right
|
||||||
|
case BLEND_STYLE_PUSH_RIGHT: // left-to-right
|
||||||
|
Segment::setClippingRect(0, dw, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_LEFT: // right-to-left
|
||||||
|
case BLEND_STYLE_PUSH_LEFT: // right-to-left
|
||||||
|
Segment::setClippingRect(w - dw, w, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PINCH_OUT: // corners
|
||||||
|
Segment::setClippingRect((w + dw)/2, (w - dw)/2, (h + dh)/2, (h - dh)/2); // inverted!!
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_INSIDE_OUT: // outward
|
||||||
|
Segment::setClippingRect((w - dw)/2, (w + dw)/2, (h - dh)/2, (h + dh)/2);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_DOWN: // top-to-bottom (2D)
|
||||||
|
case BLEND_STYLE_PUSH_DOWN: // top-to-bottom (2D)
|
||||||
|
Segment::setClippingRect(0, w, 0, dh);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_SWIPE_UP: // bottom-to-top (2D)
|
||||||
|
case BLEND_STYLE_PUSH_UP: // bottom-to-top (2D)
|
||||||
|
Segment::setClippingRect(0, w, h - dh, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_OPEN_H: // horizontal-outward (2D) same look as INSIDE_OUT on 1D
|
||||||
|
Segment::setClippingRect((w - dw)/2, (w + dw)/2, 0, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_OPEN_V: // vertical-outward (2D)
|
||||||
|
Segment::setClippingRect(0, w, (h - dh)/2, (h + dh)/2);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_TL: // TL-to-BR (2D)
|
||||||
|
Segment::setClippingRect(0, dw, 0, dh);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_TR: // TR-to-BL (2D)
|
||||||
|
Segment::setClippingRect(w - dw, w, 0, dh);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_BR: // BR-to-TL (2D)
|
||||||
|
Segment::setClippingRect(w - dw, w, h - dh, h);
|
||||||
|
break;
|
||||||
|
case BLEND_STYLE_PUSH_BL: // BL-to-TR (2D)
|
||||||
|
Segment::setClippingRect(0, dw, h - dh, h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
frameDelay = (*_mode[seg.currentMode()])(); // run new/current mode
|
||||||
|
// now run old/previous mode
|
||||||
Segment::tmpsegd_t _tmpSegData;
|
Segment::tmpsegd_t _tmpSegData;
|
||||||
Segment::modeBlend(true); // set semaphore
|
Segment::modeBlend(true); // set semaphore
|
||||||
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
||||||
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||||
unsigned d2 = (*_mode[tmpMode])(); // run old mode
|
frameDelay = min(frameDelay, (unsigned)(*_mode[seg.currentMode()])()); // run old mode
|
||||||
|
seg.call++; // increment old mode run counter
|
||||||
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
||||||
frameDelay = min(frameDelay,d2); // use shortest delay
|
|
||||||
Segment::modeBlend(false); // unset semaphore
|
Segment::modeBlend(false); // unset semaphore
|
||||||
}
|
blendingStyle = orgBS; // restore blending style if it was modified for single pixel segment
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
frameDelay = (*_mode[seg.mode])(); // run effect mode (not in transition)
|
||||||
seg.call++;
|
seg.call++;
|
||||||
if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition
|
if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition
|
||||||
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
|
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
|
||||||
@ -1442,6 +1587,7 @@ void WS2812FX::service() {
|
|||||||
}
|
}
|
||||||
_segment_index++;
|
_segment_index++;
|
||||||
}
|
}
|
||||||
|
Segment::setClippingRect(0, 0); // disable clipping for overlays
|
||||||
_isServicing = false;
|
_isServicing = false;
|
||||||
_triggered = false;
|
_triggered = false;
|
||||||
|
|
||||||
|
@ -114,8 +114,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
CJSON(strip.correctWB, hw_led["cct"]);
|
CJSON(strip.correctWB, hw_led["cct"]);
|
||||||
CJSON(strip.cctFromRgb, hw_led[F("cr")]);
|
CJSON(strip.cctFromRgb, hw_led[F("cr")]);
|
||||||
CJSON(cctICused, hw_led[F("ic")]);
|
CJSON(cctICused, hw_led[F("ic")]);
|
||||||
int cctBlending = 0;
|
uint8_t cctBlending = hw_led[F("cb")] | Bus::getCCTBlend();
|
||||||
CJSON(cctBlending, hw_led[F("cb")]);
|
|
||||||
Bus::setCCTBlend(cctBlending);
|
Bus::setCCTBlend(cctBlending);
|
||||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||||
CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
|
CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
|
||||||
@ -407,12 +406,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||||
|
|
||||||
JsonObject light_tr = light["tr"];
|
JsonObject light_tr = light["tr"];
|
||||||
CJSON(fadeTransition, light_tr["mode"]);
|
|
||||||
CJSON(modeBlending, light_tr["fx"]);
|
|
||||||
int tdd = light_tr["dur"] | -1;
|
int tdd = light_tr["dur"] | -1;
|
||||||
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
||||||
strip.setTransition(fadeTransition ? transitionDelayDefault : 0);
|
strip.setTransition(transitionDelayDefault);
|
||||||
CJSON(strip.paletteFade, light_tr["pal"]);
|
|
||||||
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
|
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
|
||||||
CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]);
|
CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]);
|
||||||
|
|
||||||
@ -922,10 +918,7 @@ void serializeConfig() {
|
|||||||
light_gc["val"] = gammaCorrectVal;
|
light_gc["val"] = gammaCorrectVal;
|
||||||
|
|
||||||
JsonObject light_tr = light.createNestedObject("tr");
|
JsonObject light_tr = light.createNestedObject("tr");
|
||||||
light_tr["mode"] = fadeTransition;
|
|
||||||
light_tr["fx"] = modeBlending;
|
|
||||||
light_tr["dur"] = transitionDelayDefault / 100;
|
light_tr["dur"] = transitionDelayDefault / 100;
|
||||||
light_tr["pal"] = strip.paletteFade;
|
|
||||||
light_tr[F("rpc")] = randomPaletteChangeTime;
|
light_tr[F("rpc")] = randomPaletteChangeTime;
|
||||||
light_tr[F("hrp")] = useHarmonicRandomPalette;
|
light_tr[F("hrp")] = useHarmonicRandomPalette;
|
||||||
|
|
||||||
|
@ -266,7 +266,29 @@
|
|||||||
<div id="segutil2">
|
<div id="segutil2">
|
||||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||||
</div>
|
</div>
|
||||||
<p>Transition: <input id="tt" type="number" min="0" max="65.5" step="0.1" value="0.7"> s</p>
|
<p>Transition: <input id="tt" type="number" min="0" max="65.5" step="0.1" value="0.7" onchange="parseFloat(this.value)===0?gId('bsp').classList.add('hide'):gId('bsp').classList.remove('hide');"> s</p>
|
||||||
|
<p id="bsp">Blend:
|
||||||
|
<select id="bs" class="sel-sg" onchange="requestJson({'bs':parseInt(this.value)})">
|
||||||
|
<option value="0">Fade</option>
|
||||||
|
<option value="1">Fairy Dust</option>
|
||||||
|
<option value="2">Swipe right</option>
|
||||||
|
<option value="3">Swipe left</option>
|
||||||
|
<option value="4">Push right</option>
|
||||||
|
<option value="5">Push left</option>
|
||||||
|
<option value="6">Pinch-out</option>
|
||||||
|
<option value="7">Inside-out</option>
|
||||||
|
<option value="8" data-type="2D">Swipe up</option>
|
||||||
|
<option value="9" data-type="2D">Swipe down</option>
|
||||||
|
<option value="10" data-type="2D">Open V</option>
|
||||||
|
<option value="11" data-type="2D">Open H</option>
|
||||||
|
<option value="12" data-type="2D">Push up</option>
|
||||||
|
<option value="13" data-type="2D">Push down</option>
|
||||||
|
<option value="14" data-type="2D">Push TL</option>
|
||||||
|
<option value="15" data-type="2D">Push TR</option>
|
||||||
|
<option value="16" data-type="2D">Push BR</option>
|
||||||
|
<option value="17" data-type="2D">Push BL</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
<p id="ledmap" class="hide"></p>
|
<p id="ledmap" class="hide"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -677,8 +677,10 @@ function parseInfo(i) {
|
|||||||
isM = mw>0 && mh>0;
|
isM = mw>0 && mh>0;
|
||||||
if (!isM) {
|
if (!isM) {
|
||||||
gId("filter2D").classList.add('hide');
|
gId("filter2D").classList.add('hide');
|
||||||
|
gId('bs').querySelectorAll('option[data-type="2D"]').forEach((o,i)=>{o.style.display='none';});
|
||||||
} else {
|
} else {
|
||||||
gId("filter2D").classList.remove('hide');
|
gId("filter2D").classList.remove('hide');
|
||||||
|
gId('bs').querySelectorAll('option[data-type="2D"]').forEach((o,i)=>{o.style.display='';});
|
||||||
}
|
}
|
||||||
// if (i.noaudio) {
|
// if (i.noaudio) {
|
||||||
// gId("filterVol").classList.add("hide");
|
// gId("filterVol").classList.add("hide");
|
||||||
@ -1437,6 +1439,9 @@ function readState(s,command=false)
|
|||||||
|
|
||||||
tr = s.transition;
|
tr = s.transition;
|
||||||
gId('tt').value = tr/10;
|
gId('tt').value = tr/10;
|
||||||
|
gId('bs').value = s.bs || 0;
|
||||||
|
if (tr===0) gId('bsp').classList.add('hide')
|
||||||
|
else gId('bsp').classList.remove('hide')
|
||||||
|
|
||||||
populateSegments(s);
|
populateSegments(s);
|
||||||
var selc=0;
|
var selc=0;
|
||||||
@ -1698,6 +1703,7 @@ function requestJson(command=null)
|
|||||||
var tn = parseInt(t.value*10);
|
var tn = parseInt(t.value*10);
|
||||||
if (tn != tr) command.transition = tn;
|
if (tn != tr) command.transition = tn;
|
||||||
}
|
}
|
||||||
|
//command.bs = parseInt(gId('bs').value);
|
||||||
req = JSON.stringify(command);
|
req = JSON.stringify(command);
|
||||||
if (req.length > 1340) useWs = false; // do not send very long requests over websocket
|
if (req.length > 1340) useWs = false; // do not send very long requests over websocket
|
||||||
if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes
|
if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes
|
||||||
|
@ -844,12 +844,7 @@ Swap: <select id="xw${s}" name="XW${s}">
|
|||||||
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
||||||
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||||
<h3>Transitions</h3>
|
<h3>Transitions</h3>
|
||||||
Enable transitions: <input type="checkbox" name="TF" onchange="gId('tran').style.display=this.checked?'inline':'none';"><br>
|
Default transition time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
||||||
<span id="tran">
|
|
||||||
Effect blending: <input type="checkbox" name="EB"><br>
|
|
||||||
Default transition time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
|
||||||
Palette transitions: <input type="checkbox" name="PF"><br>
|
|
||||||
</span>
|
|
||||||
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
||||||
Use harmonic <i>Random Cycle</i> Palette: <input type="checkbox" name="TH"><br>
|
Use harmonic <i>Random Cycle</i> Palette: <input type="checkbox" name="TH"><br>
|
||||||
<h3>Timed light</h3>
|
<h3>Timed light</h3>
|
||||||
|
@ -494,6 +494,7 @@ um_data_t* simulateSound(uint8_t simulationId);
|
|||||||
void enumerateLedmaps();
|
void enumerateLedmaps();
|
||||||
[[gnu::hot]] uint8_t get_random_wheel_index(uint8_t pos);
|
[[gnu::hot]] uint8_t get_random_wheel_index(uint8_t pos);
|
||||||
[[gnu::hot, gnu::pure]] float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
[[gnu::hot, gnu::pure]] float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
||||||
|
uint32_t hashInt(uint32_t s);
|
||||||
|
|
||||||
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
||||||
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
||||||
@ -553,6 +554,7 @@ float asin_t(float x);
|
|||||||
template <typename T> T atan_t(T x);
|
template <typename T> T atan_t(T x);
|
||||||
float floor_t(float x);
|
float floor_t(float x);
|
||||||
float fmod_t(float num, float denom);
|
float fmod_t(float num, float denom);
|
||||||
|
uint32_t sqrt32_bw(uint32_t x);
|
||||||
#define sin_t sin_approx
|
#define sin_t sin_approx
|
||||||
#define cos_t cos_approx
|
#define cos_t cos_approx
|
||||||
#define tan_t tan_approx
|
#define tan_t tan_approx
|
||||||
|
@ -332,15 +332,20 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
tr = root[F("transition")] | -1;
|
tr = root[F("transition")] | -1;
|
||||||
if (tr >= 0) {
|
if (tr >= 0) {
|
||||||
transitionDelay = tr * 100;
|
transitionDelay = tr * 100;
|
||||||
if (fadeTransition) strip.setTransition(transitionDelay);
|
strip.setTransition(transitionDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
blendingStyle = root[F("bs")] | blendingStyle;
|
||||||
|
blendingStyle = constrain(blendingStyle, 0, BLEND_STYLE_COUNT-1);
|
||||||
|
#endif
|
||||||
|
|
||||||
// temporary transition (applies only once)
|
// temporary transition (applies only once)
|
||||||
tr = root[F("tt")] | -1;
|
tr = root[F("tt")] | -1;
|
||||||
if (tr >= 0) {
|
if (tr >= 0) {
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
if (fadeTransition) strip.setTransition(tr * 100);
|
strip.setTransition(tr * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr = root[F("tb")] | -1;
|
tr = root[F("tb")] | -1;
|
||||||
@ -568,6 +573,9 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
root["on"] = (bri > 0);
|
root["on"] = (bri > 0);
|
||||||
root["bri"] = briLast;
|
root["bri"] = briLast;
|
||||||
root[F("transition")] = transitionDelay/100; //in 100ms
|
root[F("transition")] = transitionDelay/100; //in 100ms
|
||||||
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
|
root[F("bs")] = blendingStyle;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forPreset) {
|
if (!forPreset) {
|
||||||
@ -761,7 +769,7 @@ void serializeInfo(JsonObject root)
|
|||||||
|
|
||||||
root[F("freeheap")] = ESP.getFreeHeap();
|
root[F("freeheap")] = ESP.getFreeHeap();
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
if (psramSafe && psramFound()) root[F("psram")] = ESP.getFreePsram();
|
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||||
#endif
|
#endif
|
||||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ byte scaledBri(byte in)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//applies global brightness
|
//applies global temporary brightness (briT) to strip
|
||||||
void applyBri() {
|
void applyBri() {
|
||||||
if (!(realtimeMode && arlsForceMaxBri)) {
|
if (!(realtimeMode && arlsForceMaxBri)) {
|
||||||
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
||||||
@ -85,7 +85,7 @@ void applyFinalBri() {
|
|||||||
briOld = bri;
|
briOld = bri;
|
||||||
briT = bri;
|
briT = bri;
|
||||||
applyBri();
|
applyBri();
|
||||||
strip.trigger();
|
strip.trigger(); // force one last update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,29 +129,23 @@ void stateUpdated(byte callMode) {
|
|||||||
// notify usermods of state change
|
// notify usermods of state change
|
||||||
UsermodManager::onStateChange(callMode);
|
UsermodManager::onStateChange(callMode);
|
||||||
|
|
||||||
if (fadeTransition) {
|
if (strip.getTransition() == 0) {
|
||||||
if (strip.getTransition() == 0) {
|
jsonTransitionOnce = false;
|
||||||
jsonTransitionOnce = false;
|
transitionActive = false;
|
||||||
transitionActive = false;
|
|
||||||
applyFinalBri();
|
|
||||||
strip.trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transitionActive) {
|
|
||||||
briOld = briT;
|
|
||||||
} else
|
|
||||||
strip.setTransitionMode(true); // force all segments to transition mode
|
|
||||||
transitionActive = true;
|
|
||||||
transitionStartTime = millis();
|
|
||||||
} else {
|
|
||||||
applyFinalBri();
|
applyFinalBri();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (transitionActive) {
|
||||||
|
briOld = briT;
|
||||||
|
} else
|
||||||
|
strip.setTransitionMode(true); // force all segments to transition mode
|
||||||
|
transitionActive = true;
|
||||||
|
transitionStartTime = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void updateInterfaces(uint8_t callMode)
|
void updateInterfaces(uint8_t callMode) {
|
||||||
{
|
|
||||||
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
|
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
|
||||||
|
|
||||||
sendDataWs();
|
sendDataWs();
|
||||||
@ -172,8 +166,7 @@ void updateInterfaces(uint8_t callMode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleTransitions()
|
void handleTransitions() {
|
||||||
{
|
|
||||||
//handle still pending interface update
|
//handle still pending interface update
|
||||||
updateInterfaces(interfaceUpdateCallMode);
|
updateInterfaces(interfaceUpdateCallMode);
|
||||||
|
|
||||||
@ -204,8 +197,7 @@ void colorUpdated(byte callMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleNightlight()
|
void handleNightlight() {
|
||||||
{
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; // take care of millis() rollover
|
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; // take care of millis() rollover
|
||||||
if (now - lastNlUpdate < 100) return; // allow only 10 NL updates per second
|
if (now - lastNlUpdate < 100) return; // allow only 10 NL updates per second
|
||||||
@ -285,7 +277,6 @@ void handleNightlight()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//utility for FastLED to use our custom timer
|
//utility for FastLED to use our custom timer
|
||||||
uint32_t get_millisecond_timer()
|
uint32_t get_millisecond_timer() {
|
||||||
{
|
|
||||||
return strip.now;
|
return strip.now;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ if (millis() - presetCycledTime > (100 * playlistEntryDur) || doAdvancePlaylist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0);
|
strip.setTransition(playlistEntries[playlistIndex].tr * 100);
|
||||||
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
||||||
applyPresetFromPlaylist(playlistEntries[playlistIndex].preset);
|
applyPresetFromPlaylist(playlistEntries[playlistIndex].preset);
|
||||||
doAdvancePlaylist = false;
|
doAdvancePlaylist = false;
|
||||||
|
@ -327,11 +327,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
}
|
}
|
||||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||||
|
|
||||||
fadeTransition = request->hasArg(F("TF"));
|
|
||||||
modeBlending = request->hasArg(F("EB"));
|
|
||||||
t = request->arg(F("TD")).toInt();
|
t = request->arg(F("TD")).toInt();
|
||||||
if (t >= 0) transitionDelayDefault = t;
|
if (t >= 0) transitionDelayDefault = t;
|
||||||
strip.paletteFade = request->hasArg(F("PF"));
|
|
||||||
t = request->arg(F("TP")).toInt();
|
t = request->arg(F("TP")).toInt();
|
||||||
randomPaletteChangeTime = MIN(255,MAX(1,t));
|
randomPaletteChangeTime = MIN(255,MAX(1,t));
|
||||||
useHarmonicRandomPalette = request->hasArg(F("TH"));
|
useHarmonicRandomPalette = request->hasArg(F("TH"));
|
||||||
@ -1149,7 +1146,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
|
|
||||||
pos = req.indexOf(F("TT="));
|
pos = req.indexOf(F("TT="));
|
||||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||||
if (fadeTransition) strip.setTransition(transitionDelay);
|
strip.setTransition(transitionDelay);
|
||||||
|
|
||||||
//set time (unix timestamp)
|
//set time (unix timestamp)
|
||||||
pos = req.indexOf(F("ST="));
|
pos = req.indexOf(F("ST="));
|
||||||
|
@ -225,10 +225,8 @@ static void parseNotifyPacket(const uint8_t *udpIn) {
|
|||||||
|
|
||||||
// set transition time before making any segment changes
|
// set transition time before making any segment changes
|
||||||
if (version > 3) {
|
if (version > 3) {
|
||||||
if (fadeTransition) {
|
jsonTransitionOnce = true;
|
||||||
jsonTransitionOnce = true;
|
strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00));
|
||||||
strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//apply colors from notification to main segment, only if not syncing full segments
|
//apply colors from notification to main segment, only if not syncing full segments
|
||||||
|
@ -595,6 +595,13 @@ float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
|
|||||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t hashInt(uint32_t s) {
|
||||||
|
// borrowed from https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key
|
||||||
|
s = ((s >> 16) ^ s) * 0x45d9f3b;
|
||||||
|
s = ((s >> 16) ^ s) * 0x45d9f3b;
|
||||||
|
return (s >> 16) ^ s;
|
||||||
|
}
|
||||||
|
|
||||||
// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
||||||
uint32_t hw_random(uint32_t upperlimit) {
|
uint32_t hw_random(uint32_t upperlimit) {
|
||||||
uint32_t rnd = hw_random();
|
uint32_t rnd = hw_random();
|
||||||
@ -608,4 +615,4 @@ int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) {
|
|||||||
}
|
}
|
||||||
uint32_t diff = upperlimit - lowerlimit;
|
uint32_t diff = upperlimit - lowerlimit;
|
||||||
return hw_random(diff) + lowerlimit;
|
return hw_random(diff) + lowerlimit;
|
||||||
}
|
}
|
||||||
|
@ -591,8 +591,7 @@ WLED_GLOBAL bool wasConnected _INIT(false);
|
|||||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||||
|
|
||||||
// transitions
|
// transitions
|
||||||
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color
|
WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style
|
||||||
WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending
|
|
||||||
WLED_GLOBAL bool transitionActive _INIT(false);
|
WLED_GLOBAL bool transitionActive _INIT(false);
|
||||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
||||||
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
||||||
|
@ -224,7 +224,7 @@ void loadSettingsFromEEPROM()
|
|||||||
|
|
||||||
if (lastEEPROMversion > 7)
|
if (lastEEPROMversion > 7)
|
||||||
{
|
{
|
||||||
strip.paletteFade = EEPROM.read(374);
|
//strip.paletteFade = EEPROM.read(374);
|
||||||
strip.paletteBlend = EEPROM.read(382);
|
strip.paletteBlend = EEPROM.read(382);
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
|
@ -220,3 +220,27 @@ float fmod_t(float num, float denom) {
|
|||||||
#endif
|
#endif
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bit-wise integer square root calculation (exact)
|
||||||
|
uint32_t sqrt32_bw(uint32_t x) {
|
||||||
|
uint32_t res = 0;
|
||||||
|
uint32_t bit;
|
||||||
|
uint32_t num = x; // use 32bit for faster calculation
|
||||||
|
|
||||||
|
if(num < 1 << 10) bit = 1 << 10; // speed optimization for small numbers < 32^2
|
||||||
|
else if (num < 1 << 20) bit = 1 << 20; // speed optimization for medium numbers < 1024^2
|
||||||
|
else bit = 1 << 30; // start with highest power of 4 <= 2^32
|
||||||
|
|
||||||
|
while (bit > num) bit >>= 2; // reduce iterations
|
||||||
|
|
||||||
|
while (bit != 0) {
|
||||||
|
if (num >= res + bit) {
|
||||||
|
num -= res + bit;
|
||||||
|
res = (res >> 1) + bit;
|
||||||
|
} else {
|
||||||
|
res >>= 1;
|
||||||
|
}
|
||||||
|
bit >>= 2;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@ -370,10 +370,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
printSetFormCheckbox(settingsScript,PSTR("GB"),gammaCorrectBri);
|
printSetFormCheckbox(settingsScript,PSTR("GB"),gammaCorrectBri);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("GC"),gammaCorrectCol);
|
printSetFormCheckbox(settingsScript,PSTR("GC"),gammaCorrectCol);
|
||||||
dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(settingsScript,PSTR("GV"),nS);
|
dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(settingsScript,PSTR("GV"),nS);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("TF"),fadeTransition);
|
|
||||||
printSetFormCheckbox(settingsScript,PSTR("EB"),modeBlending);
|
|
||||||
printSetFormValue(settingsScript,PSTR("TD"),transitionDelayDefault);
|
printSetFormValue(settingsScript,PSTR("TD"),transitionDelayDefault);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("PF"),strip.paletteFade);
|
|
||||||
printSetFormValue(settingsScript,PSTR("TP"),randomPaletteChangeTime);
|
printSetFormValue(settingsScript,PSTR("TP"),randomPaletteChangeTime);
|
||||||
printSetFormCheckbox(settingsScript,PSTR("TH"),useHarmonicRandomPalette);
|
printSetFormCheckbox(settingsScript,PSTR("TH"),useHarmonicRandomPalette);
|
||||||
printSetFormValue(settingsScript,PSTR("BF"),briMultiplier);
|
printSetFormValue(settingsScript,PSTR("BF"),briMultiplier);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user