Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Effect blending styles #3877

Open
wants to merge 16 commits into
base: 0_15
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
- v0.15.0-b2
- WS2805 support (RGB + WW + CW, 600kbps)
- Unified PSRAM use
- NeoPixelBus v2.7.9
- NeoPixelBus v2.7.9 (for future WS2805 support)
- Ubiquitous PSRAM mode for all variants of ESP32
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
Expand Down
2 changes: 1 addition & 1 deletion usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void setup() {
jsonTransitionOnce = true;
strip.setTransition(0); //no transition
effectCurrent = FX_MODE_COLOR_WIPE;
resetTimebase(); //make sure wipe starts from beginning
strip.resetTimebase(); //make sure wipe starts from beginning

//set wipe direction
Segment& seg = strip.getSegment(0);
Expand Down
111 changes: 0 additions & 111 deletions usermods/stairway_wipe_basic/wled06_usermod.ino

This file was deleted.

35 changes: 31 additions & 4 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,25 @@

#define MODE_COUNT 187


#define BLEND_STYLE_FADE 0
#define BLEND_STYLE_FAIRY_DUST 1
#define BLEND_STYLE_SWIPE_RIGHT 2
#define BLEND_STYLE_SWIPE_LEFT 3
#define BLEND_STYLE_PINCH_OUT 4
#define BLEND_STYLE_INSIDE_OUT 5
#define BLEND_STYLE_SWIPE_UP 6
#define BLEND_STYLE_SWIPE_DOWN 7
#define BLEND_STYLE_OPEN_H 8
#define BLEND_STYLE_OPEN_V 9
#define BLEND_STYLE_PUSH_TL 10
#define BLEND_STYLE_PUSH_TR 11
#define BLEND_STYLE_PUSH_BR 12
#define BLEND_STYLE_PUSH_BL 13

#define BLEND_STYLE_COUNT 14


typedef enum mapping1D2D {
M12_Pixels = 0,
M12_pBar = 1,
Expand Down Expand Up @@ -425,6 +444,9 @@ typedef struct Segment {
static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF
#ifndef WLED_DISABLE_MODE_BLEND
static bool _modeBlend; // mode/effect blending semaphore
// clipping
static uint16_t _clipStart, _clipStop;
static uint8_t _clipStartY, _clipStopY;
#endif

// transition data, valid only if transitional==true, holds values during transition (72 bytes)
Expand All @@ -435,6 +457,7 @@ typedef struct Segment {
#else
uint32_t _colorT[NUM_COLORS];
#endif
uint8_t _palTid; // previous palette
uint8_t _briT; // temporary brightness
uint8_t _cctT; // temporary CCT
CRGBPalette16 _palT; // temporary palette
Expand Down Expand Up @@ -572,6 +595,7 @@ typedef struct Segment {
uint16_t progress(void); // transition progression between 0-65535
uint8_t currentBri(bool useCct = false); // current segment brightness/CCT (blended while in transition)
uint8_t currentMode(void); // currently active effect/mode (while in transition)
uint8_t currentPalette(void); // currently active palette (while in transition)
uint32_t currentColor(uint8_t slot); // currently active segment color (blended while in transition)
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
void setCurrentPalette(void);
Expand All @@ -587,6 +611,10 @@ typedef struct Segment {
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
#endif
#ifndef WLED_DISABLE_MODE_BLEND
static inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; };
#endif
bool isPixelClipped(int i);
uint32_t getPixelColor(int i);
// 1D support functions (some implement 2D as well)
void blur(uint8_t, bool smear = false);
Expand Down Expand Up @@ -618,6 +646,7 @@ typedef struct Segment {
inline 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); }
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
#endif
bool isPixelXYClipped(int x, int y);
uint32_t getPixelColorXY(int x, int y);
// 2D support functions
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
Expand Down Expand Up @@ -656,6 +685,7 @@ typedef struct Segment {
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
#endif
inline bool isPixelXYClipped(int x, int y) { return isPixelClipped(x); }
inline uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(x); }
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
Expand Down Expand Up @@ -699,9 +729,7 @@ class WS2812FX { // 96 bytes
public:

WS2812FX() :
paletteFade(0),
paletteBlend(0),
cctBlending(0),
now(millis()),
timebase(0),
isMatrix(false),
Expand Down Expand Up @@ -782,6 +810,7 @@ class WS2812FX { // 96 bytes
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name), // add effect to the list; defined in FX.cpp
setupEffectData(void); // add default effects to the list; defined in FX.cpp

inline void resetTimebase() { timebase = 0U - millis(); }
inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); }
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
Expand All @@ -796,7 +825,6 @@ class WS2812FX { // 96 bytes
inline void resume(void) { _suspend = false; } // will resume strip.service() execution

bool
paletteFade,
checkSegmentAlignment(void),
hasRGBWBus(void),
hasCCTBus(void),
Expand All @@ -812,7 +840,6 @@ class WS2812FX { // 96 bytes

uint8_t
paletteBlend,
cctBlending,
getActiveSegmentsNum(void),
getFirstSelectedSegId(void),
getLastActiveSegmentId(void),
Expand Down
35 changes: 33 additions & 2 deletions wled00/FX_2Dfcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,41 @@ uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y)
return isActive() ? (x%width) + (y%height) * width : 0;
}

// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false)
// if clipping start > stop the clipping range is inverted
// _modeBlend==true -> old effect during transition
// _modeBlend==false -> new effect during transition
bool IRAM_ATTR Segment::isPixelXYClipped(int x, int y) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) {
const bool invertX = _clipStart > _clipStop;
const bool invertY = _clipStartY > _clipStopY;
const int startX = invertX ? _clipStop : _clipStart;
const int stopX = invertX ? _clipStart : _clipStop;
const int startY = invertY ? _clipStopY : _clipStartY;
const int stopY = invertY ? _clipStartY : _clipStopY;
if (blendingStyle == BLEND_STYLE_FAIRY_DUST) {
const unsigned width = stopX - startX; // assumes full segment width (faster than virtualWidth())
const unsigned len = width * (stopY - startY); // assumes full segment height (faster than virtualHeight())
if (len < 2) return false;
const unsigned shuffled = hashInt(x + y * width) % len;
const unsigned pos = (shuffled * 0xFFFFU) / len;
return progress() <= pos;
}
bool xInside = (x >= startX && x < stopX); if (invertX) xInside = !xInside;
bool yInside = (y >= startY && y < stopY); if (invertY) yInside = !yInside;
const bool clip = (invertX && invertY) ? !_modeBlend : _modeBlend;
if (xInside && yInside) return clip; // covers window & corners (inverted)
return !clip;
}
#endif
return false;
}

void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
{
if (!isActive()) return; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
if (x >= virtualWidth() || y >= virtualHeight() || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit

uint8_t _bri_t = currentBri();
if (_bri_t < 255) {
Expand Down Expand Up @@ -263,7 +294,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
// returns RGBW values of pixel
uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) {
if (!isActive()) return 0; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0 || isPixelXYClipped(x,y)) return 0; // if pixel would fall out of virtual segment just exit
if (reverse ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed
Expand Down
Loading