Refactoring WS2812FX class.
- effect functions no longer part of class - methods to access private members - separate Segment, Segment_runtime, ColorTransition from WS2812FX
This commit is contained in:
parent
febd7cbca8
commit
64fd207533
@ -103,7 +103,7 @@ class Animated_Staircase : public Usermod {
|
||||
|
||||
void updateSegments() {
|
||||
mainSegmentId = strip.getMainSegmentId();
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
maxSegmentId = i - 1;
|
||||
@ -290,7 +290,7 @@ class Animated_Staircase : public Usermod {
|
||||
}
|
||||
} else {
|
||||
// Restore segment options
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
maxSegmentId = i - 1;
|
||||
|
@ -355,7 +355,7 @@ public:
|
||||
// Color in grayscale bitmaps if Segment 1 exists
|
||||
// TODO If secondary and tertiary are black, color all in primary,
|
||||
// else color first three from Seg 1 color slots and last three from Seg 2 color slots
|
||||
WS2812FX::Segment& seg1 = strip.getSegment(tubeSegment);
|
||||
Segment& seg1 = strip.getSegment(tubeSegment);
|
||||
if (seg1.isActive()) {
|
||||
digitColor = strip.getPixelColor(seg1.start + digit);
|
||||
dimming = seg1.opacity;
|
||||
|
@ -63,7 +63,7 @@ class ElekstubeIPSUsermod : public Usermod {
|
||||
if (!toki.isTick()) return;
|
||||
updateLocalTime();
|
||||
|
||||
WS2812FX::Segment& seg1 = strip.getSegment(tfts.tubeSegment);
|
||||
Segment& seg1 = strip.getSegment(tfts.tubeSegment);
|
||||
if (seg1.isActive()) {
|
||||
bool update = false;
|
||||
if (seg1.opacity != lastBri) update = true;
|
||||
|
@ -96,7 +96,7 @@ class StairwayWipeUsermod : public Usermod {
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
WS2812FX::Segment& seg = strip.getSegment(0);
|
||||
Segment& seg = strip.getSegment(0);
|
||||
bool doReverse = (userVar0 == 2);
|
||||
seg.setOption(1, doReverse);
|
||||
|
||||
|
@ -89,7 +89,7 @@ void startWipe()
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
WS2812FX::Segment& seg = strip.getSegment(0);
|
||||
Segment& seg = strip.getSegment(0);
|
||||
bool doReverse = (userVar0 == 2);
|
||||
seg.setOption(1, doReverse);
|
||||
|
||||
|
@ -528,12 +528,12 @@ public:
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
strip.setMode(i, effectCurrent);
|
||||
}
|
||||
} else {
|
||||
//WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
//Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
strip.setMode(strip.getMainSegmentId(), effectCurrent);
|
||||
}
|
||||
lampUdated();
|
||||
@ -556,12 +556,12 @@ public:
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
lampUdated();
|
||||
@ -584,12 +584,12 @@ public:
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
lampUdated();
|
||||
@ -618,7 +618,7 @@ public:
|
||||
default: val = strip.getSegment(id).custom1 = max(min((increase ? strip.getSegment(id).custom1+fadeAmount : strip.getSegment(id).custom1-fadeAmount), 255), 0); break;
|
||||
}
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || i == id) continue;
|
||||
switch (par) {
|
||||
case 3: strip.getSegment(i).custom3 = strip.getSegment(id).custom3; break;
|
||||
@ -627,7 +627,7 @@ public:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
switch (par) {
|
||||
case 3: val = seg.custom3 = max(min((increase ? seg.custom3+fadeAmount : seg.custom3-fadeAmount), 255), 0); break;
|
||||
case 2: val = seg.custom2 = max(min((increase ? seg.custom2+fadeAmount : seg.custom2-fadeAmount), 255), 0); break;
|
||||
@ -657,12 +657,12 @@ public:
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.palette = effectPalette;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.palette = effectPalette;
|
||||
}
|
||||
lampUdated();
|
||||
@ -686,12 +686,12 @@ public:
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
lampUdated();
|
||||
@ -715,12 +715,12 @@ public:
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
lampUdated();
|
||||
@ -775,12 +775,12 @@ public:
|
||||
currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0);
|
||||
// if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.setCCT(currentCCT, i);
|
||||
}
|
||||
// } else {
|
||||
// WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
// Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
// seg.setCCT(currentCCT, strip.getMainSegmentId());
|
||||
// }
|
||||
lampUdated();
|
||||
|
@ -27,14 +27,14 @@ saveMacro(1, "&FX=0&R=255&G=255&B=255", false);
|
||||
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
|
||||
//select first two segments (background color + FX settable)
|
||||
WS2812FX::Segment &seg = strip.getSegment(0);
|
||||
Segment &seg = strip.getSegment(0);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
||||
strip.getSegment(0).setOption(0, false);
|
||||
strip.getSegment(0).setOption(2, false);
|
||||
//other segments are text
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
WS2812FX::Segment &seg = strip.getSegment(i);
|
||||
Segment &seg = strip.getSegment(i);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
||||
strip.getSegment(i).setOption(0, true);
|
||||
strip.setBrightness(128);
|
||||
@ -50,7 +50,7 @@ void selectWordSegments(bool state)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
//WS2812FX::Segment &seg = strip.getSegment(i);
|
||||
//Segment &seg = strip.getSegment(i);
|
||||
strip.getSegment(i).setOption(0, state);
|
||||
// strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
//seg.mode = 12;
|
||||
|
2313
wled00/FX.cpp
2313
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
690
wled00/FX.h
690
wled00/FX.h
@ -54,10 +54,15 @@
|
||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||
#endif
|
||||
|
||||
//colors.cpp (.h does not like including other .h)
|
||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16);
|
||||
uint32_t color_add(uint32_t,uint32_t);
|
||||
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
#define FRAMETIME _frametime
|
||||
//#define FRAMETIME _frametime
|
||||
#define FRAMETIME strip.getFrameTime()
|
||||
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
@ -82,11 +87,14 @@
|
||||
#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15)
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT _segments[_segment_index]
|
||||
#define SEGCOLOR(x) _colors_t[x]
|
||||
#define SEGENV _segment_runtimes[_segment_index]
|
||||
#define SEGLEN _virtualSegmentLength
|
||||
#define SEGACT SEGMENT.stop
|
||||
//#define SEGMENT _segments[_segment_index]
|
||||
//#define SEGCOLOR(x) _colors_t[x]
|
||||
//#define SEGENV _segment_runtimes[_segment_index]
|
||||
//#define SEGLEN _virtualSegmentLength
|
||||
#define SEGMENT strip.getSegment(strip.getCurrSegmentId())
|
||||
#define SEGENV strip.getSegmentRuntime(strip.getCurrSegmentId())
|
||||
#define SEGCOLOR(x) strip.segColor(x)
|
||||
#define SEGLEN strip.segLen()
|
||||
#define SPEED_FORMULA_L 5U + (50U*(255U - SEGMENT.speed))/SEGLEN
|
||||
|
||||
// some common colors
|
||||
@ -110,15 +118,15 @@
|
||||
// bit 2: segment is on
|
||||
// bit 1: reverse segment
|
||||
// bit 0: segment is selected
|
||||
#define NO_OPTIONS (uint8_t)0x00
|
||||
#define TRANSPOSED (uint8_t)0x400 // rotated 90deg & reversed
|
||||
#define REVERSE_Y_2D (uint8_t)0x200
|
||||
#define MIRROR_Y_2D (uint8_t)0x100
|
||||
#define TRANSITIONAL (uint8_t)0x080
|
||||
#define MIRROR (uint8_t)0x008
|
||||
#define SEGMENT_ON (uint8_t)0x004
|
||||
#define REVERSE (uint8_t)0x002
|
||||
#define SELECTED (uint8_t)0x001
|
||||
#define NO_OPTIONS (uint16_t)0x0000
|
||||
#define TRANSPOSED (uint16_t)0x0400 // rotated 90deg & reversed
|
||||
#define REVERSE_Y_2D (uint16_t)0x0200
|
||||
#define MIRROR_Y_2D (uint16_t)0x0100
|
||||
#define TRANSITIONAL (uint16_t)0x0080
|
||||
#define MIRROR (uint16_t)0x0008
|
||||
#define SEGMENT_ON (uint16_t)0x0004
|
||||
#define REVERSE (uint16_t)0x0002
|
||||
#define SELECTED (uint16_t)0x0001
|
||||
|
||||
#define FX_MODE_STATIC 0
|
||||
#define FX_MODE_BLINK 1
|
||||
@ -359,249 +367,98 @@
|
||||
#endif
|
||||
|
||||
|
||||
class WS2812FX {
|
||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||
// segment parameters
|
||||
typedef struct Segment { // 35 (36 in memory) bytes
|
||||
uint16_t start; // start index / start X coordinate 2D (left)
|
||||
uint16_t stop; // stop index / stop X coordinate 2D (right); segment is invalid if stop == 0
|
||||
uint16_t offset;
|
||||
uint8_t speed;
|
||||
uint8_t intensity;
|
||||
uint8_t palette;
|
||||
uint8_t mode;
|
||||
uint16_t options; //bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected
|
||||
uint8_t grouping, spacing;
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
uint8_t cct; //0==1900K, 255==10091K
|
||||
uint8_t _capabilities;
|
||||
uint8_t custom1, custom2, custom3; // custom FX parameters
|
||||
uint16_t startY; // start Y coodrinate 2D (top)
|
||||
uint16_t stopY; // stop Y coordinate 2D (bottom)
|
||||
char *name;
|
||||
inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); }
|
||||
inline bool isSelected() { return getOption(0); }
|
||||
inline bool isActive() { return stop > start; }
|
||||
inline uint16_t width() { return stop - start; }
|
||||
inline uint16_t height() { return stopY - startY; }
|
||||
inline uint16_t length() { return width(); }
|
||||
inline uint16_t groupLength() { return grouping + spacing; }
|
||||
inline uint8_t getLightCapabilities() { return _capabilities; }
|
||||
bool setColor(uint8_t slot, uint32_t c, uint8_t segn); //returns true if changed
|
||||
void setCCT(uint16_t k, uint8_t segn);
|
||||
void setOpacity(uint8_t o, uint8_t segn);
|
||||
void setOption(uint8_t n, bool val, uint8_t segn = 255);
|
||||
// 2D matrix
|
||||
uint16_t virtualWidth();
|
||||
uint16_t virtualHeight();
|
||||
// 1D strip
|
||||
uint16_t virtualLength();
|
||||
uint8_t differs(Segment& b);
|
||||
void refreshLightCapabilities();
|
||||
} segment;
|
||||
|
||||
// pre show callback
|
||||
typedef void (*show_callback) (void);
|
||||
|
||||
// segment runtime parameters
|
||||
typedef struct Segment_runtime { // 28 bytes
|
||||
unsigned long next_time; // millis() of next update
|
||||
uint32_t step; // custom "step" var
|
||||
uint32_t call; // call counter
|
||||
uint16_t aux0; // custom var
|
||||
uint16_t aux1; // custom var
|
||||
byte* data = nullptr;
|
||||
|
||||
bool allocateData(uint16_t len);
|
||||
void deallocateData();
|
||||
void resetIfRequired();
|
||||
/**
|
||||
* Flags that before the next effect is calculated,
|
||||
* the internal segment state should be reset.
|
||||
* Call resetIfRequired before calling the next effect function.
|
||||
* Safe to call from interrupts and network requests.
|
||||
*/
|
||||
inline void markForReset() { _requiresReset = true; }
|
||||
private:
|
||||
uint16_t _dataLen = 0;
|
||||
bool _requiresReset = false;
|
||||
} segment_runtime;
|
||||
|
||||
|
||||
// color transitions
|
||||
typedef struct ColorTransition { // 12 bytes
|
||||
uint32_t colorOld = 0;
|
||||
uint32_t transitionStart;
|
||||
uint16_t transitionDur;
|
||||
uint8_t segment = 0xFF; //lower 6 bits: the segment this transition is for (255 indicates transition not in use/available) upper 2 bits: color channel
|
||||
uint8_t briOld = 0;
|
||||
|
||||
static void startTransition(uint8_t oldBri, uint32_t oldCol, uint8_t segn, uint8_t slot);
|
||||
uint8_t currentBri(bool turningOff = false, uint8_t slot = 0);
|
||||
uint16_t progress(bool allowEnd = false); //transition progression between 0-65535
|
||||
uint32_t currentColor(uint32_t colorNew) {
|
||||
return color_blend(colorOld, colorNew, progress(true), true);
|
||||
}
|
||||
} color_transition;
|
||||
|
||||
|
||||
// main "strip" class
|
||||
class WS2812FX {
|
||||
typedef uint16_t (*mode_ptr)(void); // pointer to mode function
|
||||
typedef void (*show_callback)(void); // pre show callback
|
||||
|
||||
static WS2812FX* instance;
|
||||
|
||||
public:
|
||||
|
||||
// segment parameters
|
||||
typedef struct Segment { // 35 (36 in memory) bytes
|
||||
uint16_t start; // start index / start X coordinate 2D (left)
|
||||
uint16_t stop; // stop index / stop X coordinate 2D (right); segment is invalid if stop == 0
|
||||
uint16_t offset;
|
||||
uint8_t speed;
|
||||
uint8_t intensity;
|
||||
uint8_t palette;
|
||||
uint8_t mode;
|
||||
uint16_t options; //bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected
|
||||
uint8_t grouping, spacing;
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
uint8_t cct; //0==1900K, 255==10091K
|
||||
uint8_t _capabilities;
|
||||
uint8_t custom1, custom2, custom3; // custom FX parameters
|
||||
uint16_t startY; // start Y coodrinate 2D (top)
|
||||
uint16_t stopY; // stop Y coordinate 2D (bottom)
|
||||
char *name;
|
||||
inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); }
|
||||
inline bool isSelected() { return getOption(0); }
|
||||
inline bool isActive() { return stop > start; }
|
||||
inline uint16_t width() { return stop - start; }
|
||||
inline uint16_t height() { return stopY - startY; }
|
||||
inline uint16_t length() { return width(); }
|
||||
inline uint16_t groupLength() { return grouping + spacing; }
|
||||
inline uint8_t getLightCapabilities() { return _capabilities; }
|
||||
bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
||||
if (c == colors[slot]) return false;
|
||||
uint8_t b = (slot == 1) ? cct : opacity;
|
||||
ColorTransition::startTransition(b, colors[slot], instance->_transitionDur, segn, slot);
|
||||
colors[slot] = c; return true;
|
||||
}
|
||||
void setCCT(uint16_t k, uint8_t segn) {
|
||||
if (segn >= MAX_NUM_SEGMENTS) return;
|
||||
if (k > 255) { //kelvin value, convert to 0-255
|
||||
if (k < 1900) k = 1900;
|
||||
if (k > 10091) k = 10091;
|
||||
k = (k - 1900) >> 5;
|
||||
}
|
||||
if (cct == k) return;
|
||||
ColorTransition::startTransition(cct, colors[1], instance->_transitionDur, segn, 1);
|
||||
cct = k;
|
||||
}
|
||||
void setOpacity(uint8_t o, uint8_t segn) {
|
||||
if (segn >= MAX_NUM_SEGMENTS) return;
|
||||
if (opacity == o) return;
|
||||
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
|
||||
opacity = o;
|
||||
}
|
||||
void setOption(uint8_t n, bool val, uint8_t segn = 255) {
|
||||
bool prevOn = false;
|
||||
if (n == SEG_OPTION_ON) {
|
||||
prevOn = getOption(SEG_OPTION_ON);
|
||||
if (!val && prevOn) { //fade off
|
||||
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
|
||||
}
|
||||
}
|
||||
if (val) options |= 0x01 << n;
|
||||
else options &= ~(0x01 << n);
|
||||
if (n == SEG_OPTION_ON && val && !prevOn) { //fade on
|
||||
ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0);
|
||||
}
|
||||
}
|
||||
// 2D matrix
|
||||
uint16_t virtualWidth() {
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vWidth = ((getOption(SEG_OPTION_TRANSPOSED) ? height() : width()) + groupLen - 1) / groupLen;
|
||||
if (getOption(SEG_OPTION_MIRROR)) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vWidth;
|
||||
}
|
||||
uint16_t virtualHeight() {
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vHeight = ((getOption(SEG_OPTION_TRANSPOSED) ? width() : height()) + groupLen - 1) / groupLen;
|
||||
if (getOption(SEG_OPTION_MIRROR_Y)) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vHeight;
|
||||
}
|
||||
// 1D strip
|
||||
uint16_t virtualLength() {
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vLength = (length() + groupLen - 1) / groupLen;
|
||||
if (getOption(SEG_OPTION_MIRROR)) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vLength;
|
||||
}
|
||||
uint8_t differs(Segment& b);
|
||||
void refreshLightCapabilities();
|
||||
} segment;
|
||||
|
||||
// segment runtime parameters
|
||||
typedef struct Segment_runtime { // 28 bytes
|
||||
unsigned long next_time; // millis() of next update
|
||||
uint32_t step; // custom "step" var
|
||||
uint32_t call; // call counter
|
||||
uint16_t aux0; // custom var
|
||||
uint16_t aux1; // custom var
|
||||
byte* data = nullptr;
|
||||
bool allocateData(uint16_t len){
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
deallocateData();
|
||||
if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
// if possible use SPI RAM on ESP32
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound())
|
||||
data = (byte*) ps_malloc(len);
|
||||
else
|
||||
#endif
|
||||
data = (byte*) malloc(len);
|
||||
if (!data) return false; //allocation failed
|
||||
WS2812FX::instance->_usedSegmentData += len;
|
||||
_dataLen = len;
|
||||
memset(data, 0, len);
|
||||
return true;
|
||||
}
|
||||
void deallocateData(){
|
||||
free(data);
|
||||
data = nullptr;
|
||||
WS2812FX::instance->_usedSegmentData -= _dataLen;
|
||||
_dataLen = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If reset of this segment was request, clears runtime
|
||||
* settings of this segment.
|
||||
* Must not be called while an effect mode function is running
|
||||
* because it could access the data buffer and this method
|
||||
* may free that data buffer.
|
||||
*/
|
||||
void resetIfRequired() {
|
||||
if (_requiresReset) {
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
deallocateData();
|
||||
_requiresReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags that before the next effect is calculated,
|
||||
* the internal segment state should be reset.
|
||||
* Call resetIfRequired before calling the next effect function.
|
||||
* Safe to call from interrupts and network requests.
|
||||
*/
|
||||
inline void markForReset() { _requiresReset = true; }
|
||||
private:
|
||||
uint16_t _dataLen = 0;
|
||||
bool _requiresReset = false;
|
||||
} segment_runtime;
|
||||
|
||||
typedef struct ColorTransition { // 12 bytes
|
||||
uint32_t colorOld = 0;
|
||||
uint32_t transitionStart;
|
||||
uint16_t transitionDur;
|
||||
uint8_t segment = 0xFF; //lower 6 bits: the segment this transition is for (255 indicates transition not in use/available) upper 2 bits: color channel
|
||||
uint8_t briOld = 0;
|
||||
static void startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot) {
|
||||
if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || dur == 0) return;
|
||||
if (instance->_brightness == 0) return; //do not need transitions if master bri is off
|
||||
if (!instance->_segments[segn].getOption(SEG_OPTION_ON)) return; //not if segment is off either
|
||||
uint8_t tIndex = 0xFF; //none found
|
||||
uint16_t tProgression = 0;
|
||||
uint8_t s = segn + (slot << 6); //merge slot and segment into one byte
|
||||
|
||||
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
|
||||
uint8_t tSeg = instance->transitions[i].segment;
|
||||
//see if this segment + color already has a running transition
|
||||
if (tSeg == s) {
|
||||
tIndex = i; break;
|
||||
}
|
||||
if (tSeg == 0xFF) { //free transition
|
||||
tIndex = i; tProgression = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (tIndex == 0xFF) { //no slot found yet
|
||||
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
|
||||
//find most progressed transition to overwrite
|
||||
uint16_t prog = instance->transitions[i].progress();
|
||||
if (prog > tProgression) {
|
||||
tIndex = i; tProgression = prog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColorTransition& t = instance->transitions[tIndex];
|
||||
if (t.segment == s) //this is an active transition on the same segment+color
|
||||
{
|
||||
bool wasTurningOff = (oldBri == 0);
|
||||
t.briOld = t.currentBri(wasTurningOff, slot);
|
||||
t.colorOld = t.currentColor(oldCol);
|
||||
} else {
|
||||
t.briOld = oldBri;
|
||||
t.colorOld = oldCol;
|
||||
uint8_t prevSeg = t.segment & 0x3F;
|
||||
if (prevSeg < MAX_NUM_SEGMENTS) instance->_segments[prevSeg].setOption(SEG_OPTION_TRANSITIONAL, false);
|
||||
}
|
||||
t.transitionDur = dur;
|
||||
t.transitionStart = millis();
|
||||
t.segment = s;
|
||||
instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||
//refresh immediately, required for Solid mode
|
||||
if (instance->_segment_runtimes[segn].next_time > t.transitionStart + 22) instance->_segment_runtimes[segn].next_time = t.transitionStart;
|
||||
}
|
||||
uint16_t progress(bool allowEnd = false) { //transition progression between 0-65535
|
||||
uint32_t timeNow = millis();
|
||||
if (timeNow - transitionStart > transitionDur) {
|
||||
if (allowEnd) {
|
||||
uint8_t segn = segment & 0x3F;
|
||||
if (segn < MAX_NUM_SEGMENTS) instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, false);
|
||||
segment = 0xFF;
|
||||
}
|
||||
return 0xFFFF;
|
||||
}
|
||||
uint32_t elapsed = timeNow - transitionStart;
|
||||
uint32_t prog = elapsed * 0xFFFF / transitionDur;
|
||||
return (prog > 0xFFFF) ? 0xFFFF : prog;
|
||||
}
|
||||
uint32_t currentColor(uint32_t colorNew) {
|
||||
return instance->color_blend(colorOld, colorNew, progress(true), true);
|
||||
}
|
||||
uint8_t currentBri(bool turningOff = false, uint8_t slot = 0) {
|
||||
uint8_t segn = segment & 0x3F;
|
||||
if (segn >= MAX_NUM_SEGMENTS) return 0;
|
||||
uint8_t briNew = instance->_segments[segn].opacity;
|
||||
if (slot == 0) {
|
||||
if (!instance->_segments[segn].getOption(SEG_OPTION_ON) || turningOff) briNew = 0;
|
||||
} else { //transition slot 1 brightness for CCT transition
|
||||
briNew = instance->_segments[segn].cct;
|
||||
}
|
||||
uint32_t prog = progress() + 1;
|
||||
return ((briNew * prog) + (briOld * (0x10000 - prog))) >> 16;
|
||||
}
|
||||
} color_transition;
|
||||
|
||||
WS2812FX() {
|
||||
WS2812FX::instance = this;
|
||||
setupEffectData();
|
||||
@ -614,6 +471,8 @@ class WS2812FX {
|
||||
resetSegments();
|
||||
}
|
||||
|
||||
static WS2812FX* getInstance(void) { return instance; }
|
||||
|
||||
void
|
||||
finalizeInit(),
|
||||
service(void),
|
||||
@ -627,11 +486,8 @@ class WS2812FX {
|
||||
setCCT(uint16_t k),
|
||||
setBrightness(uint8_t b, bool direct = false),
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
||||
setShowCallback(show_callback cb),
|
||||
setTransition(uint16_t t),
|
||||
setTransitionMode(bool t),
|
||||
calcGammaTable(float),
|
||||
trigger(void),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=0),
|
||||
setMainSegmentId(uint8_t n),
|
||||
restartRuntime(),
|
||||
@ -640,6 +496,7 @@ class WS2812FX {
|
||||
fixInvalidSegments(),
|
||||
setPixelColor(int n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = false),
|
||||
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
|
||||
show(void),
|
||||
setTargetFps(uint8_t fps),
|
||||
deserializeMap(uint8_t n=0);
|
||||
@ -652,6 +509,9 @@ class WS2812FX {
|
||||
inline void setPixelColor(int n, CRGB c) {setPixelColor(n, c.red, c.green, c.blue);}
|
||||
inline void setPixelColor(float i, uint32_t c, bool aa=true) {setPixelColor(i, byte(c>>16), byte(c>>8), byte(c), byte(c>>24), aa);}
|
||||
inline void setPixelColor(float i, CRGB c, bool aa=true) {setPixelColor(i, c.red, c.green, c.blue, 0, aa);}
|
||||
inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
|
||||
inline void setShowCallback(show_callback cb) { _callback = cb; }
|
||||
inline void setTransition(uint16_t t) { _transitionDur = t; }
|
||||
|
||||
bool
|
||||
gammaCorrectBri = false,
|
||||
@ -662,24 +522,28 @@ class WS2812FX {
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void);
|
||||
|
||||
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
|
||||
inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;}
|
||||
|
||||
uint8_t
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
milliampsPerLed = 55,
|
||||
cctBlending = 0,
|
||||
getBrightness(void),
|
||||
getPaletteCount(void),
|
||||
getMaxSegments(void),
|
||||
getActiveSegmentsNum(void),
|
||||
getFirstSelectedSegId(void),
|
||||
getMainSegmentId(void),
|
||||
getLastActiveSegmentId(void),
|
||||
getTargetFps(void),
|
||||
setPixelSegment(uint8_t n),
|
||||
gamma8(uint8_t),
|
||||
gamma8_cal(uint8_t, float),
|
||||
get_random_wheel_index(uint8_t);
|
||||
|
||||
inline uint8_t getBrightness(void) { return _brightness; }
|
||||
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; }
|
||||
inline uint8_t getCurrSegmentId(void) { return _segment_index; }
|
||||
inline uint8_t getMainSegmentId(void) { return _mainSegment; }
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; }
|
||||
inline uint8_t getTargetFps() { return _targetFps; }
|
||||
inline uint8_t getModeCount() { return _modeCount; }
|
||||
inline uint8_t sin_gap(uint16_t in) {
|
||||
if (in & 0x100) return 0;
|
||||
@ -693,165 +557,39 @@ class WS2812FX {
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
triwave16(uint16_t),
|
||||
getLengthTotal(void),
|
||||
getLengthPhysical(void),
|
||||
getFps();
|
||||
|
||||
inline uint16_t getMinShowDelay() { return MIN_SHOW_DELAY; }
|
||||
inline uint16_t getFrameTime(void) { return _frametime; }
|
||||
inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; }
|
||||
inline uint16_t getLengthTotal(void) { return _length; }
|
||||
inline uint16_t segLen(void) { return _virtualSegmentLength; }
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase,
|
||||
color_wheel(uint8_t),
|
||||
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
|
||||
color_blend(uint32_t,uint32_t,uint16_t,bool b16=false),
|
||||
color_add(uint32_t,uint32_t),
|
||||
currentColor(uint32_t colorNew, uint8_t tNr),
|
||||
gamma32(uint32_t),
|
||||
getLastShow(void),
|
||||
getPixelColor(uint16_t);
|
||||
|
||||
inline uint32_t getLastShow(void) { return _lastShow; }
|
||||
inline uint32_t segColor(uint8_t i) { return _colors_t[i]; }
|
||||
|
||||
const char *
|
||||
getModeData(uint8_t id = 0) { return id<_modeCount ? _modeData[id] : nullptr; }
|
||||
|
||||
const char **
|
||||
getModeDataSrc(void) { return _modeData; }
|
||||
|
||||
WS2812FX::Segment
|
||||
&getSegment(uint8_t n),
|
||||
&getFirstSelectedSeg(void),
|
||||
&getMainSegment(void);
|
||||
inline Segment& getSegment(uint8_t id) { return _segments[id >= MAX_NUM_SEGMENTS ? getMainSegmentId() : id]; }
|
||||
inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; }
|
||||
inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; }
|
||||
inline Segment* getSegments(void) { return _segments; }
|
||||
inline Segment_runtime& getSegmentRuntime(uint8_t id) { return _segment_runtimes[id >= MAX_NUM_SEGMENTS ? getMainSegmentId() : id]; }
|
||||
|
||||
WS2812FX::Segment*
|
||||
getSegments(void);
|
||||
|
||||
// builtin modes
|
||||
uint16_t
|
||||
mode_static(void),
|
||||
mode_blink(void),
|
||||
mode_blink_rainbow(void),
|
||||
mode_strobe(void),
|
||||
mode_strobe_rainbow(void),
|
||||
mode_color_wipe(void),
|
||||
mode_color_sweep(void),
|
||||
mode_color_wipe_random(void),
|
||||
mode_color_sweep_random(void),
|
||||
mode_random_color(void),
|
||||
mode_dynamic(void),
|
||||
mode_breath(void),
|
||||
mode_fade(void),
|
||||
mode_scan(void),
|
||||
mode_dual_scan(void),
|
||||
mode_theater_chase(void),
|
||||
mode_theater_chase_rainbow(void),
|
||||
mode_rainbow(void),
|
||||
mode_rainbow_cycle(void),
|
||||
mode_running_lights(void),
|
||||
mode_saw(void),
|
||||
mode_twinkle(void),
|
||||
mode_dissolve(void),
|
||||
mode_dissolve_random(void),
|
||||
mode_sparkle(void),
|
||||
mode_flash_sparkle(void),
|
||||
mode_hyper_sparkle(void),
|
||||
mode_multi_strobe(void),
|
||||
mode_android(void),
|
||||
mode_chase_color(void),
|
||||
mode_chase_random(void),
|
||||
mode_chase_rainbow(void),
|
||||
mode_chase_flash(void),
|
||||
mode_chase_flash_random(void),
|
||||
mode_chase_rainbow_white(void),
|
||||
mode_colorful(void),
|
||||
mode_traffic_light(void),
|
||||
mode_running_color(void),
|
||||
mode_aurora(void),
|
||||
mode_running_random(void),
|
||||
mode_larson_scanner(void),
|
||||
mode_comet(void),
|
||||
mode_fireworks(void),
|
||||
mode_rain(void),
|
||||
mode_tetrix(void),
|
||||
mode_halloween(void),
|
||||
mode_fire_flicker(void),
|
||||
mode_gradient(void),
|
||||
mode_loading(void),
|
||||
mode_police(void),
|
||||
mode_fairy(void),
|
||||
mode_two_dots(void),
|
||||
mode_fairytwinkle(void),
|
||||
mode_running_dual(void),
|
||||
mode_bicolor_chase(void),
|
||||
mode_tricolor_chase(void),
|
||||
mode_tricolor_wipe(void),
|
||||
mode_tricolor_fade(void),
|
||||
mode_lightning(void),
|
||||
mode_icu(void),
|
||||
mode_multi_comet(void),
|
||||
mode_dual_larson_scanner(void),
|
||||
mode_random_chase(void),
|
||||
mode_oscillate(void),
|
||||
mode_fire_2012(void),
|
||||
mode_pride_2015(void),
|
||||
mode_bpm(void),
|
||||
mode_juggle(void),
|
||||
mode_palette(void),
|
||||
mode_colorwaves(void),
|
||||
mode_fillnoise8(void),
|
||||
mode_noise16_1(void),
|
||||
mode_noise16_2(void),
|
||||
mode_noise16_3(void),
|
||||
mode_noise16_4(void),
|
||||
mode_colortwinkle(void),
|
||||
mode_lake(void),
|
||||
mode_meteor(void),
|
||||
mode_meteor_smooth(void),
|
||||
mode_railway(void),
|
||||
mode_ripple(void),
|
||||
mode_twinklefox(void),
|
||||
mode_twinklecat(void),
|
||||
mode_halloween_eyes(void),
|
||||
mode_static_pattern(void),
|
||||
mode_tri_static_pattern(void),
|
||||
mode_spots(void),
|
||||
mode_spots_fade(void),
|
||||
mode_glitter(void),
|
||||
mode_candle(void),
|
||||
mode_starburst(void),
|
||||
mode_exploding_fireworks(void),
|
||||
mode_bouncing_balls(void),
|
||||
mode_sinelon(void),
|
||||
mode_sinelon_dual(void),
|
||||
mode_sinelon_rainbow(void),
|
||||
mode_popcorn(void),
|
||||
mode_drip(void),
|
||||
mode_plasma(void),
|
||||
mode_percent(void),
|
||||
mode_ripple_rainbow(void),
|
||||
mode_heartbeat(void),
|
||||
mode_pacifica(void),
|
||||
mode_candle_multi(void),
|
||||
mode_solid_glitter(void),
|
||||
mode_sunrise(void),
|
||||
mode_phased(void),
|
||||
mode_twinkleup(void),
|
||||
mode_noisepal(void),
|
||||
mode_sinewave(void),
|
||||
mode_phased_noise(void),
|
||||
mode_flow(void),
|
||||
mode_chunchun(void),
|
||||
mode_dancing_shadows(void),
|
||||
mode_washing_machine(void),
|
||||
mode_candy_cane(void),
|
||||
mode_blends(void),
|
||||
mode_tv_simulator(void),
|
||||
mode_dynamic_smooth(void),
|
||||
// non-audio transfered from WLED-SR
|
||||
mode_perlinmove(void),
|
||||
mode_wavesins(void),
|
||||
mode_FlowStripe(void);
|
||||
|
||||
// 2D support (panels)
|
||||
// 2D support (panels)
|
||||
bool
|
||||
isMatrix = false;
|
||||
|
||||
@ -915,119 +653,12 @@ class WS2812FX {
|
||||
uint32_t
|
||||
getPixelColorXY(uint16_t, uint16_t);
|
||||
|
||||
// end 2D support
|
||||
// end 2D support
|
||||
|
||||
// 2D modes
|
||||
uint16_t
|
||||
mode_2Dspaceships(void),
|
||||
mode_2Dcrazybees(void),
|
||||
mode_2Dghostrider(void),
|
||||
mode_2Dfloatingblobs(void),
|
||||
mode_2Dscrollingtext(void),
|
||||
mode_2Ddriftrose(void);
|
||||
|
||||
// WLED-SR modes
|
||||
#ifndef USERMOD_AUDIOREACTIVE
|
||||
uint16_t
|
||||
mode_2Dnoise(void),
|
||||
mode_2Dfirenoise(void),
|
||||
mode_2Dsquaredswirl(void),
|
||||
mode_2Ddna(void),
|
||||
mode_2Dmatrix(void),
|
||||
mode_2Dmetaballs(void),
|
||||
mode_2DPulser(void),
|
||||
mode_2Dgameoflife(void),
|
||||
mode_2Dtartan(void),
|
||||
mode_2DPolarLights(void),
|
||||
mode_2DSwirl(void),
|
||||
mode_2DLissajous(void),
|
||||
mode_2DFrizzles(void),
|
||||
mode_2DPlasmaball(void),
|
||||
mode_2DHiphotic(void),
|
||||
mode_2DSindots(void),
|
||||
mode_2DDNASpiral(void),
|
||||
mode_2DBlackHole(void),
|
||||
mode_2DSunradiation(void),
|
||||
mode_2DWaverly(void),
|
||||
mode_2DDrift(void),
|
||||
mode_2DColoredBursts(void),
|
||||
mode_2DJulia(void),
|
||||
mode_gravimeter(void),
|
||||
mode_gravcenter(void),
|
||||
mode_gravcentric(void),
|
||||
mode_juggles(void),
|
||||
mode_matripix(void),
|
||||
mode_midnoise(void),
|
||||
mode_noisemeter(void),
|
||||
mode_noisefire(void),
|
||||
mode_pixelwave(void),
|
||||
mode_plasmoid(void),
|
||||
mode_puddles(void),
|
||||
mode_puddlepeak(void),
|
||||
mode_ripplepeak(void),
|
||||
mode_2DAkemi(void);
|
||||
#else
|
||||
uint16_t
|
||||
mode_pixels(void),
|
||||
mode_pixelwave(void),
|
||||
mode_juggles(void),
|
||||
mode_matripix(void),
|
||||
mode_gravimeter(void),
|
||||
mode_plasmoid(void),
|
||||
mode_puddles(void),
|
||||
mode_midnoise(void),
|
||||
mode_noisemeter(void),
|
||||
mode_freqwave(void),
|
||||
mode_freqmatrix(void),
|
||||
mode_2DGEQ(void),
|
||||
mode_waterfall(void),
|
||||
mode_freqpixels(void),
|
||||
mode_binmap(void),
|
||||
mode_noisefire(void),
|
||||
mode_puddlepeak(void),
|
||||
mode_noisemove(void),
|
||||
mode_2Dnoise(void),
|
||||
mode_ripplepeak(void),
|
||||
mode_2Dfirenoise(void),
|
||||
mode_2Dsquaredswirl(void),
|
||||
mode_2Ddna(void),
|
||||
mode_2Dmatrix(void),
|
||||
mode_2Dmetaballs(void),
|
||||
mode_freqmap(void),
|
||||
mode_gravcenter(void),
|
||||
mode_gravcentric(void),
|
||||
mode_gravfreq(void),
|
||||
mode_DJLight(void),
|
||||
mode_2DFunkyPlank(void),
|
||||
mode_2DPulser(void),
|
||||
mode_blurz(void),
|
||||
mode_2Dgameoflife(void),
|
||||
mode_2Dtartan(void),
|
||||
mode_2DPolarLights(void),
|
||||
mode_2DSwirl(void),
|
||||
mode_2DLissajous(void),
|
||||
mode_2DFrizzles(void),
|
||||
mode_2DPlasmaball(void),
|
||||
mode_2DHiphotic(void),
|
||||
mode_2DSindots(void),
|
||||
mode_2DDNASpiral(void),
|
||||
mode_2DBlackHole(void),
|
||||
mode_rocktaves(void),
|
||||
mode_2DAkemi(void),
|
||||
mode_2DSunradiation(void),
|
||||
mode_2DWaverly(void),
|
||||
mode_2DDrift(void),
|
||||
mode_2DColoredBursts(void),
|
||||
mode_2DJulia(void),
|
||||
mode_customEffect(void); //WLEDSR Custom Effects
|
||||
#endif
|
||||
|
||||
private:
|
||||
uint32_t crgb_to_col(CRGB fastled);
|
||||
CRGB col_to_crgb(uint32_t);
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
|
||||
private:
|
||||
uint16_t _length, _virtualSegmentLength;
|
||||
uint16_t _rand16seed;
|
||||
uint8_t _brightness;
|
||||
@ -1050,38 +681,6 @@ class WS2812FX {
|
||||
|
||||
show_callback _callback = nullptr;
|
||||
|
||||
// mode helper functions
|
||||
uint16_t
|
||||
blink(uint32_t, uint32_t, bool strobe, bool),
|
||||
candle(bool),
|
||||
color_wipe(bool, bool),
|
||||
dynamic(bool),
|
||||
scan(bool),
|
||||
fireworks_base(CRGB*),
|
||||
running_base(bool,bool),
|
||||
larson_scanner(bool),
|
||||
sinelon_base(bool,bool),
|
||||
dissolve(uint32_t),
|
||||
chase(uint32_t, uint32_t, uint32_t, bool),
|
||||
gradient_base(bool),
|
||||
ripple_base(bool),
|
||||
police_base(uint32_t, uint32_t),
|
||||
running(uint32_t, uint32_t, bool theatre=false),
|
||||
tricolor_chase(uint32_t, uint32_t),
|
||||
twinklefox_base(bool),
|
||||
spots_base(uint16_t),
|
||||
phased_base(uint8_t);
|
||||
|
||||
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
|
||||
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
|
||||
|
||||
void
|
||||
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
|
||||
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot),
|
||||
estimateCurrentAndLimitBri(void),
|
||||
load_gradient_palette(uint8_t),
|
||||
handle_palette(void);
|
||||
|
||||
uint16_t* customMappingTable = nullptr;
|
||||
uint16_t customMappingSize = 0;
|
||||
|
||||
@ -1100,18 +699,21 @@ class WS2812FX {
|
||||
// start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities, custom 1, custom 2, custom 3
|
||||
{0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0, DEFAULT_C1, DEFAULT_C2, DEFAULT_C3, 0, 1}
|
||||
};
|
||||
friend class Segment;
|
||||
|
||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
||||
friend class Segment_runtime;
|
||||
|
||||
ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element
|
||||
friend class ColorTransition;
|
||||
|
||||
void
|
||||
estimateCurrentAndLimitBri(void),
|
||||
load_gradient_palette(uint8_t),
|
||||
handle_palette(void);
|
||||
|
||||
uint16_t
|
||||
transitionProgress(uint8_t tNr);
|
||||
|
||||
public:
|
||||
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
|
||||
inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;}
|
||||
};
|
||||
|
||||
extern const char JSON_mode_names[];
|
||||
|
@ -110,15 +110,6 @@ void WS2812FX::setUpMatrix() {
|
||||
uint16_t IRAM_ATTR WS2812FX::XY(uint16_t x, uint16_t y) {
|
||||
uint16_t width = SEGMENT.virtualWidth(); // segment width in logical pixels
|
||||
uint16_t height = SEGMENT.virtualHeight(); // segment height in logical pixels
|
||||
/*
|
||||
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) {
|
||||
uint16_t t;
|
||||
// swap X & Y if segment transposed
|
||||
t = x; x = y; y = t;
|
||||
// swap width & height if segment transposed
|
||||
t = width; width = height; height = t;
|
||||
}
|
||||
*/
|
||||
return (x%width) + (y%height) * width;
|
||||
}
|
||||
|
||||
@ -294,13 +285,13 @@ void WS2812FX::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint16_t x = 0; x < cols; x++) {
|
||||
CRGB cur = leds ? leds[XY(x,row)] : col_to_crgb(getPixelColorXY(x, row));
|
||||
CRGB cur = leds ? leds[XY(x,row)] : CRGB(getPixelColorXY(x, row));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (x) {
|
||||
CRGB prev = (leds ? leds[XY(x-1,row)] : col_to_crgb(getPixelColorXY(x-1, row))) + part;
|
||||
CRGB prev = (leds ? leds[XY(x-1,row)] : CRGB(getPixelColorXY(x-1, row))) + part;
|
||||
if (leds) leds[XY(x-1,row)] = prev;
|
||||
else setPixelColorXY(x-1, row, prev);
|
||||
}
|
||||
@ -321,13 +312,13 @@ void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint16_t i = 0; i < rows; i++) {
|
||||
CRGB cur = leds ? leds[XY(col,i)] : col_to_crgb(getPixelColorXY(col, i));
|
||||
CRGB cur = leds ? leds[XY(col,i)] : CRGB(getPixelColorXY(col, i));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if (i) {
|
||||
CRGB prev = (leds ? leds[XY(col,i-1)] : col_to_crgb(getPixelColorXY(col, i-1))) + part;
|
||||
CRGB prev = (leds ? leds[XY(col,i-1)] : CRGB(getPixelColorXY(col, i-1))) + part;
|
||||
if (leds) leds[XY(col,i-1)] = prev;
|
||||
else setPixelColorXY(col, i-1, prev);
|
||||
}
|
||||
@ -374,9 +365,9 @@ void WS2812FX::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds)
|
||||
uint16_t yp = vertical ? y-1 : y;
|
||||
uint16_t xn = vertical ? x : x+1;
|
||||
uint16_t yn = vertical ? y+1 : y;
|
||||
CRGB curr = leds ? leds[XY(x,y)] : col_to_crgb(getPixelColorXY(x,y));
|
||||
CRGB prev = (xp<0 || yp<0) ? CRGB::Black : (leds ? leds[XY(xp,yp)] : col_to_crgb(getPixelColorXY(xp,yp)));
|
||||
CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : (leds ? leds[XY(xn,yn)] : col_to_crgb(getPixelColorXY(xn,yn)));
|
||||
CRGB curr = leds ? leds[XY(x,y)] : CRGB(getPixelColorXY(x,y));
|
||||
CRGB prev = (xp<0 || yp<0) ? CRGB::Black : (leds ? leds[XY(xp,yp)] : CRGB(getPixelColorXY(xp,yp)));
|
||||
CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : (leds ? leds[XY(xn,yn)] : CRGB(getPixelColorXY(xn,yn)));
|
||||
uint16_t r, g, b;
|
||||
r = (curr.r*keep + (prev.r + next.r)*seep) / 3;
|
||||
g = (curr.g*keep + (prev.g + next.g)*seep) / 3;
|
||||
@ -491,7 +482,7 @@ void WS2812FX::nscale8(CRGB* leds, uint8_t scale) {
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
if (leds) leds[XY(x,y)].nscale8(scale);
|
||||
else setPixelColorXY(x, y, col_to_crgb(getPixelColorXY(x, y)).nscale8(scale));
|
||||
else setPixelColorXY(x, y, CRGB(getPixelColorXY(x, y)).nscale8(scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,253 @@
|
||||
#error "Max segments must be at least max number of busses!"
|
||||
#endif
|
||||
|
||||
|
||||
bool Segment::setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
||||
if (c == colors[slot]) return false;
|
||||
uint8_t b = (slot == 1) ? cct : opacity;
|
||||
ColorTransition::startTransition(b, colors[slot], segn, slot);
|
||||
colors[slot] = c; return true;
|
||||
}
|
||||
|
||||
void Segment::setCCT(uint16_t k, uint8_t segn) {
|
||||
if (segn >= MAX_NUM_SEGMENTS) return;
|
||||
if (k > 255) { //kelvin value, convert to 0-255
|
||||
if (k < 1900) k = 1900;
|
||||
if (k > 10091) k = 10091;
|
||||
k = (k - 1900) >> 5;
|
||||
}
|
||||
if (cct == k) return;
|
||||
ColorTransition::startTransition(cct, colors[1], segn, 1);
|
||||
cct = k;
|
||||
}
|
||||
|
||||
void Segment::setOpacity(uint8_t o, uint8_t segn) {
|
||||
if (segn >= MAX_NUM_SEGMENTS) return;
|
||||
if (opacity == o) return;
|
||||
ColorTransition::startTransition(opacity, colors[0], segn, 0);
|
||||
opacity = o;
|
||||
}
|
||||
|
||||
void Segment::setOption(uint8_t n, bool val, uint8_t segn) {
|
||||
bool prevOn = false;
|
||||
if (n == SEG_OPTION_ON) {
|
||||
prevOn = getOption(SEG_OPTION_ON);
|
||||
if (!val && prevOn) { //fade off
|
||||
ColorTransition::startTransition(opacity, colors[0], segn, 0);
|
||||
}
|
||||
}
|
||||
if (val) options |= 0x01 << n;
|
||||
else options &= ~(0x01 << n);
|
||||
if (n == SEG_OPTION_ON && val && !prevOn) { //fade on
|
||||
ColorTransition::startTransition(0, colors[0], segn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// 2D matrix
|
||||
uint16_t Segment::virtualWidth() {
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vWidth = ((getOption(SEG_OPTION_TRANSPOSED) ? height() : width()) + groupLen - 1) / groupLen;
|
||||
if (getOption(SEG_OPTION_MIRROR)) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vWidth;
|
||||
}
|
||||
|
||||
uint16_t Segment::virtualHeight() {
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vHeight = ((getOption(SEG_OPTION_TRANSPOSED) ? width() : height()) + groupLen - 1) / groupLen;
|
||||
if (getOption(SEG_OPTION_MIRROR_Y)) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vHeight;
|
||||
}
|
||||
|
||||
// 1D strip
|
||||
uint16_t Segment::virtualLength() {
|
||||
uint16_t groupLen = groupLength();
|
||||
uint16_t vLength = (length() + groupLen - 1) / groupLen;
|
||||
if (getOption(SEG_OPTION_MIRROR)) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vLength;
|
||||
}
|
||||
|
||||
uint8_t Segment::differs(Segment& b) {
|
||||
uint8_t d = 0;
|
||||
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (offset != b.offset) d |= SEG_DIFFERS_GSO;
|
||||
if (grouping != b.grouping) d |= SEG_DIFFERS_GSO;
|
||||
if (spacing != b.spacing) d |= SEG_DIFFERS_GSO;
|
||||
if (opacity != b.opacity) d |= SEG_DIFFERS_BRI;
|
||||
if (mode != b.mode) d |= SEG_DIFFERS_FX;
|
||||
if (speed != b.speed) d |= SEG_DIFFERS_FX;
|
||||
if (intensity != b.intensity) d |= SEG_DIFFERS_FX;
|
||||
if (palette != b.palette) d |= SEG_DIFFERS_FX;
|
||||
if (custom1 != b.custom1) d |= SEG_DIFFERS_FX;
|
||||
if (custom2 != b.custom2) d |= SEG_DIFFERS_FX;
|
||||
if (custom3 != b.custom3) d |= SEG_DIFFERS_FX;
|
||||
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
|
||||
|
||||
//bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected
|
||||
if ((options & 0b11100101110) != (b.options & 0b11100101110)) d |= SEG_DIFFERS_OPT;
|
||||
if ((options & 0x01) != (b.options & 0x01)) d |= SEG_DIFFERS_SEL;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void Segment::refreshLightCapabilities() {
|
||||
if (!isActive()) {
|
||||
_capabilities = 0; return;
|
||||
}
|
||||
uint8_t capabilities = 0;
|
||||
|
||||
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
if (!bus->isOk()) continue;
|
||||
if (bus->getStart() >= stop) continue;
|
||||
if (bus->getStart() + bus->getLength() <= start) continue;
|
||||
|
||||
uint8_t type = bus->getType();
|
||||
if (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH)) capabilities |= 0x01; // segment supports RGB (full color)
|
||||
if (bus->isRgbw()) capabilities |= 0x02; // segment supports white channel
|
||||
if (!cctFromRgb) {
|
||||
switch (type) {
|
||||
case TYPE_ANALOG_5CH:
|
||||
case TYPE_ANALOG_2CH:
|
||||
capabilities |= 0x04; //segment supports white CCT
|
||||
}
|
||||
}
|
||||
if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider)
|
||||
uint8_t aWM = Bus::getAutoWhiteMode()<255 ? Bus::getAutoWhiteMode() : bus->getAWMode();
|
||||
bool whiteSlider = (aWM == RGBW_MODE_DUAL || aWM == RGBW_MODE_MANUAL_ONLY); // white slider allowed
|
||||
if (bus->isRgbw() && (whiteSlider || !(capabilities & 0x01))) capabilities |= 0x08; // allow white channel adjustments (AWM allows or is not RGB)
|
||||
}
|
||||
_capabilities = capabilities;
|
||||
}
|
||||
|
||||
|
||||
bool Segment_runtime::allocateData(uint16_t len){
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
WS2812FX *instance = WS2812FX::getInstance();
|
||||
deallocateData();
|
||||
if (instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
// if possible use SPI RAM on ESP32
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound())
|
||||
data = (byte*) ps_malloc(len);
|
||||
else
|
||||
#endif
|
||||
data = (byte*) malloc(len);
|
||||
if (!data) return false; //allocation failed
|
||||
instance->_usedSegmentData += len;
|
||||
_dataLen = len;
|
||||
memset(data, 0, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Segment_runtime::deallocateData(){
|
||||
free(data);
|
||||
data = nullptr;
|
||||
WS2812FX::getInstance()->_usedSegmentData -= _dataLen;
|
||||
_dataLen = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If reset of this segment was request, clears runtime
|
||||
* settings of this segment.
|
||||
* Must not be called while an effect mode function is running
|
||||
* because it could access the data buffer and this method
|
||||
* may free that data buffer.
|
||||
*/
|
||||
void Segment_runtime::resetIfRequired() {
|
||||
if (_requiresReset) {
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
deallocateData();
|
||||
_requiresReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ColorTransition::startTransition(uint8_t oldBri, uint32_t oldCol, uint8_t segn, uint8_t slot) {
|
||||
WS2812FX *instance = WS2812FX::getInstance();
|
||||
if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || instance->_transitionDur == 0) return;
|
||||
if (instance->_brightness == 0) return; //do not need transitions if master bri is off
|
||||
if (!instance->_segments[segn].getOption(SEG_OPTION_ON)) return; //not if segment is off either
|
||||
uint8_t tIndex = 0xFF; //none found
|
||||
uint16_t tProgression = 0;
|
||||
uint8_t s = segn + (slot << 6); //merge slot and segment into one byte
|
||||
|
||||
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
|
||||
uint8_t tSeg = instance->transitions[i].segment;
|
||||
//see if this segment + color already has a running transition
|
||||
if (tSeg == s) {
|
||||
tIndex = i; break;
|
||||
}
|
||||
if (tSeg == 0xFF) { //free transition
|
||||
tIndex = i; tProgression = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (tIndex == 0xFF) { //no slot found yet
|
||||
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
|
||||
//find most progressed transition to overwrite
|
||||
uint16_t prog = instance->transitions[i].progress();
|
||||
if (prog > tProgression) {
|
||||
tIndex = i; tProgression = prog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColorTransition& t = instance->transitions[tIndex];
|
||||
if (t.segment == s) //this is an active transition on the same segment+color
|
||||
{
|
||||
bool wasTurningOff = (oldBri == 0);
|
||||
t.briOld = t.currentBri(wasTurningOff, slot);
|
||||
t.colorOld = t.currentColor(oldCol);
|
||||
} else {
|
||||
t.briOld = oldBri;
|
||||
t.colorOld = oldCol;
|
||||
uint8_t prevSeg = t.segment & 0x3F;
|
||||
if (prevSeg < MAX_NUM_SEGMENTS) instance->_segments[prevSeg].setOption(SEG_OPTION_TRANSITIONAL, false);
|
||||
}
|
||||
t.transitionDur = instance->_transitionDur;
|
||||
t.transitionStart = millis();
|
||||
t.segment = s;
|
||||
instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||
//refresh immediately, required for Solid mode
|
||||
if (instance->_segment_runtimes[segn].next_time > t.transitionStart + 22) instance->_segment_runtimes[segn].next_time = t.transitionStart;
|
||||
}
|
||||
|
||||
uint16_t ColorTransition::progress(bool allowEnd) { //transition progression between 0-65535
|
||||
WS2812FX *instance = WS2812FX::getInstance();
|
||||
uint32_t timeNow = millis();
|
||||
if (timeNow - transitionStart > transitionDur) {
|
||||
if (allowEnd) {
|
||||
uint8_t segn = segment & 0x3F;
|
||||
if (segn < MAX_NUM_SEGMENTS) instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, false);
|
||||
segment = 0xFF;
|
||||
}
|
||||
return 0xFFFF;
|
||||
}
|
||||
uint32_t elapsed = timeNow - transitionStart;
|
||||
uint32_t prog = elapsed * 0xFFFF / transitionDur;
|
||||
return (prog > 0xFFFF) ? 0xFFFF : prog;
|
||||
}
|
||||
|
||||
uint8_t ColorTransition::currentBri(bool turningOff, uint8_t slot) {
|
||||
WS2812FX *instance = WS2812FX::getInstance();
|
||||
uint8_t segn = segment & 0x3F;
|
||||
if (segn >= MAX_NUM_SEGMENTS) return 0;
|
||||
uint8_t briNew = instance->_segments[segn].opacity;
|
||||
if (slot == 0) {
|
||||
if (!instance->_segments[segn].getOption(SEG_OPTION_ON) || turningOff) briNew = 0;
|
||||
} else { //transition slot 1 brightness for CCT transition
|
||||
briNew = instance->_segments[segn].cct;
|
||||
}
|
||||
uint32_t prog = progress() + 1;
|
||||
return ((briNew * prog) + (briOld * (0x10000 - prog))) >> 16;
|
||||
}
|
||||
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit(void)
|
||||
{
|
||||
@ -149,8 +396,11 @@ void WS2812FX::service() {
|
||||
uint16_t delay = FRAMETIME;
|
||||
|
||||
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
|
||||
SEGLEN = SEGMENT.virtualLength();
|
||||
_bri_t = SEGMENT.opacity; _colors_t[0] = SEGMENT.colors[0]; _colors_t[1] = SEGMENT.colors[1]; _colors_t[2] = SEGMENT.colors[2];
|
||||
_virtualSegmentLength = SEGMENT.virtualLength();
|
||||
_bri_t = SEGMENT.opacity;
|
||||
_colors_t[0] = SEGMENT.colors[0];
|
||||
_colors_t[1] = SEGMENT.colors[1];
|
||||
_colors_t[2] = SEGMENT.colors[2];
|
||||
uint8_t _cct_t = SEGMENT.cct;
|
||||
if (!SEGMENT.getOption(SEG_OPTION_ON)) _bri_t = 0;
|
||||
for (uint8_t t = 0; t < MAX_NUM_TRANSITIONS; t++) {
|
||||
@ -166,14 +416,14 @@ void WS2812FX::service() {
|
||||
}
|
||||
handle_palette();
|
||||
|
||||
delay = (this->*_mode[SEGMENT.mode])(); // effect function (NOTE: may add SEGMENT and SEGENV to parameters)
|
||||
delay = (*_mode[SEGMENT.mode])();
|
||||
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
|
||||
}
|
||||
|
||||
SEGENV.next_time = nowUp + delay;
|
||||
}
|
||||
}
|
||||
SEGLEN = 0;
|
||||
_virtualSegmentLength = 0;
|
||||
busses.setSegmentCCT(-1);
|
||||
if(doShow) {
|
||||
yield();
|
||||
@ -187,7 +437,7 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColor(float i, byte r, byte g, byte b, byte
|
||||
{
|
||||
if (i<0.0f || i>1.0f) return; // not normalized
|
||||
|
||||
float fC = i * (SEGLEN-1);
|
||||
float fC = i * (_virtualSegmentLength-1);
|
||||
if (aa) {
|
||||
uint16_t iL = roundf(fC-0.49f);
|
||||
uint16_t iR = roundf(fC+0.49f);
|
||||
@ -213,8 +463,8 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColor(float i, byte r, byte g, byte b, byte
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(int i, byte r, byte g, byte b, byte w)
|
||||
{
|
||||
uint8_t segIdx = SEGLEN ? _segment_index : _mainSegment;
|
||||
if (isMatrix && SEGLEN) {
|
||||
uint8_t segIdx = _virtualSegmentLength ? _segment_index : _mainSegment;
|
||||
if (isMatrix && _virtualSegmentLength) {
|
||||
// map linear pixel into 2D segment area (even for 1D segments, expanding vertically)
|
||||
uint16_t h = _segments[segIdx].virtualHeight(); // segment height in logical pixels
|
||||
for (uint16_t y = 0; y < h; y++) { // expand 1D effect vertically
|
||||
@ -223,9 +473,9 @@ void IRAM_ATTR WS2812FX::setPixelColor(int i, byte r, byte g, byte b, byte w)
|
||||
return;
|
||||
}
|
||||
|
||||
if (SEGLEN || (realtimeMode && useMainSegmentOnly)) {
|
||||
if (_virtualSegmentLength || (realtimeMode && useMainSegmentOnly)) {
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (SEGLEN && _bri_t < 255) { // SEGLEN!=0 -> from segment/FX
|
||||
if (_virtualSegmentLength && _bri_t < 255) { // _virtualSegmentLength!=0 -> from segment/FX
|
||||
r = scale8(r, _bri_t);
|
||||
g = scale8(g, _bri_t);
|
||||
b = scale8(b, _bri_t);
|
||||
@ -392,22 +642,11 @@ uint16_t WS2812FX::getFps() {
|
||||
return _cumulativeFps +1;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getTargetFps() {
|
||||
return _targetFps;
|
||||
}
|
||||
|
||||
void WS2812FX::setTargetFps(uint8_t fps) {
|
||||
if (fps > 0 && fps <= 120) _targetFps = fps;
|
||||
_frametime = 1000 / _targetFps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the next frame to be computed on all active segments.
|
||||
*/
|
||||
void WS2812FX::trigger() {
|
||||
_triggered = true;
|
||||
}
|
||||
|
||||
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
if (segid >= MAX_NUM_SEGMENTS) return;
|
||||
|
||||
@ -420,11 +659,6 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getPaletteCount()
|
||||
{
|
||||
return 13 + GRADIENT_PALETTE_COUNT;
|
||||
}
|
||||
|
||||
//applies to all active and selected segments
|
||||
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
|
||||
if (slot >= NUM_COLORS) return;
|
||||
@ -465,14 +699,6 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getBrightness(void) {
|
||||
return _brightness;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getMaxSegments(void) {
|
||||
return MAX_NUM_SEGMENTS;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getFirstSelectedSegId(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
@ -499,10 +725,6 @@ void WS2812FX::setMainSegmentId(uint8_t n) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getMainSegmentId(void) {
|
||||
return _mainSegment;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getLastActiveSegmentId(void) {
|
||||
for (uint8_t i = MAX_NUM_SEGMENTS -1; i > 0; i--) {
|
||||
if (_segments[i].isActive()) return i;
|
||||
@ -532,7 +754,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
//}
|
||||
i += SEGMENT.start;
|
||||
|
||||
if (SEGLEN) {
|
||||
if (_virtualSegmentLength) {
|
||||
/* offset/phase */
|
||||
i += SEGMENT.offset;
|
||||
if (i >= SEGMENT.stop) i -= SEGMENT.length();
|
||||
@ -544,31 +766,6 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
if (id >= MAX_NUM_SEGMENTS) return _segments[getMainSegmentId()];
|
||||
return _segments[id];
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getFirstSelectedSeg(void) {
|
||||
return _segments[getFirstSelectedSegId()];
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getMainSegment(void) {
|
||||
return _segments[getMainSegmentId()];
|
||||
}
|
||||
|
||||
WS2812FX::Segment* WS2812FX::getSegments(void) {
|
||||
return _segments;
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getLastShow(void) {
|
||||
return _lastShow;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthTotal(void) {
|
||||
return _length;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
uint16_t len = 0;
|
||||
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
@ -579,64 +776,6 @@ uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::Segment::differs(Segment& b) {
|
||||
uint8_t d = 0;
|
||||
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (offset != b.offset) d |= SEG_DIFFERS_GSO;
|
||||
if (grouping != b.grouping) d |= SEG_DIFFERS_GSO;
|
||||
if (spacing != b.spacing) d |= SEG_DIFFERS_GSO;
|
||||
if (opacity != b.opacity) d |= SEG_DIFFERS_BRI;
|
||||
if (mode != b.mode) d |= SEG_DIFFERS_FX;
|
||||
if (speed != b.speed) d |= SEG_DIFFERS_FX;
|
||||
if (intensity != b.intensity) d |= SEG_DIFFERS_FX;
|
||||
if (palette != b.palette) d |= SEG_DIFFERS_FX;
|
||||
if (custom1 != b.custom1) d |= SEG_DIFFERS_FX;
|
||||
if (custom2 != b.custom2) d |= SEG_DIFFERS_FX;
|
||||
if (custom3 != b.custom3) d |= SEG_DIFFERS_FX;
|
||||
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
|
||||
|
||||
//bit pattern: msb first: [transposed mirrorY reverseY] transitional (tbd) paused needspixelstate mirrored on reverse selected
|
||||
if ((options & 0b11100101110) != (b.options & 0b11100101110)) d |= SEG_DIFFERS_OPT;
|
||||
if ((options & 0x01) != (b.options & 0x01)) d |= SEG_DIFFERS_SEL;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void WS2812FX::Segment::refreshLightCapabilities() {
|
||||
if (!isActive()) {
|
||||
_capabilities = 0; return;
|
||||
}
|
||||
uint8_t capabilities = 0;
|
||||
|
||||
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
if (!bus->isOk()) continue;
|
||||
if (bus->getStart() >= stop) continue;
|
||||
if (bus->getStart() + bus->getLength() <= start) continue;
|
||||
|
||||
uint8_t type = bus->getType();
|
||||
if (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH)) capabilities |= 0x01; // segment supports RGB (full color)
|
||||
if (bus->isRgbw()) capabilities |= 0x02; // segment supports white channel
|
||||
if (!cctFromRgb) {
|
||||
switch (type) {
|
||||
case TYPE_ANALOG_5CH:
|
||||
case TYPE_ANALOG_2CH:
|
||||
capabilities |= 0x04; //segment supports white CCT
|
||||
}
|
||||
}
|
||||
if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider)
|
||||
uint8_t aWM = Bus::getAutoWhiteMode()<255 ? Bus::getAutoWhiteMode() : bus->getAWMode();
|
||||
bool whiteSlider = (aWM == RGBW_MODE_DUAL || aWM == RGBW_MODE_MANUAL_ONLY); // white slider allowed
|
||||
if (bus->isRgbw() && (whiteSlider || !(capabilities & 0x01))) capabilities |= 0x08; // allow white channel adjustments (AWM allows or is not RGB)
|
||||
}
|
||||
_capabilities = capabilities;
|
||||
}
|
||||
|
||||
//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw.
|
||||
//returns if there is an RGBW bus (supports RGB and White, not only white)
|
||||
//not influenced by auto-white mode, also true if white slider does not affect output white channel
|
||||
@ -847,7 +986,7 @@ uint8_t WS2812FX::setPixelSegment(uint8_t n)
|
||||
uint8_t prevSegId = _segment_index;
|
||||
if (n < MAX_NUM_SEGMENTS) {
|
||||
_segment_index = n;
|
||||
SEGLEN = SEGMENT.virtualLength();
|
||||
_virtualSegmentLength = SEGMENT.virtualLength();
|
||||
}
|
||||
return prevSegId;
|
||||
}
|
||||
@ -863,16 +1002,6 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setShowCallback(show_callback cb)
|
||||
{
|
||||
_callback = cb;
|
||||
}
|
||||
|
||||
void WS2812FX::setTransition(uint16_t t)
|
||||
{
|
||||
_transitionDur = t;
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t)
|
||||
{
|
||||
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
|
||||
@ -885,51 +1014,6 @@ void WS2812FX::setTransitionMode(bool t)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t IRAM_ATTR WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
if(blend == 0) return color1;
|
||||
uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
if(blend == blendmax) return color2;
|
||||
uint8_t shift = b16 ? 16 : 8;
|
||||
|
||||
uint32_t w1 = W(color1);
|
||||
uint32_t r1 = R(color1);
|
||||
uint32_t g1 = G(color1);
|
||||
uint32_t b1 = B(color1);
|
||||
|
||||
uint32_t w2 = W(color2);
|
||||
uint32_t r2 = R(color2);
|
||||
uint32_t g2 = G(color2);
|
||||
uint32_t b2 = B(color2);
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
|
||||
|
||||
return RGBW32(r3, g3, b3, w3);
|
||||
}
|
||||
|
||||
/*
|
||||
* color add function that preserves ratio
|
||||
* idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
||||
*/
|
||||
uint32_t WS2812FX::color_add(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
uint32_t r = R(c1) + R(c2);
|
||||
uint32_t g = G(c1) + G(c2);
|
||||
uint32_t b = B(c1) + B(c2);
|
||||
uint32_t w = W(c1) + W(c2);
|
||||
uint16_t max = r;
|
||||
if (g > max) max = g;
|
||||
if (b > max) max = b;
|
||||
if (w > max) max = w;
|
||||
if (max < 256) return RGBW32(r, g, b, w);
|
||||
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills segment with color
|
||||
*/
|
||||
@ -998,8 +1082,8 @@ void WS2812FX::fadeToBlackBy(uint8_t fadeBy) {
|
||||
const uint16_t rows = SEGMENT.virtualHeight(); // will be 1 for 1D
|
||||
|
||||
for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
if (isMatrix) setPixelColorXY(x, y, col_to_crgb(getPixelColorXY(x,y)).nscale8(255-fadeBy));
|
||||
else setPixelColor(x, col_to_crgb(getPixelColor(x)).nscale8(255-fadeBy));
|
||||
if (isMatrix) setPixelColorXY(x, y, CRGB(getPixelColorXY(x,y)).nscale8(255-fadeBy));
|
||||
else setPixelColor(x, CRGB(getPixelColor(x)).nscale8(255-fadeBy));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1019,9 +1103,9 @@ void WS2812FX::blur(uint8_t blur_amount)
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for(uint16_t i = 0; i < SEGLEN; i++)
|
||||
for(uint16_t i = 0; i < _virtualSegmentLength; i++)
|
||||
{
|
||||
CRGB cur = col_to_crgb(getPixelColor(i));
|
||||
CRGB cur = CRGB(getPixelColor(i));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
@ -1038,7 +1122,7 @@ void WS2812FX::blur(uint8_t blur_amount)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR WS2812FX::triwave16(uint16_t in)
|
||||
uint16_t WS2812FX::triwave16(uint16_t in)
|
||||
{
|
||||
if (in < 0x8000) return in *2;
|
||||
return 0xFFFF - (in - 0x8000)*2;
|
||||
@ -1105,22 +1189,6 @@ uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
|
||||
}
|
||||
|
||||
|
||||
uint32_t IRAM_ATTR WS2812FX::crgb_to_col(CRGB fastled)
|
||||
{
|
||||
return RGBW32(fastled.red, fastled.green, fastled.blue, 0);
|
||||
}
|
||||
|
||||
|
||||
CRGB IRAM_ATTR WS2812FX::col_to_crgb(uint32_t color)
|
||||
{
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = R(color);
|
||||
fastled_col.green = G(color);
|
||||
fastled_col.blue = B(color);
|
||||
return fastled_col;
|
||||
}
|
||||
|
||||
|
||||
void WS2812FX::load_gradient_palette(uint8_t index)
|
||||
{
|
||||
byte i = constrain(index, 0, GRADIENT_PALETTE_COUNT -1);
|
||||
@ -1176,22 +1244,22 @@ void WS2812FX::handle_palette(void)
|
||||
_lastPaletteChange = millis();
|
||||
} break;}
|
||||
case 2: {//primary color only
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB prim = CRGB(SEGCOLOR(0));
|
||||
targetPalette = CRGBPalette16(prim); break;}
|
||||
case 3: {//primary + secondary
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
CRGB prim = CRGB(SEGCOLOR(0));
|
||||
CRGB sec = CRGB(SEGCOLOR(1));
|
||||
targetPalette = CRGBPalette16(prim,prim,sec,sec); break;}
|
||||
case 4: {//primary + secondary + tertiary
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
CRGB ter = col_to_crgb(SEGCOLOR(2));
|
||||
CRGB prim = CRGB(SEGCOLOR(0));
|
||||
CRGB sec = CRGB(SEGCOLOR(1));
|
||||
CRGB ter = CRGB(SEGCOLOR(2));
|
||||
targetPalette = CRGBPalette16(ter,sec,prim); break;}
|
||||
case 5: {//primary + secondary (+tert if not off), more distinct
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
CRGB prim = CRGB(SEGCOLOR(0));
|
||||
CRGB sec = CRGB(SEGCOLOR(1));
|
||||
if (SEGCOLOR(2)) {
|
||||
CRGB ter = col_to_crgb(SEGCOLOR(2));
|
||||
CRGB ter = CRGB(SEGCOLOR(2));
|
||||
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,ter,ter,ter,ter,ter,prim);
|
||||
} else {
|
||||
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec);
|
||||
@ -1227,7 +1295,7 @@ void WS2812FX::handle_palette(void)
|
||||
|
||||
/*
|
||||
* Gets a single color from the currently selected palette.
|
||||
* @param i Palette Index (if mapping is true, the full palette will be SEGLEN long, if false, 255). Will wrap around automatically.
|
||||
* @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically.
|
||||
* @param mapping if true, LED position in segment is considered for color
|
||||
* @param wrap FastLED palettes will usally wrap back to the start smoothly. Set false to get a hard edge
|
||||
* @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead
|
||||
@ -1243,12 +1311,12 @@ uint32_t IRAM_ATTR WS2812FX::color_from_palette(uint16_t i, bool mapping, bool w
|
||||
}
|
||||
|
||||
uint8_t paletteIndex = i;
|
||||
if (mapping && SEGLEN > 1) paletteIndex = (i*255)/(SEGLEN -1);
|
||||
if (mapping && _virtualSegmentLength > 1) paletteIndex = (i*255)/(_virtualSegmentLength -1);
|
||||
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col;
|
||||
fastled_col = ColorFromPalette(currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
|
||||
|
||||
return crgb_to_col(fastled_col);
|
||||
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -1302,7 +1370,7 @@ void WS2812FX::deserializeMap(uint8_t n) {
|
||||
}
|
||||
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
byte gammaT[] = {
|
||||
static byte gammaT[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
@ -1321,7 +1389,7 @@ byte gammaT[] = {
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
uint8_t WS2812FX::gamma8_cal(uint8_t b, float gamma) {
|
||||
return (int)(pow((float)b / 255.0, gamma) * 255 + 0.5);
|
||||
return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
}
|
||||
|
||||
void WS2812FX::calcGammaTable(float gamma)
|
||||
|
@ -195,7 +195,7 @@ void handleAnalog(uint8_t b)
|
||||
colorHStoRGB(aRead*256,255,col);
|
||||
} else {
|
||||
// otherwise use "double press" for segment selection
|
||||
WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]);
|
||||
Segment& seg = strip.getSegment(macroDoublePress[b]);
|
||||
if (aRead == 0) {
|
||||
seg.setOption(SEG_OPTION_ON, 0); // off
|
||||
} else {
|
||||
|
@ -1,9 +1,54 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Color conversion methods
|
||||
* Color conversion & utility methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t IRAM_ATTR color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
if(blend == 0) return color1;
|
||||
uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
if(blend == blendmax) return color2;
|
||||
uint8_t shift = b16 ? 16 : 8;
|
||||
|
||||
uint32_t w1 = W(color1);
|
||||
uint32_t r1 = R(color1);
|
||||
uint32_t g1 = G(color1);
|
||||
uint32_t b1 = B(color1);
|
||||
|
||||
uint32_t w2 = W(color2);
|
||||
uint32_t r2 = R(color2);
|
||||
uint32_t g2 = G(color2);
|
||||
uint32_t b2 = B(color2);
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
|
||||
|
||||
return RGBW32(r3, g3, b3, w3);
|
||||
}
|
||||
|
||||
/*
|
||||
* color add function that preserves ratio
|
||||
* idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
||||
*/
|
||||
uint32_t color_add(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
uint32_t r = R(c1) + R(c2);
|
||||
uint32_t g = G(c1) + G(c2);
|
||||
uint32_t b = B(c1) + B(c2);
|
||||
uint32_t w = W(c1) + W(c2);
|
||||
uint16_t max = r;
|
||||
if (g > max) max = g;
|
||||
if (b > max) max = b;
|
||||
if (w > max) max = w;
|
||||
if (max < 256) return RGBW32(r, g, b, w);
|
||||
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
|
||||
}
|
||||
|
||||
void setRandomColor(byte* rgb)
|
||||
{
|
||||
lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex);
|
||||
|
@ -5,6 +5,8 @@
|
||||
* Readability defines and their associated numerical values + compile-time constants
|
||||
*/
|
||||
|
||||
#define GRADIENT_PALETTE_COUNT 58
|
||||
|
||||
//Defaults
|
||||
#define DEFAULT_CLIENT_SSID "Your_Network"
|
||||
#define DEFAULT_AP_PASS "wled1234"
|
||||
|
@ -58,6 +58,9 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
|
||||
|
||||
//colors.cpp
|
||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||
uint32_t color_add(uint32_t,uint32_t);
|
||||
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
@ -129,7 +132,7 @@ void handleIR();
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
|
||||
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serializeModeNames(JsonArray arr, const char *qstring);
|
||||
|
@ -90,7 +90,7 @@ void changeEffect(uint8_t fx)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
strip.setMode(i, fx);
|
||||
}
|
||||
@ -106,7 +106,7 @@ void changePalette(uint8_t pal)
|
||||
{
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.palette = pal;
|
||||
}
|
||||
@ -125,7 +125,7 @@ void changeEffectSpeed(int8_t amount)
|
||||
effectSpeed = (byte)constrain(new_val,0,255);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
@ -135,7 +135,7 @@ void changeEffectSpeed(int8_t amount)
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||
WS2812FX::Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = R(sseg.colors[0]);
|
||||
fastled_col.green = G(sseg.colors[0]);
|
||||
@ -148,7 +148,7 @@ void changeEffectSpeed(int8_t amount)
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
}
|
||||
@ -172,7 +172,7 @@ void changeEffectIntensity(int8_t amount)
|
||||
effectIntensity = (byte)constrain(new_val,0,255);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
@ -182,7 +182,7 @@ void changeEffectIntensity(int8_t amount)
|
||||
setValuesFromMainSeg();
|
||||
}
|
||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||
WS2812FX::Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = R(sseg.colors[0]);
|
||||
fastled_col.green = G(sseg.colors[0]);
|
||||
@ -193,7 +193,7 @@ void changeEffectIntensity(int8_t amount)
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
if (irApplyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
|
||||
}
|
||||
@ -215,7 +215,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
if (irApplyToAllSelected) {
|
||||
// main segment may not be selected!
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
byte capabilities = seg.getLightCapabilities();
|
||||
uint32_t mask = 0;
|
||||
@ -233,7 +233,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
setValuesFromFirstSelectedSeg();
|
||||
} else {
|
||||
byte i = strip.getMainSegmentId();
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
byte capabilities = seg.getLightCapabilities();
|
||||
uint32_t mask = 0;
|
||||
bool isRGB = GET_BIT(capabilities, 0); // is segment RGB capable
|
||||
@ -253,7 +253,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
|
||||
|
||||
void changeWhite(int8_t amount, int16_t cct=-1)
|
||||
{
|
||||
WS2812FX::Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
byte r = R(seg.colors[0]);
|
||||
byte g = G(seg.colors[0]);
|
||||
byte b = B(seg.colors[0]);
|
||||
@ -424,7 +424,7 @@ void decodeIR24CT(uint32_t code)
|
||||
|
||||
void decodeIR40(uint32_t code)
|
||||
{
|
||||
WS2812FX::Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
byte r = R(seg.colors[0]);
|
||||
byte g = G(seg.colors[0]);
|
||||
byte b = B(seg.colors[0]);
|
||||
|
@ -11,8 +11,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
byte id = elem["id"] | it;
|
||||
if (id >= strip.getMaxSegments()) return;
|
||||
|
||||
WS2812FX::Segment& seg = strip.getSegment(id);
|
||||
WS2812FX::Segment prev = seg; //make a backup so we can tell if something changed
|
||||
Segment& seg = strip.getSegment(id);
|
||||
Segment prev = seg; //make a backup so we can tell if something changed
|
||||
|
||||
uint16_t start = elem["start"] | seg.start;
|
||||
int stop = elem["stop"] | -1;
|
||||
@ -327,7 +327,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
//apply all selected segments
|
||||
//bool didSet = false;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive()) {
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
@ -396,7 +396,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
return stateResponse;
|
||||
}
|
||||
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||
{
|
||||
root["id"] = id;
|
||||
if (segmentBounds) {
|
||||
@ -494,7 +494,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
bool selectedSegmentsOnly = root[F("sc")] | false;
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
Segment &sg = strip.getSegment(s);
|
||||
if (selectedSegmentsOnly && !sg.isSelected()) continue;
|
||||
if (sg.isActive()) {
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
|
@ -8,7 +8,7 @@ void setValuesFromMainSeg() { setValuesFromSegment(strip.getMainSegment
|
||||
void setValuesFromFirstSelectedSeg() { setValuesFromSegment(strip.getFirstSelectedSegId()); }
|
||||
void setValuesFromSegment(uint8_t s)
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(s);
|
||||
Segment& seg = strip.getSegment(s);
|
||||
col[0] = R(seg.colors[0]);
|
||||
col[1] = G(seg.colors[0]);
|
||||
col[2] = B(seg.colors[0]);
|
||||
@ -30,9 +30,9 @@ void applyValuesToSelectedSegs()
|
||||
{
|
||||
// copy of first selected segment to tell if value was updated
|
||||
uint8_t firstSel = strip.getFirstSelectedSegId();
|
||||
WS2812FX::Segment selsegPrev = strip.getSegment(firstSel);
|
||||
Segment selsegPrev = strip.getSegment(firstSel);
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;
|
||||
|
||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||
|
@ -13,8 +13,6 @@
|
||||
#ifndef PalettesWLED_h
|
||||
#define PalettesWLED_h
|
||||
|
||||
#define GRADIENT_PALETTE_COUNT 58
|
||||
|
||||
const byte ib_jul01_gp[] PROGMEM = {
|
||||
0, 194, 1, 1,
|
||||
94, 1, 29, 18,
|
||||
|
@ -612,7 +612,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
}
|
||||
|
||||
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
||||
Segment& selseg = strip.getSegment(selectedSeg);
|
||||
pos = req.indexOf(F("SV=")); //segment selected
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
@ -823,7 +823,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
|
||||
// apply to main and all selected segments to prevent #1618.
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all
|
||||
if (fxModeChanged) strip.setMode(i, effectIn);
|
||||
if (speedChanged) seg.speed = speedIn;
|
||||
|
@ -28,7 +28,7 @@ void notify(byte callMode, bool followUp)
|
||||
default: return;
|
||||
}
|
||||
byte udpOut[WLEDPACKETSIZE];
|
||||
WS2812FX::Segment& mainseg = strip.getMainSegment();
|
||||
Segment& mainseg = strip.getMainSegment();
|
||||
udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol
|
||||
udpOut[1] = callMode;
|
||||
udpOut[2] = bri;
|
||||
@ -92,7 +92,7 @@ void notify(byte callMode, bool followUp)
|
||||
udpOut[39] = strip.getMaxSegments();
|
||||
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment &selseg = strip.getSegment(i);
|
||||
Segment &selseg = strip.getSegment(i);
|
||||
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||
udpOut[0 +ofs] = i;
|
||||
udpOut[1 +ofs] = selseg.start >> 8;
|
||||
@ -143,7 +143,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
if (!realtimeMode && !realtimeOverride) {
|
||||
uint16_t stop, start;
|
||||
if (useMainSegmentOnly) {
|
||||
WS2812FX::Segment& mainseg = strip.getMainSegment();
|
||||
Segment& mainseg = strip.getMainSegment();
|
||||
start = mainseg.start;
|
||||
stop = mainseg.stop;
|
||||
mainseg.setOption(SEG_OPTION_FREEZE, true, strip.getMainSegmentId());
|
||||
@ -343,7 +343,7 @@ void handleNotifications()
|
||||
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte
|
||||
uint8_t id = udpIn[0 +ofs];
|
||||
if (id > strip.getMaxSegments()) break;
|
||||
WS2812FX::Segment& selseg = strip.getSegment(id);
|
||||
Segment& selseg = strip.getSegment(id);
|
||||
uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
|
||||
uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
||||
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
||||
@ -378,7 +378,7 @@ void handleNotifications()
|
||||
// simple effect sync, applies to all selected segments
|
||||
if (applyEffects && (version < 11 || !receiveSegmentOptions)) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected()) continue;
|
||||
if (udpIn[8] < strip.getModeCount()) strip.setMode(i, udpIn[8]);
|
||||
seg.speed = udpIn[9];
|
||||
|
@ -418,7 +418,7 @@ void deEEP() {
|
||||
segObj[F("ix")] = EEPROM.read(i+16);
|
||||
segObj["pal"] = EEPROM.read(i+17);
|
||||
} else {
|
||||
WS2812FX::Segment* seg = strip.getSegments();
|
||||
Segment* seg = strip.getSegments();
|
||||
memcpy(seg, EEPROM.getDataPtr() +i+2, 240);
|
||||
if (ver == 2) { //versions before 2004230 did not have opacity
|
||||
for (byte j = 0; j < strip.getMaxSegments(); j++)
|
||||
|
Loading…
Reference in New Issue
Block a user