Segment API

- moved all drawing logic to segment
- moved transitions to segment
Conditional 2D compile.
Rearranged effect IDs.
Implemented dynamic effect arrays.
This commit is contained in:
Blaz Kristan 2022-07-10 22:23:25 +02:00
parent f0992d56c1
commit d9f2c2b968
17 changed files with 1473 additions and 1401 deletions

View File

@ -251,6 +251,7 @@ private:
* Sort either the modes or the palettes using quicksort.
*/
void re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip) {
if (!modeNames) return;
listBeingSorted = modeNames;
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
listBeingSorted = nullptr;
@ -777,7 +778,7 @@ public:
for (byte i=0; i<strip.getMaxSegments(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue;
seg.setCCT(currentCCT, i);
seg.setCCT(currentCCT);
}
// } else {
// Segment& seg = strip.getSegment(strip.getMainSegmentId());

File diff suppressed because it is too large Load Diff

View File

@ -87,10 +87,10 @@ uint32_t color_add(uint32_t,uint32_t);
#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15)
#define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT strip.getSegment(strip.getCurrSegmentId())
#define SEGENV strip.getSegmentRuntime(strip.getCurrSegmentId())
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
#define SEGENV strip._segment_runtimes[strip.getCurrSegmentId()]
#define SEGCOLOR(x) strip.segColor(x)
#define SEGLEN strip.segLen()
#define SEGLEN strip._virtualSegmentLength
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
// some common colors
@ -246,125 +246,143 @@ uint32_t color_add(uint32_t,uint32_t);
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
// new 2D effects
#define FX_MODE_SPACESHIPS 118
#define FX_MODE_CRAZYBEES 119
#define FX_MODE_GHOST_RIDER 120
#define FX_MODE_BLOBS 121
#define FX_MODE_SCROLL_TEXT 122
#define FX_MODE_DRIFT_ROSE 123
#define FX_MODE_2DSPACESHIPS 118
#define FX_MODE_2DCRAZYBEES 119
#define FX_MODE_2DGHOSTRIDER 120
#define FX_MODE_2DBLOBS 121
#define FX_MODE_2DSCROLLTEXT 122
#define FX_MODE_2DDRIFTROSE 123
// WLED-SR effects (non SR compatible IDs)
#define FX_MODE_2DBLACKHOLE 124 // non audio
#define FX_MODE_2DDNASPIRAL 125 // non audio
#define FX_MODE_2DHIPHOTIC 126 // non audio
#define FX_MODE_2DPLASMABALL 127 // non audio
#define FX_MODE_2DSINDOTS 128 // non audio
#define FX_MODE_2DFRIZZLES 129 // non audio
#define FX_MODE_2DLISSAJOUS 130 // non audio
#define FX_MODE_2DPOLARLIGHTS 131 // non audio
#define FX_MODE_2DTARTAN 132 // non audio
#define FX_MODE_2DGAMEOFLIFE 133 // non audio
#define FX_MODE_2DJULIA 134 // non audio
#define FX_MODE_2DCOLOREDBURSTS 135 // non audio
#define FX_MODE_2DSUNRADIATION 136 // non audio
#define FX_MODE_2DNOISE 137 // non audio
#define FX_MODE_2DFIRENOISE 138 // non audio
#define FX_MODE_2DSQUAREDSWIRL 139 // non audio
#define FX_MODE_2DDNA 140 // non audio
#define FX_MODE_2DMATRIX 141 // non audio
#define FX_MODE_2DMETABALLS 142 // non audio
#define FX_MODE_2DPULSER 143 // non audio
#define FX_MODE_2DDRIFT 144 // non audio
#define FX_MODE_2DWAVERLY 145 // audio enhanced
#define FX_MODE_2DSWIRL 146 // audio enhanced
#define FX_MODE_2DAKEMI 147 // audio enhanced
#define FX_MODE_PIXELWAVE 160 // audio enhanced
#define FX_MODE_JUGGLES 161 // audio enhanced
#define FX_MODE_MATRIPIX 162 // audio enhanced
#define FX_MODE_GRAVIMETER 163 // audio enhanced
#define FX_MODE_PLASMOID 164 // audio enhanced
#define FX_MODE_PUDDLES 165 // audio enhanced
#define FX_MODE_MIDNOISE 166 // audio enhanced
#define FX_MODE_NOISEMETER 167 // audio enhanced
#define FX_MODE_NOISEFIRE 168 // audio enhanced
#define FX_MODE_PUDDLEPEAK 169 // audio enhanced
#define FX_MODE_RIPPLEPEAK 170 // audio enhanced
#define FX_MODE_GRAVCENTER 171 // audio enhanced
#define FX_MODE_GRAVCENTRIC 172 // audio enhanced
// WLED-SR effects
#ifndef USERMOD_AUDIOREACTIVE
#define FX_MODE_2DBLACKHOLE 124 // non audio
#define FX_MODE_2DDNASPIRAL 125 // non audio
#define FX_MODE_2DHIPHOTIC 126 // non audio
#define FX_MODE_2DPLASMABALL 127 // non audio
#define FX_MODE_2DSINDOTS 128 // non audio
#define FX_MODE_PIXELWAVE 129 // audio enhanced
#define FX_MODE_JUGGLES 130 // audio enhanced
#define FX_MODE_MATRIPIX 131 // audio enhanced
#define FX_MODE_GRAVIMETER 132 // audio enhanced
#define FX_MODE_PLASMOID 133 // audio enhanced
#define FX_MODE_PUDDLES 134 // audio enhanced
#define FX_MODE_MIDNOISE 135 // audio enhanced
#define FX_MODE_NOISEMETER 136 // audio enhanced
#define FX_MODE_2DFRIZZLES 137 // non audio
#define FX_MODE_2DLISSAJOUS 138 // non audio
#define FX_MODE_2DPOLARLIGHTS 139 // non audio
#define FX_MODE_2DTARTAN 140 // non audio
#define FX_MODE_2DGAMEOFLIFE 141 // non audio
#define FX_MODE_2DJULIA 142 // non audio
#define FX_MODE_NOISEFIRE 143 // audio enhanced
#define FX_MODE_PUDDLEPEAK 144 // audio enhanced
#define FX_MODE_2DCOLOREDBURSTS 145 // non audio
#define FX_MODE_2DSUNRADIATION 146 // non audio
#define FX_MODE_2DNOISE 147 // non audio
#define FX_MODE_RIPPLEPEAK 148 // audio enhanced
#define FX_MODE_2DFIRENOISE 149 // non audio
#define FX_MODE_2DSQUAREDSWIRL 150 // non audio
#define FX_MODE_2DDNA 151 // non audio
#define FX_MODE_2DMATRIX 152 // non audio
#define FX_MODE_2DMETABALLS 153 // non audio
#define FX_MODE_2DPULSER 154 // non audio
#define FX_MODE_2DDRIFT 155 // non audio
#define FX_MODE_2DWAVERLY 156 // audio enhanced
#define FX_MODE_GRAVCENTER 157 // audio enhanced
#define FX_MODE_GRAVCENTRIC 158 // audio enhanced
#define FX_MODE_2DSWIRL 159 // audio enhanced
#define FX_MODE_2DAKEMI 160 // audio enhanced
#define MODE_COUNT 161
#define MODE_COUNT 173
#else
#define FX_MODE_PIXELS 128
#define FX_MODE_PIXELWAVE 129 // audio enhanced
#define FX_MODE_JUGGLES 130 // audio enhanced
#define FX_MODE_MATRIPIX 131 // audio enhanced
#define FX_MODE_GRAVIMETER 132 // audio enhanced
#define FX_MODE_PLASMOID 133 // audio enhanced
#define FX_MODE_PUDDLES 134 // audio enhanced
#define FX_MODE_MIDNOISE 135 // audio enhanced
#define FX_MODE_NOISEMETER 136 // audio enhanced
#define FX_MODE_FREQWAVE 137
#define FX_MODE_FREQMATRIX 138
#define FX_MODE_2DGEQ 139
#define FX_MODE_WATERFALL 140
#define FX_MODE_FREQPIXELS 141
#define FX_MODE_BINMAP 142
#define FX_MODE_NOISEFIRE 143 // audio enhanced
#define FX_MODE_PUDDLEPEAK 144 // audio enhanced
#define FX_MODE_NOISEMOVE 145
#define FX_MODE_2DNOISE 146 // non audio
#define FX_MODE_PIXELS 173
// #define FX_MODE_PIXELWAVE 129 // audio enhanced
// #define FX_MODE_JUGGLES 130 // audio enhanced
// #define FX_MODE_MATRIPIX 131 // audio enhanced
// #define FX_MODE_GRAVIMETER 132 // audio enhanced
// #define FX_MODE_PLASMOID 133 // audio enhanced
// #define FX_MODE_PUDDLES 134 // audio enhanced
// #define FX_MODE_MIDNOISE 135 // audio enhanced
// #define FX_MODE_NOISEMETER 136 // audio enhanced
#define FX_MODE_FREQWAVE 174
#define FX_MODE_FREQMATRIX 175
#define FX_MODE_2DGEQ 148
#define FX_MODE_WATERFALL 176
#define FX_MODE_FREQPIXELS 177
#define FX_MODE_BINMAP 178
// #define FX_MODE_NOISEFIRE 143 // audio enhanced
// #define FX_MODE_PUDDLEPEAK 144 // audio enhanced
#define FX_MODE_NOISEMOVE 179
// #define FX_MODE_2DNOISE 146 // non audio
//#define FX_MODE_PERLINMOVE 147 // moved to 53
#define FX_MODE_RIPPLEPEAK 148 // audio enhanced
#define FX_MODE_2DFIRENOISE 149 // non audio
#define FX_MODE_2DSQUAREDSWIRL 150 // non audio
// #define FX_MODE_RIPPLEPEAK 148 // audio enhanced
// #define FX_MODE_2DFIRENOISE 149 // non audio
// #define FX_MODE_2DSQUAREDSWIRL 150 // non audio
//#define FX_MODE_2DFIRE2012 151 // implemented in native Fire2012
#define FX_MODE_2DDNA 152 // non audio
#define FX_MODE_2DMATRIX 153 // non audio
#define FX_MODE_2DMETABALLS 154 // non audio
#define FX_MODE_FREQMAP 155
#define FX_MODE_GRAVCENTER 156 // audio enhanced
#define FX_MODE_GRAVCENTRIC 157 // audio enhanced
#define FX_MODE_GRAVFREQ 158
#define FX_MODE_DJLIGHT 159
#define FX_MODE_2DFUNKYPLANK 160
// #define FX_MODE_2DDNA 152 // non audio
// #define FX_MODE_2DMATRIX 153 // non audio
// #define FX_MODE_2DMETABALLS 154 // non audio
#define FX_MODE_FREQMAP 180
// #define FX_MODE_GRAVCENTER 156 // audio enhanced
// #define FX_MODE_GRAVCENTRIC 157 // audio enhanced
#define FX_MODE_GRAVFREQ 181
#define FX_MODE_DJLIGHT 182
#define FX_MODE_2DFUNKYPLANK 149
//#define FX_MODE_2DCENTERBARS 161 // obsolete by X & Y mirroring
#define FX_MODE_2DPULSER 162 // non audio
#define FX_MODE_BLURZ 163
#define FX_MODE_2DDRIFT 164 // non audio
#define FX_MODE_2DWAVERLY 165 // audio enhanced
#define FX_MODE_2DSUNRADIATION 166 // non audio
#define FX_MODE_2DCOLOREDBURSTS 167 // non audio
#define FX_MODE_2DJULIA 168 // non audio
#define FX_MODE_2DPOOLNOISE 169 // reserved in JSON_mode_names
#define FX_MODE_2DTWISTER 170 // reserved in JSON_mode_names
#define FX_MODE_2DCAELEMENTATY 171 // reserved in JSON_mode_names
#define FX_MODE_2DGAMEOFLIFE 172 // non audio
#define FX_MODE_2DTARTAN 173 // non audio
#define FX_MODE_2DPOLARLIGHTS 174 // non audio
#define FX_MODE_2DSWIRL 175 // audio enhanced
#define FX_MODE_2DLISSAJOUS 176 // non audio
#define FX_MODE_2DFRIZZLES 177 // non audio
#define FX_MODE_2DPLASMABALL 178 // non audio
// #define FX_MODE_2DPULSER 162 // non audio
#define FX_MODE_BLURZ 183
// #define FX_MODE_2DDRIFT 164 // non audio
// #define FX_MODE_2DWAVERLY 165 // audio enhanced
// #define FX_MODE_2DSUNRADIATION 166 // non audio
// #define FX_MODE_2DCOLOREDBURSTS 167 // non audio
// #define FX_MODE_2DJULIA 168 // non audio
#define FX_MODE_2DPOOLNOISE 150 // reserved in JSON_mode_names
#define FX_MODE_2DTWISTER 151 // reserved in JSON_mode_names
#define FX_MODE_2DCAELEMENTATY 152 // reserved in JSON_mode_names
// #define FX_MODE_2DGAMEOFLIFE 172 // non audio
// #define FX_MODE_2DTARTAN 173 // non audio
// #define FX_MODE_2DPOLARLIGHTS 174 // non audio
// #define FX_MODE_2DSWIRL 175 // audio enhanced
// #define FX_MODE_2DLISSAJOUS 176 // non audio
// #define FX_MODE_2DFRIZZLES 177 // non audio
// #define FX_MODE_2DPLASMABALL 178 // non audio
//#define FX_MODE_FLOWSTRIPE 179 // moved to 114
#define FX_MODE_2DHIPHOTIC 180 // non audio
#define FX_MODE_2DSINDOTS 181 // non audio
#define FX_MODE_2DDNASPIRAL 182 // non audio
#define FX_MODE_2DBLACKHOLE 183 // non audio
// #define FX_MODE_2DHIPHOTIC 180 // non audio
// #define FX_MODE_2DSINDOTS 181 // non audio
// #define FX_MODE_2DDNASPIRAL 182 // non audio
// #define FX_MODE_2DBLACKHOLE 183 // non audio
//#define FX_MODE_WAVESINS 184 // moved to 48
#define FX_MODE_ROCKTAVES 185
#define FX_MODE_2DAKEMI 186 // audio enhanced
#define FX_MODE_ROCKTAVES 184
// #define FX_MODE_2DAKEMI 186 // audio enhanced
//#define FX_MODE_CUSTOMEFFECT 187 //WLEDSR Custom Effects
#define MODE_COUNT 187
#define MODE_COUNT 185
#endif
struct Segment;
// color transitions
typedef struct ColorTransition { // 20 bytes
uint32_t colorOld[NUM_COLORS];
uint8_t briOld;
uint8_t cctOld;
uint32_t transitionStart;
uint16_t transitionDur;
void startTransition(Segment *seg, uint16_t dur, uint8_t oldBri, uint8_t oldCct, uint32_t *oldCol);
void handleTransition(Segment *seg, uint8_t &newBri, uint8_t &newCct, uint32_t *newCol);
uint16_t progress(); //transition progression between 0-65535
uint8_t currentBri(uint8_t briNew, bool useCct = false);
uint32_t currentColor(uint8_t slot, uint32_t colorNew) {
return color_blend(colorOld[slot], colorNew, progress(), true);
}
} color_transition;
// segment parameters
typedef struct Segment { // 35 (36 in memory) bytes
typedef struct Segment { // 40 (44 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;
@ -382,6 +400,8 @@ typedef struct Segment { // 35 (36 in memory) bytes
uint16_t startY; // start Y coodrinate 2D (top)
uint16_t stopY; // stop Y coordinate 2D (bottom)
char *name;
color_transition transition;
inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); }
inline bool isSelected() { return getOption(0); }
inline bool isActive() { return stop > start; }
@ -390,22 +410,71 @@ typedef struct Segment { // 35 (36 in memory) bytes
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);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
void setCCT(uint16_t k);
void setOpacity(uint8_t o);
void setOption(uint8_t n, bool val);
uint8_t differs(Segment& b);
void refreshLightCapabilities();
// 1D strip
uint16_t virtualLength();
void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline
void setPixelColor(int n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); } // automatically inline
void setPixelColor(float i, uint32_t c, bool aa = true);
void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, c.red, c.green, c.blue, 0, aa); }
uint32_t getPixelColor(uint16_t i);
// 1D support functions (some implement 2D as well)
void blur(uint8_t);
void fill(uint32_t c);
void fade_out(uint8_t r);
void fadeToBlackBy(uint8_t fadeBy);
void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend);
void addPixelColor(uint16_t n, uint32_t color);
uint8_t get_random_wheel_index(uint8_t pos);
uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255);
uint32_t color_wheel(uint8_t pos);
// 2D matrix
uint16_t virtualWidth();
uint16_t virtualHeight();
// 1D strip
uint16_t virtualLength();
uint8_t differs(Segment& b);
void refreshLightCapabilities();
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[])
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, c.red, c.green, c.blue); } // automatically inline
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true);
void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, c.red, c.green, c.blue, 0, aa); }
uint32_t getPixelColorXY(uint16_t x, uint16_t y);
// 2D support functions
void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend);
void addPixelColorXY(uint16_t x, uint16_t y, uint32_t color);
void blur1d(CRGB* leds, fract8 blur_amount);
void blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds=nullptr); // 1D box blur (with weight)
void blur2d(CRGB* leds, fract8 blur_amount);
void blurRow(uint16_t row, fract8 blur_amount, CRGB* leds=nullptr);
void blurCol(uint16_t col, fract8 blur_amount, CRGB* leds=nullptr);
void moveX(CRGB *leds, int8_t delta);
void moveY(CRGB *leds, int8_t delta);
void move(uint8_t dir, uint8_t delta, CRGB *leds=nullptr);
void fill_solid(CRGB* leds, CRGB c);
void fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
void fadeToBlackBy(CRGB* leds, uint8_t fadeBy);
void nscale8(CRGB* leds, uint8_t scale);
void setPixels(CRGB* leds);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds = nullptr);
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color, CRGB *leds = nullptr);
void wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c);
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t c) { drawCharacter(chr, x, y, w, h, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
} segment;
// segment runtime parameters
typedef struct Segment_runtime { // 28 bytes
typedef struct Segment_runtime { // 23 (24 in memory) bytes
unsigned long next_time; // millis() of next update
uint32_t step; // custom "step" var
uint32_t call; // call counter
@ -429,25 +498,9 @@ typedef struct Segment_runtime { // 28 bytes
} 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 {
class WS2812FX { // 96 bytes
typedef uint16_t (*mode_ptr)(void); // pointer to mode function
typedef void (*show_callback)(void); // pre show callback
@ -457,7 +510,10 @@ class WS2812FX {
WS2812FX() {
WS2812FX::instance = this;
setupEffectData();
_mode = new mode_ptr[_modeCount];
_modeData = new const char*[_modeCount];
if (_mode && _modeData) setupEffectData();
else _modeCount = 1; // only Solid will work
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
targetPalette = CloudColors_p;
@ -467,15 +523,16 @@ class WS2812FX {
resetSegments();
}
~WS2812FX() {
delete[] _mode;
delete[] _modeData;
}
static WS2812FX* getInstance(void) { return instance; }
void
finalizeInit(),
service(void),
blur(uint8_t),
fill(uint32_t c, uint8_t seg=255),
fade_out(uint8_t r),
fadeToBlackBy(uint8_t fadeBy),
setMode(uint8_t segid, uint8_t m),
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setColor(uint8_t slot, uint32_t c),
@ -490,21 +547,18 @@ class WS2812FX {
resetSegments(),
makeAutoSegments(bool forceReset = false),
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),
setPixelColor(int n, uint32_t c),
show(void),
setTargetFps(uint8_t fps),
deserializeMap(uint8_t n=0);
void addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name) { if (id < _modeCount) { _mode[id] = mode_fn; _modeData[id] = mode_name;} }
void setupEffectData(void); // defined in FX.cpp
void fill(uint32_t c) { for (int i = 0; i < _length; i++) setPixelColor(i, c); } // fill whole strip with color (inline)
void addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp
void setupEffectData(void); // add default effects to the list; defined in FX.cpp
// outsmart the compiler :) by correctly overloading
inline void setPixelColor(int n, uint32_t c) {setPixelColor(n, byte(c>>16), byte(c>>8), byte(c), byte(c>>24));}
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 setPixelColor(int n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
inline void setPixelColor(int n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
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; }
@ -531,8 +585,7 @@ class WS2812FX {
getLastActiveSegmentId(void),
setPixelSegment(uint8_t n),
gamma8(uint8_t),
gamma8_cal(uint8_t, float),
get_random_wheel_index(uint8_t);
gamma8_cal(uint8_t, float);
inline uint8_t getBrightness(void) { return _brightness; }
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; }
@ -541,31 +594,21 @@ class WS2812FX {
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;
return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0
}
int8_t
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
uint16_t
ablMilliampsMax,
currentMilliamps,
triwave16(uint16_t),
getLengthPhysical(void),
getFps();
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; }
inline uint16_t getTransition(void) { return _transitionDur; }
uint32_t
now,
timebase,
color_wheel(uint8_t),
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
currentColor(uint32_t colorNew, uint8_t tNr),
gamma32(uint32_t),
getPixelColor(uint16_t);
@ -574,7 +617,7 @@ class WS2812FX {
inline uint32_t segColor(uint8_t i) { return _colors_t[i]; }
const char *
getModeData(uint8_t id = 0) { return id<_modeCount ? _modeData[id] : nullptr; }
getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
const char **
getModeDataSrc(void) { return _modeData; }
@ -589,6 +632,8 @@ class WS2812FX {
bool
isMatrix = false;
#ifndef WLED_DISABLE_2D
#define WLED_MAX_PANELS 64
uint8_t
hPanels = 1,
vPanels = 1;
@ -599,7 +644,6 @@ class WS2812FX {
matrixWidth = DEFAULT_LED_COUNT,
matrixHeight = 1;
#define WLED_MAX_PANELS 64
typedef struct panel_bitfield_t {
unsigned char
bottomStart : 1, // starts at bottom?
@ -610,41 +654,15 @@ class WS2812FX {
Panel
matrix = {0,0,0,0},
panel[WLED_MAX_PANELS] = {{0,0,0,0}};
#endif
void
setUpMatrix(),
setPixelColorXY(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = false),
blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend),
addPixelColorXY(uint16_t x, uint16_t y, uint32_t color),
blur1d(CRGB* leds, fract8 blur_amount),
blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds=nullptr), // 1D box blur (with weight)
blur2d(CRGB* leds, fract8 blur_amount),
blurRow(uint16_t row, fract8 blur_amount, CRGB* leds=nullptr),
blurCol(uint16_t col, fract8 blur_amount, CRGB* leds=nullptr),
moveX(CRGB *leds, int8_t delta),
moveY(CRGB *leds, int8_t delta),
move(uint8_t dir, uint8_t delta, CRGB *leds=nullptr),
fill_solid(CRGB* leds, CRGB c),
fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius, CRGB c),
fadeToBlackBy(CRGB* leds, uint8_t fadeBy),
nscale8(CRGB* leds, uint8_t scale),
setPixels(CRGB* leds),
drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds = nullptr),
drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color, CRGB *leds = nullptr),
wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c);
setPixelColorXY(int x, int y, uint32_t c);
// outsmart the compiler :) by correctly overloading
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); }
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, c.red, c.green, c.blue, 0); }
inline void setPixelColorXY(float x, float y, uint32_t c, bool aa=true) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24), aa); }
inline void setPixelColorXY(float x, float y, CRGB c, bool aa=true) { setPixelColorXY(x, y, c.red, c.green, c.blue, 0, aa); }
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t c) { drawCharacter(chr, x, y, w, h, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
uint16_t
XY(uint16_t, uint16_t),
get2DPixelIndex(uint16_t x, uint16_t y, uint8_t seg=255);
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, c.red, c.green, c.blue); }
uint32_t
getPixelColorXY(uint16_t, uint16_t);
@ -654,8 +672,20 @@ class WS2812FX {
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
uint32_t _colors_t[3];
uint16_t _virtualSegmentLength;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element
// 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;
private:
uint16_t _length, _virtualSegmentLength;
uint16_t _length;
uint16_t _rand16seed;
uint8_t _brightness;
uint16_t _usedSegmentData = 0;
@ -671,9 +701,8 @@ class WS2812FX {
_triggered;
uint8_t _modeCount = MODE_COUNT;
// TODO: allocate memory using new or malloc()
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
const char *_modeData[MODE_COUNT]; // mode (effect) name and its slider control data array
mode_ptr *_mode; // SRAM footprint: 4 bytes per element
const char **_modeData; // mode (effect) name and its slider control data array
show_callback _callback = nullptr;
@ -683,26 +712,12 @@ class WS2812FX {
uint32_t _lastPaletteChange = 0;
uint32_t _lastShow = 0;
uint32_t _colors_t[3];
uint8_t _bri_t;
bool _no_rgb = false;
uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99;
uint8_t _mainSegment;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element
// 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),

View File

@ -26,23 +26,6 @@
#include "FX.h"
#include "palettes.h"
#ifdef SEGMENT
#undef SEGMENT
#endif
#ifdef SEGCOLOR
#undef SEGCOLOR
#endif
#ifdef SEGENV
#undef SEGENV
#endif
#ifdef SEGLEN
#undef SEGLEN
#endif
#define SEGMENT _segments[_segment_index]
#define SEGCOLOR(x) _colors_t[x]
#define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN _virtualSegmentLength
// setUpMatrix() - constructs ledmap array from matrix of panels with WxH pixels
// this converts physical (possibly irregular) LED arrangement into well defined
// array of logical pixels: fist entry corresponds to left-topmost logical pixel
@ -52,6 +35,7 @@
// but ledmap takes care of that. ledmap is constructed upon initialization
// so matrix should disable regular ledmap processing
void WS2812FX::setUpMatrix() {
#ifndef WLED_DISABLE_2D
// erase old ledmap, just in case.
if (customMappingTable != nullptr) delete[] customMappingTable;
customMappingTable = nullptr;
@ -63,7 +47,7 @@ void WS2812FX::setUpMatrix() {
// safety check
if (matrixWidth * matrixHeight > MAX_LEDS) {
matrixWidth = getLengthTotal();
matrixWidth = _length;
matrixHeight = 1;
isMatrix = false;
return;
@ -111,93 +95,112 @@ void WS2812FX::setUpMatrix() {
#endif
} else {
// memory allocation error
matrixWidth = getLengthTotal();
matrixWidth = _length;
matrixHeight = 1;
isMatrix = false;
return;
}
} else {
// not a matrix set up
matrixWidth = getLengthTotal();
matrixWidth = _length;
matrixHeight = 1;
}
#endif
}
// absolute matrix version of setPixelColor()
void IRAM_ATTR WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
{
#ifndef WLED_DISABLE_2D
if (!isMatrix) return; // not a matrix set-up
uint16_t index = y * matrixWidth + x;
if (index >= _length) return;
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
#endif
}
// returns RGBW values of pixel
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
#ifndef WLED_DISABLE_2D
uint16_t index = (y * matrixWidth + x);
if (index >= _length) return 0;
if (index < customMappingSize) index = customMappingTable[index];
return busses.getPixelColor(index);
#else
return 0;
#endif
}
///////////////////////////////////////////////////////////
// Segment:: routines
///////////////////////////////////////////////////////////
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
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
uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y) {
#ifndef WLED_DISABLE_2D
uint16_t width = virtualWidth(); // segment width in logical pixels
uint16_t height = virtualHeight(); // segment height in logical pixels
return (x%width) + (y%height) * width;
#else
return 0;
#endif
}
// get2DPixelIndex(x,y,seg) - returns an index of segment pixel in a matrix layout
// index still needs to undergo ledmap processing to represent actual physical pixel
// matrix is always organized by matrixHeight number of matrixWidth pixels from top to bottom, left to right
// so: pixel at get2DPixelIndex(5,6) in a 2D segment with [start=10, stop=19, startY=20, stopY=29 : 10x10 pixels]
// corresponds to pixel with logical index of 847 (0 based) if a 2D segment belongs to a 32x32 matrix.
// math: (matrixWidth * (startY + y)) + start + x => (32 * (20+6)) + 10 + 5 = 847
uint16_t IRAM_ATTR WS2812FX::get2DPixelIndex(uint16_t x, uint16_t y, uint8_t seg) {
if (seg == 255) seg = _segment_index;
x %= _segments[seg].width(); // just in case constrain x (wrap around)
y %= _segments[seg].height(); // just in case constrain y (wrap around)
return ((_segments[seg].startY + y) * matrixWidth) + _segments[seg].start + x;
}
void IRAM_ATTR WS2812FX::setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w)
void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
{
if (!isMatrix) return; // not a matrix set-up
#ifndef WLED_DISABLE_2D
if (!strip.isMatrix) return; // not a matrix set-up
if (_bri_t < 255) {
r = scale8(r, _bri_t);
g = scale8(g, _bri_t);
b = scale8(b, _bri_t);
w = scale8(w, _bri_t);
uint8_t _bri_t = getOption(SEG_OPTION_TRANSITIONAL) ? transition.briOld : opacity;
if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t);
byte b = scale8(B(col), _bri_t);
byte w = scale8(W(col), _bri_t);
col = RGBW32(r, g, b, w);
}
uint32_t col = RGBW32(r, g, b, w);
if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) x = SEGMENT.virtualWidth() - x - 1;
if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) y = SEGMENT.virtualHeight() - y - 1;
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
if (getOption(SEG_OPTION_REVERSED) ) x = virtualWidth() - x - 1;
if (getOption(SEG_OPTION_REVERSED_Y)) y = virtualHeight() - y - 1;
if (getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= SEGMENT.groupLength(); // expand to physical pixels
y *= SEGMENT.groupLength(); // expand to physical pixels
if (x >= SEGMENT.width() || y >= SEGMENT.height()) return; // if pixel would fall out of segment just exit
x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
for (uint8_t j = 0; j < SEGMENT.grouping; j++) { // groupping vertically
for (uint8_t g = 0; g < SEGMENT.grouping; g++) { // groupping horizontally
uint16_t index, xX = (x+g), yY = (y+j);
if (xX >= SEGMENT.width() || yY >= SEGMENT.height()) continue; // we have reached one dimension's end
for (int j = 0; j < grouping; j++) { // groupping vertically
for (int g = 0; g < grouping; g++) { // groupping horizontally
uint16_t xX = (x+g), yY = (y+j);
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
index = get2DPixelIndex(xX, yY);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
strip.setPixelColorXY(start + xX, startY + yY, col);
if (SEGMENT.getOption(SEG_OPTION_MIRROR)) { //set the corresponding horizontally mirrored pixel
index = SEGMENT.getOption(SEG_OPTION_TRANSPOSED) ? get2DPixelIndex(xX, SEGMENT.height() - yY - 1) : get2DPixelIndex(SEGMENT.width() - xX - 1, yY);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
if (getOption(SEG_OPTION_MIRROR)) { //set the corresponding horizontally mirrored pixel
if (getOption(SEG_OPTION_TRANSPOSED)) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
}
if (SEGMENT.getOption(SEG_OPTION_MIRROR_Y)) { //set the corresponding vertically mirrored pixel
index = SEGMENT.getOption(SEG_OPTION_TRANSPOSED) ? get2DPixelIndex(SEGMENT.width() - xX - 1, yY) : get2DPixelIndex(xX, SEGMENT.height() - yY - 1);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
if (getOption(SEG_OPTION_MIRROR_Y)) { //set the corresponding vertically mirrored pixel
if (getOption(SEG_OPTION_TRANSPOSED)) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col);
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col);
}
if (SEGMENT.getOption(SEG_OPTION_MIRROR_Y) && SEGMENT.getOption(SEG_OPTION_MIRROR)) { //set the corresponding vertically AND horizontally mirrored pixel
index = get2DPixelIndex(SEGMENT.width() - xX - 1, SEGMENT.height() - yY - 1);
if (index < customMappingSize) index = customMappingTable[index];
busses.setPixelColor(index, col);
if (getOption(SEG_OPTION_MIRROR_Y) && getOption(SEG_OPTION_MIRROR)) { //set the corresponding vertically AND horizontally mirrored pixel
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col);
}
}
}
#endif
}
// anti-aliased version of setPixelColorXY()
void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w, bool aa)
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
{
#ifndef WLED_DISABLE_2D
if (!strip.isMatrix) return; // not a matrix set-up
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
float fX = x * (cols-1);
float fY = y * (rows-1);
@ -216,80 +219,59 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, b
uint32_t cXRYB = getPixelColorXY(xR, yB);
if (xL!=xR && yT!=yB) {
// blend TL pixel
cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, uint8_t(sqrtf(dL*dT)*255.0f));
setPixelColorXY(xL, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT));
// blend TR pixel
cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, uint8_t(sqrtf(dR*dT)*255.0f));
setPixelColorXY(xR, yT, R(cXRYT), G(cXRYT), B(cXRYT), W(cXRYT));
// blend BL pixel
cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, uint8_t(sqrtf(dL*dB)*255.0f));
setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB));
// blend BR pixel
cXRYB = color_blend(RGBW32(r,g,b,w), cXRYB, uint8_t(sqrtf(dR*dB)*255.0f));
setPixelColorXY(xR, yB, R(cXRYB), G(cXRYB), B(cXRYB), W(cXRYB));
setPixelColorXY(xL, yT, color_blend(col, cXLYT, uint8_t(sqrtf(dL*dT)*255.0f))); // blend TL pixel
setPixelColorXY(xR, yT, color_blend(col, cXRYT, uint8_t(sqrtf(dR*dT)*255.0f))); // blend TR pixel
setPixelColorXY(xL, yB, color_blend(col, cXLYB, uint8_t(sqrtf(dL*dB)*255.0f))); // blend BL pixel
setPixelColorXY(xR, yB, color_blend(col, cXRYB, uint8_t(sqrtf(dR*dB)*255.0f))); // blend BR pixel
} else if (xR!=xL && yT==yB) {
// blend L pixel
cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, uint8_t(dL*255.0f));
setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT));
// blend R pixel
cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, uint8_t(dR*255.0f));
setPixelColorXY(xR, yT, R(cXRYT), G(cXRYT), B(cXRYT), W(cXRYT));
setPixelColorXY(xR, yT, color_blend(col, cXLYT, uint8_t(dL*255.0f))); // blend L pixel
setPixelColorXY(xR, yT, color_blend(col, cXRYT, uint8_t(dR*255.0f))); // blend R pixel
} else if (xR==xL && yT!=yB) {
// blend T pixel
cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, uint8_t(dT*255.0f));
setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT));
// blend B pixel
cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, uint8_t(dB*255.0f));
setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB));
setPixelColorXY(xR, yT, color_blend(col, cXLYT, uint8_t(dT*255.0f))); // blend T pixel
setPixelColorXY(xL, yB, color_blend(col, cXLYB, uint8_t(dB*255.0f))); // blend B pixel
} else {
// exact match (x & y land on a pixel)
setPixelColorXY(xL, yT, r, g, b, w);
setPixelColorXY(xL, yT, col); // exact match (x & y land on a pixel)
}
} else {
setPixelColorXY(uint16_t(roundf(fX)), uint16_t(roundf(fY)), r, g, b, w);
setPixelColorXY(uint16_t(roundf(fX)), uint16_t(roundf(fY)), col);
}
#endif
}
// returns RGBW values of pixel
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
uint16_t index;
if (SEGLEN) {
if (SEGMENT.getOption(SEG_OPTION_REVERSED) ) x = SEGMENT.virtualWidth() - x - 1;
if (SEGMENT.getOption(SEG_OPTION_REVERSED_Y)) y = SEGMENT.virtualHeight() - y - 1;
if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= SEGMENT.groupLength(); // expand to physical pixels
y *= SEGMENT.groupLength(); // expand to physical pixels
if (x >= SEGMENT.width() || y >= SEGMENT.height()) return 0;
index = get2DPixelIndex(x, y);
} else {
index = y * matrixWidth + x;
}
if (index < customMappingSize) index = customMappingTable[index];
return busses.getPixelColor(index);
uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) {
#ifndef WLED_DISABLE_2D
if (getOption(SEG_OPTION_REVERSED) ) x = virtualWidth() - x - 1;
if (getOption(SEG_OPTION_REVERSED_Y)) y = virtualHeight() - y - 1;
if (getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels
if (x >= width() || y >= height()) return 0;
return strip.getPixelColorXY(start + x, startY + y);
#else
return 0;
#endif
}
/*
* Blends the specified color with the existing pixel color.
*/
void WS2812FX::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) {
// Blends the specified color with the existing pixel color.
void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) {
#ifndef WLED_DISABLE_2D
setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend));
#endif
}
/*
* Adds the specified color with the existing pixel color perserving color balance.
*/
void WS2812FX::addPixelColorXY(uint16_t x, uint16_t y, uint32_t color) {
// Adds the specified color with the existing pixel color perserving color balance.
void Segment::addPixelColorXY(uint16_t x, uint16_t y, uint32_t color) {
#ifndef WLED_DISABLE_2D
setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color));
#endif
}
// blurRow: perform a blur on a row of a rectangular matrix
void WS2812FX::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
if (row >= rows) return;
// blur one row
@ -311,12 +293,14 @@ void WS2812FX::blurRow(uint16_t row, fract8 blur_amount, CRGB* leds) {
else setPixelColorXY(x, row, cur);
carryover = part;
}
#endif
}
// blurCol: perform a blur on a column of a rectangular matrix
void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
if (col >= cols) return;
// blur one column
@ -338,6 +322,7 @@ void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
else setPixelColorXY(col, i, cur);
carryover = part;
}
#endif
}
// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
@ -354,17 +339,20 @@ void WS2812FX::blurCol(uint16_t col, fract8 blur_amount, CRGB* leds) {
// eventually all the way to black; this is by design so that
// it can be used to (slowly) clear the LEDs to black.
void WS2812FX::blur1d(CRGB* leds, fract8 blur_amount) {
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::blur1d(CRGB* leds, fract8 blur_amount) {
#ifndef WLED_DISABLE_2D
const uint16_t rows = virtualHeight();
for (uint16_t y = 0; y < rows; y++) blurRow(y, blur_amount, leds);
#endif
}
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
void WS2812FX::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dim1 = vertical ? rows : cols;
const uint16_t dim2 = vertical ? cols : rows;
void Segment::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint16_t dim1 = vertical ? rows : cols;
const uint16_t dim2 = vertical ? cols : rows;
if (i >= dim2) return;
const float seep = blur_amount/255.f;
const float keep = 3.f - 2.f*seep;
@ -392,63 +380,65 @@ void WS2812FX::blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds)
if (leds) leds[XY(x,y)] = tmp[j];
else setPixelColorXY(x, y, tmp[j]);
}
#endif
}
void WS2812FX::blur2d(CRGB* leds, fract8 blur_amount) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::blur2d(CRGB* leds, fract8 blur_amount) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (uint16_t i = 0; i < rows; i++) blurRow(i, blur_amount, leds); // blur all rows
for (uint16_t k = 0; k < cols; k++) blurCol(k, blur_amount, leds); // blur all columns
#endif
}
void WS2812FX::moveX(CRGB *leds, int8_t delta) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::moveX(CRGB *leds, int8_t delta) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
if (!delta) return;
if (delta > 0) {
for (uint8_t y = 0; y < rows; y++) for (uint8_t x = 0; x < cols-1; x++) {
if (x + delta >= cols) break;
if (leds) leds[XY(x, y)] = leds[XY((x + delta)%cols, y)];
else setPixelColorXY(x, y, getPixelColorXY((x + delta)%cols, y));
}
} else {
for (uint8_t y = 0; y < rows; y++) for (int16_t x = cols-1; x >= 0; x--) {
if (x + delta < 0) {
if (leds) leds[XY(x, y)] = leds[XY(cols + delta, y)];
else setPixelColorXY(x, y, getPixelColorXY(cols + delta, y));
} else {
if (leds) leds[XY(x, y)] = leds[XY(x + delta, y)];
else setPixelColorXY(x, y, getPixelColorXY(x + delta, y));
}
if (x + delta < 0) break;
if (leds) leds[XY(x, y)] = leds[XY(x + delta, y)];
else setPixelColorXY(x, y, getPixelColorXY(x + delta, y));
}
}
#endif
}
void WS2812FX::moveY(CRGB *leds, int8_t delta) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::moveY(CRGB *leds, int8_t delta) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
if (!delta) return;
if (delta > 0) {
for (uint8_t x = 0; x < cols; x++) for (uint8_t y = 0; y < rows-1; y++) {
if (leds) leds[XY(x, y)] = leds[XY(x, (y + delta)%rows)];
else setPixelColorXY(x, y, getPixelColorXY(x, (y + delta)%rows));
if (y + delta >= rows) break;
if (leds) leds[XY(x, y)] = leds[XY(x, (y + delta))];
else setPixelColorXY(x, y, getPixelColorXY(x, (y + delta)));
}
} else {
for (uint8_t x = 0; x < cols; x++) for (int16_t y = rows-1; y >= 0; y--) {
if (y + delta < 0) {
if (leds) leds[XY(x, y)] = leds[XY(x, rows + delta)];
else setPixelColorXY(x, y, getPixelColorXY(x, rows + delta));
} else {
if (leds) leds[XY(x, y)] = leds[XY(x, y + delta)];
else setPixelColorXY(x, y, getPixelColorXY(x, y + delta));
}
if (y + delta < 0) break;
if (leds) leds[XY(x, y)] = leds[XY(x, y + delta)];
else setPixelColorXY(x, y, getPixelColorXY(x, y + delta));
}
}
#endif
}
// move() - move all pixels in desired direction delta number of pixels
// @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down
// @param delta number of pixels to move
void WS2812FX::move(uint8_t dir, uint8_t delta, CRGB *leds) {
void Segment::move(uint8_t dir, uint8_t delta, CRGB *leds) {
#ifndef WLED_DISABLE_2D
if (delta==0) return;
switch (dir) {
case 0: moveX(leds, delta); break;
@ -460,21 +450,25 @@ void WS2812FX::move(uint8_t dir, uint8_t delta, CRGB *leds) {
case 6: moveY(leds,-delta); break;
case 7: moveX(leds, delta); moveY(leds,-delta); break;
}
#endif
}
void WS2812FX::fill_solid(CRGB* leds, CRGB color) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::fill_solid(CRGB* leds, CRGB color) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
if (leds) leds[XY(x,y)] = color;
else setPixelColorXY(x, y, color);
}
#endif
}
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
void WS2812FX::fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (int16_t y = -radius; y <= radius; y++) {
for (int16_t x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius &&
@ -483,31 +477,39 @@ void WS2812FX::fill_circle(CRGB* leds, uint16_t cx, uint16_t cy, uint8_t radius,
leds[XY(cx + x, cy + y)] += col;
}
}
#endif
}
void WS2812FX::fadeToBlackBy(CRGB* leds, uint8_t fadeBy) {
void Segment::fadeToBlackBy(CRGB* leds, uint8_t fadeBy) {
#ifndef WLED_DISABLE_2D
nscale8(leds, 255 - fadeBy);
#endif
}
void WS2812FX::nscale8(CRGB* leds, uint8_t scale) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::nscale8(CRGB* leds, uint8_t scale) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = 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, CRGB(getPixelColorXY(x, y)).nscale8(scale));
}
#endif
}
void WS2812FX::setPixels(CRGB* leds) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::setPixels(CRGB* leds) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) setPixelColorXY(x, y, leds[XY(x,y)]);
#endif
}
//line function
void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, CRGB *leds) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
const int16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
@ -520,8 +522,10 @@ void WS2812FX::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB
if (e2 >-dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
#endif
}
#ifndef WLED_DISABLE_2D
// font curtesy of https://github.com/idispatch/raster-fonts
static const unsigned char console_font_6x8[] PROGMEM = {
@ -6672,19 +6676,21 @@ static const unsigned char console_font_5x8[] PROGMEM = {
0x00, /* 00000 */
0x00, /* 00000 */
};
#endif
// draws a raster font character on canvas
// only supports 5x8 and 6x8 fonts ATM
void WS2812FX::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color, CRGB *leds) {
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color, CRGB *leds) {
#ifndef WLED_DISABLE_2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
if (w<5 || w>6 || h!=8) return;
for (uint8_t i = 0; i<h; i++) { // character height
int16_t y0 = y + i;
if (y0 < 0) continue; // drawing off-screen
if (y0 >= rows) break; // drawing off-screen
uint8_t bits;
uint8_t bits = 0;
switch (w) {
case 5: bits = pgm_read_byte_near(&console_font_5x8[(chr * 8) + i]); break;
case 6: bits = pgm_read_byte_near(&console_font_6x8[(chr * 8) + i]); break;
@ -6697,10 +6703,12 @@ void WS2812FX::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
}
}
}
#endif
}
#define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8))
void WS2812FX::wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu
void Segment::wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu
#ifndef WLED_DISABLE_2D
// extract the fractional parts and derive their inverses
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
// calculate the intensities for each affected pixel
@ -6713,5 +6721,6 @@ void WS2812FX::wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c) { //awe
leds[xy].g = qadd8(leds[xy].g, c.g * wu[i] >> 8);
leds[xy].b = qadd8(leds[xy].b, c.b * wu[i] >> 8);
}
#endif
}
#undef WU_WEIGHT

File diff suppressed because it is too large Load Diff

View File

@ -199,7 +199,7 @@ void handleAnalog(uint8_t b)
if (aRead == 0) {
seg.setOption(SEG_OPTION_ON, 0); // off
} else {
seg.setOpacity(aRead, macroDoublePress[b]);
seg.setOpacity(aRead);
seg.setOption(SEG_OPTION_ON, 1);
}
// this will notify clients of update (websockets,mqtt,etc)

View File

@ -91,6 +91,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
Bus::setCCTBlend(strip.cctBlending);
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
#ifndef WLED_DISABLE_2D
// 2D Matrix Settings
JsonObject matrix = hw_led[F("matrix")];
if (!matrix.isNull()) {
@ -125,6 +126,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
strip.setUpMatrix();
}
#endif
JsonArray ins = hw_led["ins"];
@ -620,6 +622,7 @@ void serializeConfig() {
hw_led["fps"] = strip.getTargetFps();
hw_led[F("rgbwm")] = Bus::getAutoWhiteMode(); // global override
#ifndef WLED_DISABLE_2D
// 2D Matrix Settings
if (strip.isMatrix) {
JsonObject matrix = hw_led.createNestedObject(F("matrix"));
@ -641,6 +644,7 @@ void serializeConfig() {
pnl["s"] = strip.panel[i].serpentine;
}
}
#endif
JsonArray hw_led_ins = hw_led.createNestedArray("ins");

View File

@ -51,7 +51,7 @@ uint32_t color_add(uint32_t c1, uint32_t c2)
void setRandomColor(byte* rgb)
{
lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex);
lastRandomIndex = strip.getMainSegment().get_random_wheel_index(lastRandomIndex);
colorHStoRGB(lastRandomIndex*256,255,rgb);
}

View File

@ -226,9 +226,9 @@ void changeColor(uint32_t c, int16_t cct=-1)
if (isRGB) mask |= 0x00FFFFFF; // RGB
if (hasW) mask |= 0xFF000000; // white
if (hasW && !wSlider && (c & 0xFF000000)) { // segment has white channel & white channel is auto calculated & white specified
seg.setColor(0, c | 0xFFFFFF, i); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
if (isCCT && cct >= 0) seg.setCCT(cct, i);
seg.setColor(0, c | 0xFFFFFF); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
} else if (c & mask) seg.setColor(0, c & mask); // only apply if not black
if (isCCT && cct >= 0) seg.setCCT(cct);
}
setValuesFromFirstSelectedSeg();
} else {
@ -243,9 +243,9 @@ void changeColor(uint32_t c, int16_t cct=-1)
if (isRGB) mask |= 0x00FFFFFF; // RGB
if (hasW) mask |= 0xFF000000; // white
if (hasW && !wSlider && (c & 0xFF000000)) { // segment has white channel & white channel is auto calculated & white specified
seg.setColor(0, c | 0xFFFFFF, i); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
if (isCCT && cct >= 0) seg.setCCT(cct, i);
seg.setColor(0, c | 0xFFFFFF); // for accurate/brighter mode we fake white (since button may not set white color to 0xFFFFFF)
} else if (c & mask) seg.setColor(0, c & mask); // only apply if not black
if (isCCT && cct >= 0) seg.setCCT(cct);
setValuesFromMainSeg();
}
stateChanged = true;

View File

@ -72,7 +72,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
uint16_t spc = elem[F("spc")] | seg.spacing;
uint16_t of = seg.offset;
if (spc>0 && spc!=seg.spacing) strip.fill(BLACK, id); // clear spacing gaps
if (spc>0 && spc!=seg.spacing) seg.fill(BLACK); // clear spacing gaps
uint16_t len = 1;
if (stop > start) len = stop - start;
@ -88,18 +88,18 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
byte segbri = seg.opacity;
if (getVal(elem["bri"], &segbri)) {
if (segbri > 0) seg.setOpacity(segbri, id);
seg.setOption(SEG_OPTION_ON, segbri, id);
if (segbri > 0) seg.setOpacity(segbri);
seg.setOption(SEG_OPTION_ON, segbri);
}
bool on = elem["on"] | seg.getOption(SEG_OPTION_ON);
if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on;
seg.setOption(SEG_OPTION_ON, on, id);
seg.setOption(SEG_OPTION_ON, on);
bool frz = elem["frz"] | seg.getOption(SEG_OPTION_FREEZE);
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.getOption(SEG_OPTION_FREEZE);
seg.setOption(SEG_OPTION_FREEZE, frz, id);
seg.setOption(SEG_OPTION_FREEZE, frz);
seg.setCCT(elem["cct"] | seg.cct, id);
seg.setCCT(elem["cct"] | seg.cct);
JsonArray colarr = elem["col"];
if (!colarr.isNull())
@ -115,7 +115,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
int kelvin = colarr[i] | -1;
if (kelvin < 0) continue;
if (kelvin == 0) seg.setColor(i, 0, id);
if (kelvin == 0) seg.setColor(i, 0);
if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
colValid = true;
} else { //HEX string, e.g. "FFAA00"
@ -132,7 +132,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
if (!colValid) continue;
seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]), id);
seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]));
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
}
}
@ -152,10 +152,12 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
#ifndef WLED_DISABLE_2D
// 2D options
seg.setOption(SEG_OPTION_REVERSED_Y, elem[F("rY")] | seg.getOption(SEG_OPTION_REVERSED_Y));
seg.setOption(SEG_OPTION_MIRROR_Y , elem[F("mY")] | seg.getOption(SEG_OPTION_MIRROR_Y ));
seg.setOption(SEG_OPTION_TRANSPOSED, elem[F("tp")] | seg.getOption(SEG_OPTION_TRANSPOSED));
#endif
byte fx = seg.mode;
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
@ -173,7 +175,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
JsonArray iarr = elem[F("i")]; //set individual LEDs
if (!iarr.isNull()) {
uint8_t oldSegId = strip.setPixelSegment(id);
//uint8_t oldSegId = strip.setPixelSegment(id);
// set brightness immediately and disable transition
transitionDelayTemp = 0;
@ -183,7 +185,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
// freeze and init to black
if (!seg.getOption(SEG_OPTION_FREEZE)) {
seg.setOption(SEG_OPTION_FREEZE, true);
strip.fill(0);
seg.fill(0);
}
uint16_t start = 0, stop = 0;
@ -215,16 +217,16 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
if (set < 2) stop = start + 1;
for (uint16_t i = start; i < stop; i++) {
if (strip.gammaCorrectCol) {
strip.setPixelColor(i, strip.gamma8(rgbw[0]), strip.gamma8(rgbw[1]), strip.gamma8(rgbw[2]), strip.gamma8(rgbw[3]));
seg.setPixelColor(i, strip.gamma8(rgbw[0]), strip.gamma8(rgbw[1]), strip.gamma8(rgbw[2]), strip.gamma8(rgbw[3]));
} else {
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
seg.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
}
}
if (!set) start++;
set = 0;
}
}
strip.setPixelSegment(oldSegId);
//strip.setPixelSegment(oldSegId);
strip.trigger();
}
// send UDP if not in preset and something changed that is not just selection
@ -249,10 +251,10 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (bri && !onBefore) { // unfreeze all segments when turning on
for (uint8_t s=0; s < strip.getMaxSegments(); s++) {
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, false, s);
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, false);
}
if (realtimeMode && !realtimeOverride && useMainSegmentOnly) { // keep live segment frozen if live
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, true, strip.getMainSegmentId());
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, true);
}
}
@ -304,7 +306,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
realtimeOverride = root[F("lor")] | realtimeOverride;
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
if (realtimeMode && useMainSegmentOnly) {
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride, strip.getMainSegmentId());
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride);
}
if (root.containsKey("live")) {
@ -520,11 +522,13 @@ void serializeInfo(JsonObject root)
leds[F("maxseg")] = strip.getMaxSegments();
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
#ifndef WLED_DISABLE_2D
if (strip.isMatrix) {
JsonObject matrix = leds.createNestedObject("matrix");
matrix["w"] = strip.matrixWidth;
matrix["h"] = strip.matrixHeight;
}
#endif
uint8_t totalLC = 0;
JsonArray lcarr = leds.createNestedArray(F("seglc"));

View File

@ -41,8 +41,8 @@ void applyValuesToSelectedSegs()
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0, i); stateChanged = true;}
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1, i); stateChanged = true;}
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1); stateChanged = true;}
}
}

View File

@ -69,7 +69,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary)
} else {
DEBUG_PRINT(F("LX: segment "));
DEBUG_PRINTLN(segId);
strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]), segId);
strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
}
}
}

View File

@ -554,6 +554,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
releaseJSONBufferLock();
}
#ifndef WLED_DISABLE_2D
//2D panels
if (subPage == 10)
{
@ -577,6 +578,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
strip.setUpMatrix(); // will check limits
}
#endif
lastEditTime = millis();
if (subPage != 2 && !doReboot) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
@ -664,9 +666,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
if (pos > 0) {
byte segbri = getNumVal(&req, pos);
selseg.setOption(SEG_OPTION_ON, segbri, selectedSeg);
selseg.setOption(SEG_OPTION_ON, segbri);
if (segbri) {
selseg.setOpacity(segbri, selectedSeg);
selseg.setOpacity(segbri);
}
}
@ -769,7 +771,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) {
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
selseg.setColor(2, col2, selectedSeg); // defined above (SS= or main)
selseg.setColor(2, col2); // defined above (SS= or main)
stateChanged = true;
if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments
}
@ -798,14 +800,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (col0Changed) {
stateChanged = true;
uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]);
selseg.setColor(0, colIn0, selectedSeg);
selseg.setColor(0, colIn0);
if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments
}
if (col1Changed) {
stateChanged = true;
uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]);
selseg.setColor(1, colIn1, selectedSeg);
selseg.setColor(1, colIn1);
if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments
}
@ -925,7 +927,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
realtimeOverride = getNumVal(&req, pos);
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
if (realtimeMode && useMainSegmentOnly) {
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride, strip.getMainSegmentId());
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, !realtimeOverride);
}
}

View File

@ -146,7 +146,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
Segment& mainseg = strip.getMainSegment();
start = mainseg.start;
stop = mainseg.stop;
mainseg.setOption(SEG_OPTION_FREEZE, true, strip.getMainSegmentId());
mainseg.setOption(SEG_OPTION_FREEZE, true);
} else {
start = 0;
stop = strip.getLengthTotal();
@ -156,7 +156,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
// if WLED was off and using main segment only, freeze non-main segments so they stay off
if (useMainSegmentOnly && bri == 0) {
for (uint8_t s=0; s < strip.getMaxSegments(); s++) {
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, true, s);
strip.getSegment(s).setOption(SEG_OPTION_FREEZE, true);
}
}
}
@ -183,7 +183,7 @@ void exitRealtime() {
realtimeMode = REALTIME_MODE_INACTIVE; // inform UI immediately
realtimeIP[0] = 0;
if (useMainSegmentOnly) { // unfreeze live segment again
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, false, strip.getMainSegmentId());
strip.getMainSegment().setOption(SEG_OPTION_FREEZE, false);
}
updateInterfaces(CALL_MODE_WS_SEND);
}
@ -351,8 +351,8 @@ void handleNotifications()
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset);
continue;
}
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01, id); //only take into account mirrored, selected, on, reversed
selseg.setOpacity(udpIn[10+ofs], id);
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
selseg.setOpacity(udpIn[10+ofs]);
if (applyEffects) {
strip.setMode(id, udpIn[11+ofs]);
selseg.speed = udpIn[12+ofs];
@ -360,10 +360,10 @@ void handleNotifications()
selseg.palette = udpIn[14+ofs];
}
if (receiveNotificationColor || !someSel) {
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]), id);
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]), id);
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]), id);
selseg.setCCT(udpIn[27+ofs], id);
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]));
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]));
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]));
selseg.setCCT(udpIn[27+ofs]);
}
//setSegment() also properly resets segments
if (receiveSegmentBounds) {

View File

@ -238,14 +238,13 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
char lineBuffer[256];
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode])));
strcpy_P(lineBuffer, strip.getModeData(mode));
if (strlen(lineBuffer) > 0) {
size_t j = 0;
for (; j < maxLen; j++) {
if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') break;
dest[j] = lineBuffer[j];
}
dest[j] = 0; // terminate string
size_t len = strlen(lineBuffer);
size_t j = 0;
for (; j < maxLen && j < len; j++) {
if (lineBuffer[j] == '\0' || lineBuffer[j] == '@') break;
dest[j] = lineBuffer[j];
}
dest[j] = 0; // terminate string
return strlen(dest);
} else return 0;
}

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2207041
#define VERSION 2207081
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@ -152,19 +152,19 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
#define PSRAMDynamicJsonDocument DynamicJsonDocument
#endif
#include "const.h"
#include "fcn_declare.h"
#include "html_ui.h"
#ifdef WLED_ENABLE_SIMPLE_UI
#include "html_simple.h"
#include "html_simple.h"
#endif
#include "html_settings.h"
#include "html_other.h"
#include "FX.h"
#include "ir_codes.h"
#include "const.h"
#include "NodeStruct.h"
#include "pin_manager.h"
#include "bus_manager.h"
#include "FX.h"
#ifndef CLIENT_SSID
#define CLIENT_SSID DEFAULT_CLIENT_SSID

View File

@ -636,6 +636,7 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == 10) // 2D matrices
{
sappend('v',SET_F("SOMP"),strip.isMatrix);
#ifndef WLED_DISABLE_2D
oappend(SET_F("resetPanels();"));
if (strip.isMatrix) {
sappend('v',SET_F("PH"),strip.panelH);
@ -660,5 +661,8 @@ void getSettingsJS(byte subPage, char* dest)
pO[l] = 'S'; sappend('c',pO,strip.panel[i].serpentine);
}
}
#else
oappend(SET_F("gId(\"somp\").remove(1);")); // remove 2D option from dropdown
#endif
}
}