Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
44 changes: 44 additions & 0 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static um_data_t* getAudioData() {
return um_data;
}


// effect functions

/*
Expand All @@ -125,6 +126,48 @@ uint16_t mode_static(void) {
}
static const char _data_FX_MODE_STATIC[] PROGMEM = "Solid";

/*
* Copy a segment and perform (optional) color adjustments
*/
uint16_t mode_copy_segment(void) {
uint32_t sourceid = SEGMENT.custom3;
if (sourceid >= strip.getSegmentsNum() || sourceid == strip.getCurrSegmentId()) { // invalid source
SEGMENT.fadeToBlackBy(5); // fade out, clears pixels and allows overlapping segments
return FRAMETIME;
}
Segment sourcesegment = strip.getSegment(sourceid);
if (sourcesegment.isActive()) {
uint32_t sourcecolor;
if(!sourcesegment.is2D()) { // 1D source, source can be expanded into 2D
uint32_t cl; // length to copy
for (unsigned i = 0; i < SEGMENT.virtualLength(); i++) {
sourcecolor = strip.getRenderedPixelXY(sourceid, i);
uint32_t color = adjust_color(sourcecolor, SEGMENT.intensity, SEGMENT.custom1, SEGMENT.custom2);
if(SEGMENT.check3) // overlay
SEGMENT.addPixelColor(i, color);
else
SEGMENT.setPixelColor(i, color);
}
} else { // 2D source, note: 2D to 1D just copies the first row (or first column if 'Switch axis' is checked in FX)
for (unsigned y = 0; y < SEGMENT.virtualHeight(); y++) {
for (unsigned x = 0; x < SEGMENT.virtualWidth(); x++) {
if(SEGMENT.check2)
sourcecolor = strip.getRenderedPixelXY(sourceid, y, x); // flip reading axis (for 2D -> 1D, in 2D Segments this does the same as 'Transpose')
else
sourcecolor = strip.getRenderedPixelXY(sourceid, x, y);
uint32_t color = adjust_color(sourcecolor, SEGMENT.intensity, SEGMENT.custom1, SEGMENT.custom2);
if(SEGMENT.check3) // overlay
SEGMENT.addPixelColorXY(x, y, color);
else
SEGMENT.setPixelColorXY(x, y, color);
}
}
}
}
return FRAMETIME;
}
static const char _data_FX_MODE_COPY[] PROGMEM = "Copy Segment@,Color shift,Lighten,Brighten,ID,,Axis(2D),Overlay;;;12;ix=0,c1=0,c2=0,c3=0";


/*
* Blink/strobe function
Expand Down Expand Up @@ -10156,6 +10199,7 @@ void WS2812FX::setupEffectData() {
_modeData.push_back(_data_RESERVED);
}
// now replace all pre-allocated effects
addEffect(FX_MODE_COPY, &mode_copy_segment, _data_FX_MODE_COPY);
// --- 1D non-audio effects ---
addEffect(FX_MODE_BLINK, &mode_blink, _data_FX_MODE_BLINK);
addEffect(FX_MODE_BREATH, &mode_breath, _data_FX_MODE_BREATH);
Expand Down
2 changes: 2 additions & 0 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define FX_MODE_COLORTWINKLE 74
#define FX_MODE_LAKE 75
#define FX_MODE_METEOR 76
#define FX_MODE_COPY 77
//#define FX_MODE_METEOR_SMOOTH 77 // merged with meteor
#define FX_MODE_RAILWAY 78
#define FX_MODE_RIPPLE 79
Expand Down Expand Up @@ -933,6 +934,7 @@ class WS2812FX { // 96 bytes

unsigned long now, timebase;
uint32_t getPixelColor(unsigned i) const;
uint32_t getRenderedPixelXY(uint8_t segid, unsigned x, unsigned y = 0) const;

inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call

Expand Down
12 changes: 12 additions & 0 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,18 @@ uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const {
return BusManager::getPixelColor(i);
}

/*
* Read rendered pixel back (following mirror/reverse/transpose but ignoring grouping)
*/
uint32_t WS2812FX::getRenderedPixelXY(uint8_t segid, unsigned x, unsigned y) const {
// For every group-length pixels, add spacing
x *= _segments[segid].groupLength(); // expand to physical pixels
y *= _segments[segid].groupLength(); // expand to physical pixels
if (x >= _segments[segid].width() || y >= _segments[segid].height()) return 0; // fill out of range pixels with black
uint32_t offset = _segments[segid].is2D() ? 0 : _segments[segid].offset; //offset in 2D segments is undefined, set to zero
return strip.getPixelColorXY(_segments[segid].start + offset + x, _segments[segid].startY + y);
}

void WS2812FX::show() {
// avoid race condition, capture _callback value
show_callback callback = _callback;
Expand Down
17 changes: 17 additions & 0 deletions wled00/colors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
return scaledcolor;
}

/*
* color adjustment in HSV color space (converts RGB to HSV and back), color conversions are not 100% accurate!
shifts hue, increase brightness, decreases saturation (if not black)
note: inputs are 32bit to speed up the function, useful input value ranges are 0-255
*/
uint32_t adjust_color(uint32_t rgb, uint32_t hueShift, uint32_t lighten, uint32_t brighten) {
if(rgb == 0 | hueShift + lighten + brighten == 0) return rgb; // black or no change
CHSV32 hsv;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since CHSV32 is custom HSV class, I would suggest to incorporate constructor from RGBW32 and uint32_t which should hide explicit calls to HSV conversion.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constructor is implemented in #4615 but it uses the fastled equivalent "rainbow" conversion for nicer colors, however, here we want the technically correct spectrum conversion to avoid color shifts.

rgb2hsv(rgb, hsv); //convert to HSV
hsv.h += (hueShift << 8); // shift hue (hue is 16 bits)
hsv.s = max((int32_t)0, (int32_t)hsv.s - (int32_t)lighten); // desaturate
hsv.v = min((uint32_t)255, (uint32_t)hsv.v + brighten); // increase brightness
uint32_t rgb_adjusted;
hsv2rgb(hsv, rgb_adjusted); // convert back to RGB TODO: make this into 16 bit conversion
return rgb_adjusted;
}

// 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes)
uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType)
{
Expand Down
1 change: 1 addition & 0 deletions wled00/fcn_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ class NeoGammaWLEDMethod {
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
[[gnu::hot, gnu::pure]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
[[gnu::hot, gnu::pure]] uint32_t adjust_color(uint32_t rgb, uint32_t hueShift, uint32_t lighten, uint32_t brighten);
[[gnu::hot, gnu::pure]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette);
CRGBPalette16 generateRandomPalette();
Expand Down