Skip to content

Commit 2448266

Browse files
authored
Merge pull request wled#4158 from Aircoookie/blending-styles
Effect blending styles (recreated PR from wled#3877)
2 parents 4951be6 + 3a426e2 commit 2448266

File tree

19 files changed

+380
-242
lines changed

19 files changed

+380
-242
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
- v0.15.0-b2
174174
- WS2805 support (RGB + WW + CW, 600kbps)
175175
- Unified PSRAM use
176-
- NeoPixelBus v2.7.9
176+
- NeoPixelBus v2.7.9 (for future WS2805 support)
177177
- Ubiquitous PSRAM mode for all variants of ESP32
178178
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
179179
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)

usermods/stairway_wipe_basic/wled06_usermod.ino

Lines changed: 0 additions & 111 deletions
This file was deleted.

wled00/FX.h

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,30 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
325325

326326
#define MODE_COUNT 187
327327

328+
329+
#define BLEND_STYLE_FADE 0x00 // universal
330+
#define BLEND_STYLE_FAIRY_DUST 0x01 // universal
331+
#define BLEND_STYLE_SWIPE_RIGHT 0x02 // 1D or 2D
332+
#define BLEND_STYLE_SWIPE_LEFT 0x03 // 1D or 2D
333+
#define BLEND_STYLE_PINCH_OUT 0x04 // 1D or 2D
334+
#define BLEND_STYLE_INSIDE_OUT 0x05 // 1D or 2D
335+
#define BLEND_STYLE_SWIPE_UP 0x06 // 2D
336+
#define BLEND_STYLE_SWIPE_DOWN 0x07 // 2D
337+
#define BLEND_STYLE_OPEN_H 0x08 // 2D
338+
#define BLEND_STYLE_OPEN_V 0x09 // 2D
339+
// as there are many push variants to optimise if statements they are groupped together
340+
#define BLEND_STYLE_PUSH_RIGHT 0x10 // 1D or 2D (& 0b00010000)
341+
#define BLEND_STYLE_PUSH_LEFT 0x11 // 1D or 2D (& 0b00010000)
342+
#define BLEND_STYLE_PUSH_UP 0x12 // 2D (& 0b00010000)
343+
#define BLEND_STYLE_PUSH_DOWN 0x13 // 2D (& 0b00010000)
344+
#define BLEND_STYLE_PUSH_TL 0x14 // 2D (& 0b00010000)
345+
#define BLEND_STYLE_PUSH_TR 0x15 // 2D (& 0b00010000)
346+
#define BLEND_STYLE_PUSH_BR 0x16 // 2D (& 0b00010000)
347+
#define BLEND_STYLE_PUSH_BL 0x17 // 2D (& 0b00010000)
348+
#define BLEND_STYLE_PUSH_MASK 0x10
349+
#define BLEND_STYLE_COUNT 18
350+
351+
328352
typedef enum mapping1D2D {
329353
M12_Pixels = 0,
330354
M12_pBar = 1,
@@ -333,7 +357,7 @@ typedef enum mapping1D2D {
333357
M12_sPinwheel = 4
334358
} mapping1D2D_t;
335359

336-
// segment, 80 bytes
360+
// segment, 68 bytes
337361
typedef struct Segment {
338362
public:
339363
uint16_t start; // start index / start X coordinate 2D (left)
@@ -436,6 +460,9 @@ typedef struct Segment {
436460
static uint16_t _transitionprogress; // current transition progress 0 - 0xFFFF
437461
#ifndef WLED_DISABLE_MODE_BLEND
438462
static bool _modeBlend; // mode/effect blending semaphore
463+
// clipping
464+
static uint16_t _clipStart, _clipStop;
465+
static uint8_t _clipStartY, _clipStopY;
439466
#endif
440467

441468
// transition data, valid only if transitional==true, holds values during transition (72 bytes)
@@ -446,6 +473,7 @@ typedef struct Segment {
446473
#else
447474
uint32_t _colorT[NUM_COLORS];
448475
#endif
476+
uint8_t _palTid; // previous palette
449477
uint8_t _briT; // temporary brightness
450478
uint8_t _cctT; // temporary CCT
451479
CRGBPalette16 _palT; // temporary palette
@@ -607,6 +635,10 @@ typedef struct Segment {
607635
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) const { setPixelColor(i, RGBW32(r,g,b,w), aa); }
608636
inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
609637
#endif
638+
#ifndef WLED_DISABLE_MODE_BLEND
639+
static inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; };
640+
#endif
641+
bool isPixelClipped(int i) const;
610642
[[gnu::hot]] uint32_t getPixelColor(int i) const;
611643
// 1D support functions (some implement 2D as well)
612644
void blur(uint8_t, bool smear = false);
@@ -653,6 +685,7 @@ typedef struct Segment {
653685
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
654686
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
655687
#endif
688+
[[gnu::hot]] bool isPixelXYClipped(int x, int y) const;
656689
[[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const;
657690
// 2D support functions
658691
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
@@ -690,6 +723,7 @@ typedef struct Segment {
690723
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
691724
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
692725
#endif
726+
inline bool isPixelXYClipped(int x, int y) { return isPixelClipped(x); }
693727
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
694728
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
695729
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
@@ -734,9 +768,7 @@ class WS2812FX { // 96 bytes
734768
public:
735769

736770
WS2812FX() :
737-
paletteFade(0),
738771
paletteBlend(0),
739-
cctBlending(0),
740772
now(millis()),
741773
timebase(0),
742774
isMatrix(false),
@@ -824,7 +856,6 @@ class WS2812FX { // 96 bytes
824856
inline void resume() { _suspend = false; } // will resume strip.service() execution
825857

826858
bool
827-
paletteFade,
828859
checkSegmentAlignment() const,
829860
hasRGBWBus() const,
830861
hasCCTBus() const,
@@ -839,7 +870,6 @@ class WS2812FX { // 96 bytes
839870

840871
uint8_t
841872
paletteBlend,
842-
cctBlending,
843873
getActiveSegmentsNum() const,
844874
getFirstSelectedSegId() const,
845875
getLastActiveSegmentId() const,

wled00/FX_2Dfcn.cpp

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint
160160
const int baseY = startY + y;
161161
#ifndef WLED_DISABLE_MODE_BLEND
162162
// if blending modes, blend with underlying pixel
163-
if (_modeBlend) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
163+
if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
164164
#endif
165165
strip.setPixelColorXY(baseX, baseY, col);
166166

@@ -179,14 +179,57 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint
179179
}
180180
}
181181

182+
// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false)
183+
// if clipping start > stop the clipping range is inverted
184+
// _modeBlend==true -> old effect during transition
185+
// _modeBlend==false -> new effect during transition
186+
bool IRAM_ATTR_YN Segment::isPixelXYClipped(int x, int y) const {
187+
#ifndef WLED_DISABLE_MODE_BLEND
188+
if (_clipStart != _clipStop && blendingStyle != BLEND_STYLE_FADE) {
189+
const bool invertX = _clipStart > _clipStop;
190+
const bool invertY = _clipStartY > _clipStopY;
191+
const int startX = invertX ? _clipStop : _clipStart;
192+
const int stopX = invertX ? _clipStart : _clipStop;
193+
const int startY = invertY ? _clipStopY : _clipStartY;
194+
const int stopY = invertY ? _clipStartY : _clipStopY;
195+
if (blendingStyle == BLEND_STYLE_FAIRY_DUST) {
196+
const unsigned width = stopX - startX; // assumes full segment width (faster than virtualWidth())
197+
const unsigned len = width * (stopY - startY); // assumes full segment height (faster than virtualHeight())
198+
if (len < 2) return false;
199+
const unsigned shuffled = hashInt(x + y * width) % len;
200+
const unsigned pos = (shuffled * 0xFFFFU) / len;
201+
return progress() > pos;
202+
}
203+
bool xInside = (x >= startX && x < stopX); if (invertX) xInside = !xInside;
204+
bool yInside = (y >= startY && y < stopY); if (invertY) yInside = !yInside;
205+
const bool clip = (invertX && invertY) ? !_modeBlend : _modeBlend;
206+
if (xInside && yInside) return clip; // covers window & corners (inverted)
207+
return !clip;
208+
}
209+
#endif
210+
return false;
211+
}
212+
182213
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const
183214
{
184215
if (!isActive()) return; // not active
185216

186217
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
187218
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
188-
// negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH
189-
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit
219+
220+
#ifndef WLED_DISABLE_MODE_BLEND
221+
unsigned prog = 0xFFFF - progress();
222+
if (!prog && !_modeBlend && (blendingStyle & BLEND_STYLE_PUSH_MASK)) {
223+
unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF;
224+
unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF;
225+
if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x += dX;
226+
else x -= dX;
227+
if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY;
228+
else y += dY;
229+
}
230+
#endif
231+
232+
if (x >= vW || y >= vH || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit
190233

191234
// if color is unscaled
192235
if (!_colorScaled) col = color_fade(col, _segBri);
@@ -259,9 +302,24 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) const
259302
// returns RGBW values of pixel
260303
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
261304
if (!isActive()) return 0; // not active
305+
262306
const int vW = vWidth();
263307
const int vH = vHeight();
264-
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit
308+
309+
#ifndef WLED_DISABLE_MODE_BLEND
310+
unsigned prog = 0xFFFF - progress();
311+
if (!prog && !_modeBlend && (blendingStyle & BLEND_STYLE_PUSH_MASK)) {
312+
unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF;
313+
unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF;
314+
if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x -= dX;
315+
else x += dX;
316+
if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY;
317+
else y += dY;
318+
}
319+
#endif
320+
321+
if (x >= vW || y >= vH || x<0 || y<0 || isPixelXYClipped(x,y)) return 0; // if pixel would fall out of virtual segment just exit
322+
265323
if (reverse ) x = vW - x - 1;
266324
if (reverse_y) y = vH - y - 1;
267325
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed

0 commit comments

Comments
 (0)