From ca05aa84ff0d94851c688493f1d9d74f699a9b6f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 30 Jan 2024 22:28:40 +0100 Subject: [PATCH] changed randomness and added optimizations -added fully random palette function ('the old way', currently just used for initialization) -changed randomness values to make it a little less random -added 10% chance for pastel color palette -now using swap() from std library for shuffeling -changed function name -moved update check from loadPalette() to handleRandomPalette() saving CPU cycles --- wled00/FX_fcn.cpp | 26 ++++++------ wled00/colors.cpp | 99 ++++++++++++++++++++++++-------------------- wled00/fcn_declare.h | 3 +- 3 files changed, 69 insertions(+), 59 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 1b8c09aaa..bb260bf2e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -77,8 +77,8 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; -CRGBPalette16 Segment::_randomPalette = generateRandomPalette(_randomPalette); -CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(_randomPalette); +CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); +CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) @@ -222,13 +222,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; case 1: {//periodically replace palette with a random one - if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { - _newRandomPalette = generateRandomPalette(_randomPalette); - _lastPaletteChange = millis()/1000U; - _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately - handleRandomPalette(); // do a 1st pass of blend - } - targetPalette = _randomPalette; + targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette() break;} case 2: {//primary color only CRGB prim = gamma32(colors[0]); @@ -463,11 +457,17 @@ void Segment::handleRandomPalette() { // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) // this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY) // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) - if(strip.paletteFade) + + if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { + _newRandomPalette = generateHarmonicRandomPalette(_randomPalette); + _lastPaletteChange = millis()/1000U; + _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately + } + + if (strip.paletteFade) { - if((millis()&0xFFFF) - _lastPaletteBlend < strip.getTransition()>>7) //assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) - { - return; //not time to fade yet + if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) {//assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) + return; //not time to fade yet, delay the update } _lastPaletteBlend = millis(); } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 9f16d1290..5daeb1f28 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -92,42 +92,33 @@ void setRandomColor(byte* rgb) } /* - *generates a random palette based on color theory + *generates a random palette based on harmonic color theory + *takes a base palette as the input, it will choose one color of the base palette and keep it */ -CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) +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].hue += random8(20)-10; // +/- 10 randomness + 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 //only one brightness value number is allowed below 200, creating mostly bright palettes - for (int i = 0; i<3; i++) { //generate three high values - palettecolors[i].saturation = random8(180,255); - palettecolors[i].value = random8(180,255); + for (int i = 0; i < 3; i++) { //generate three high values + palettecolors[i].saturation = random8(200,255); + palettecolors[i].value = random8(220,255); } //allow one to be lower palettecolors[3].saturation = random8(80,255); - palettecolors[3].value = random8(50,255); + palettecolors[3].value = random8(80,255); - //shuffle the arrays using Fisher-Yates algorithm - for (int i = 3; i > 0; i--) { - uint8_t j = random8(0, i + 1); - //swap [i] and [j] - uint8_t temp = palettecolors[i].saturation; - palettecolors[i].saturation = palettecolors[j].saturation; - palettecolors[j].saturation = temp; - } + //shuffle the arrays for (int i = 3; i > 0; i--) { - uint8_t j = random8(0, i + 1); - //swap [i] and [j] - uint8_t temp = palettecolors[i].value; - palettecolors[i].value = palettecolors[j].value; - palettecolors[j].value = temp; + std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); + std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value); } //now generate three new hues based off of the hue of the chosen current color @@ -143,50 +134,58 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) break; case 1: // triadic - harmonics[0] = basehue + 110 + random8(20); - harmonics[1] = basehue + 230 + random8(20); - harmonics[2] = basehue + random8(30)-15; + harmonics[0] = basehue + 113 + random8(15); + harmonics[1] = basehue + 233 + random8(15); + harmonics[2] = basehue -7 + random8(15); break; case 2: // split-complementary - harmonics[0] = basehue + 140 + random8(20); - harmonics[1] = basehue + 200 + random8(20); - harmonics[2] = basehue + random8(30)-15; + harmonics[0] = basehue + 145 + random8(10); + harmonics[1] = basehue + 205 + random8(10); + harmonics[2] = basehue - 5 + random8(10); break; + + case 3: // square + harmonics[0] = basehue + 85 + random8(10); + harmonics[1] = basehue + 175 + random8(10); + harmonics[2] = basehue + 265 + random8(10); + break; - case 3: // tetradic + case 4: // tetradic harmonics[0] = basehue + 80 + random8(20); harmonics[1] = basehue + 170 + random8(20); harmonics[2] = basehue + random8(30)-15; - break; - - case 4: // square - harmonics[0] = basehue + 80 + random8(20); - harmonics[1] = basehue + 170 + random8(20); - harmonics[2] = basehue + 260 + random8(20); - break; + break; } - //shuffle the hues: - for (int i = 2; i > 0; i--) { - uint8_t j = random8(0, i + 1); - //swap [i] and [j] - uint8_t temp = harmonics[i]; - harmonics[i] = harmonics[j]; - harmonics[j] = temp; + + if (random8() < 128) //50:50 chance of shuffeling hues or keep the color order + { + //shuffle the hues: + for (int i = 2; i > 0; i--) { + std::swap(harmonics[i], harmonics[random8(i + 1)]); + } } //now set the hues - int j=0; - for (int i = 0; i<4; i++) { + int j = 0; + for (int i = 0; i < 4; i++) { if(i==keepcolorposition) continue; //skip the base color palettecolors[i].hue = harmonics[j]; j++; } - //apply gamma correction + bool makepastelpalette = false; + if (random8() < 25) {//~10% chance of desaturated 'pastel' colors + makepastelpalette = true; + } + + //apply saturation & gamma correction CRGB RGBpalettecolors[4]; - for (int i = 0; i<4; i++) { + for (int i = 0; i < 4; i++) { + if(makepastelpalette && palettecolors[i].saturation > 180) { + palettecolors[i].saturation -= 160; //desaturate all four colors + } RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB RGBpalettecolors[i] = gamma32((uint32_t)RGBpalettecolors[i]); } @@ -195,7 +194,17 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) RGBpalettecolors[1], RGBpalettecolors[2], RGBpalettecolors[3]); +} +CRGBPalette16 generateRandomPalette(void) //generate fully random palette +{ + CRGBPalette16 random = CRGBPalette16( + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255))); + + return generateHarmonicRandomPalette(random); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ff3718461..e664e1706 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -65,7 +65,8 @@ class NeoGammaWLEDMethod { uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); uint32_t color_add(uint32_t,uint32_t, bool fast=false); uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette); +CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); +CRGBPalette16 generateRandomPalette(void); 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 void colorKtoRGB(uint16_t kelvin, byte* rgb);