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

Copy Segment FX #4124

Open
wants to merge 11 commits into
base: 0_15
Choose a base branch
from
33 changes: 33 additions & 0 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static um_data_t* getAudioData() {
return um_data;
}


// effect functions

/*
Expand All @@ -93,6 +94,37 @@ 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._segments.size() || sourceid == strip.getCurrSegmentId()) { // invalid source
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
SEGMENT.fadeToBlackBy(5); // fade out, clears pixels and allows overlapping segments
return FRAMETIME;
}
if (strip._segments[sourceid].isActive()) {
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
uint32_t sourcecolor;
if(!strip._segments[sourceid].is2D()) { // 1D source, source can be expanded into 2D
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
uint32_t cl; // length to copy
for (unsigned i = 0; i < SEGMENT.virtualLength(); i++) {
sourcecolor = SEGMENT.getRenderedPixelXY(strip._segments[sourceid], i);
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
SEGMENT.setPixelColor(i, adjust_color(sourcecolor, SEGMENT.intensity, SEGMENT.custom1, SEGMENT.custom2));
}
} 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 = SEGMENT.getRenderedPixelXY(strip._segments[sourceid], y, x); // flip axis (for 2D -> 1D, in 2D Segments this does the same as 'Transpose')
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
else sourcecolor = SEGMENT.getRenderedPixelXY(strip._segments[sourceid], x, y);
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
SEGMENT.setPixelColorXY(x, y, adjust_color(sourcecolor, SEGMENT.intensity, SEGMENT.custom1, SEGMENT.custom2));
}
}
}
}
return FRAMETIME;
}
static const char _data_FX_MODE_COPY[] PROGMEM = "Copy Segment@,Color shift,Lighten,Brighten,ID,,Switch axis(2D);;;1;ix=0,c1=0,c2=0,c3=0,o2=0";


/*
* Blink/strobe function
Expand Down Expand Up @@ -7830,6 +7862,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
5 changes: 3 additions & 2 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,8 @@
#define FX_MODE_WAVESINS 184
#define FX_MODE_ROCKTAVES 185
#define FX_MODE_2DAKEMI 186

#define MODE_COUNT 187
#define FX_MODE_COPY 187
#define MODE_COUNT 188

typedef enum mapping1D2D {
M12_Pixels = 0,
Expand Down Expand Up @@ -588,6 +588,7 @@ typedef struct Segment {
inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
#endif
[[gnu::hot]] uint32_t getPixelColor(int i) const;
uint32_t getRenderedPixelXY(Segment& seg, unsigned x, unsigned y = 0);
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
// 1D support functions (some implement 2D as well)
void blur(uint8_t, bool smear = false);
void fill(uint32_t c);
Expand Down
12 changes: 12 additions & 0 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,18 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
return strip.getPixelColor(i);
}

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

uint8_t Segment::differs(Segment& b) const {
uint8_t d = 0;
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
Expand Down
45 changes: 44 additions & 1 deletion wled00/colors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,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
CHSV hsv = rgb2hsv(rgb); //convert to HSV
if(hsv.v == 0) return rgb; // do not change black pixels
hsv.h += hueShift; // shift hue
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
CRGB adjusted;
hsv2rgb_spectrum(hsv, adjusted); // convert back to RGB
return RGBW32(adjusted.r,adjusted.g,adjusted.b,0);
}

void setRandomColor(byte* rgb)
{
lastRandomIndex = get_random_wheel_index(lastRandomIndex);
Expand All @@ -105,7 +122,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
{
CHSV palettecolors[4]; //array of colors for the new palette
uint8_t keepcolorposition = random8(4); //color position of current random palette to keep
palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette
palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette
palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color
//generate 4 saturation and brightness value numbers
//only one saturation is allowed to be below 200 creating mostly vibrant colors
Expand Down Expand Up @@ -228,6 +245,32 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
}
}

CHSV rgb2hsv(const uint32_t rgb) // convert rgb to hsv, more accurate and faster than fastled version
{
CHSV hsv = CHSV(0, 0, 0);
int32_t r = (rgb>>16)&0xFF;
int32_t g = (rgb>>8)&0xFF;
int32_t b = rgb&0xFF;
int32_t minval, maxval, delta;
minval = min(r, g);
minval = min(minval, b);
maxval = max(r, g);
maxval = max(maxval, b);
if (maxval == 0) return hsv; // black
hsv.v = maxval;
delta = maxval - minval;
hsv.s = (255 * delta) / maxval;
if (hsv.s == 0) return hsv; // gray value
int32_t h; //calculate hue
if (maxval == r)
h = (43 * (g - b)) / delta;
else if (maxval == g) h = 85 + (43 * (b - r)) / delta;
else h = 171 + (43 * (r - g)) / delta;
if(h < 0) h += 256;
hsv.h = h;
return hsv;
}

//get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc
{
Expand Down
3 changes: 3 additions & 0 deletions wled00/fcn_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,13 @@ class NeoGammaWLEDMethod {
[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false);
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
uint32_t adjust_color(uint32_t rgb, uint32_t hueShift, uint32_t lighten, uint32_t brighten);
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
CRGBPalette16 generateRandomPalette();
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
CHSV rgb2hsv(const uint32_t rgb); // rgb to hsv
inline CHSV rgb2hsv(const CRGB c) { return rgb2hsv((uint32_t((byte(c.r) << 16) | (byte(c.g) << 8) | (byte(c.b))))); } // CRGB to hsv
void colorKtoRGB(uint16_t kelvin, byte* rgb);
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
Expand Down