diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index eeaa2c1e1..c7fb7815d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -224,11 +224,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint unsigned long timeSinceLastChange = millis() - _lastPaletteChange; if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { _randomPalette = _newRandomPalette; - _newRandomPalette = 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))); + _newRandomPalette = generateRandomPalette(&_randomPalette); _lastPaletteChange = millis(); handleRandomPalette(); // do a 1st pass of blend } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 21c27d651..8dcc735c3 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -91,6 +91,106 @@ void setRandomColor(byte* rgb) colorHStoRGB(lastRandomIndex*256,255,rgb); } +/* + *generates a random palette based on color theory + */ + +CRGBPalette16 generateRandomPalette(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 + //generate 4 saturation and brightness value numbers + //only one saturation is allowed to be below 200 creating mostly vibrant colors + //only one brigthness value number is allowed to 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); + } + //allow one to be lower + palettecolors[3].saturation = random8(80,255); + palettecolors[3].value = random8(50,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; + } + + 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; + } + + //now generate three new hues based off of the hue of the chosen current color + uint8_t basehue = palettecolors[keepcolorposition].hue; + uint8_t harmonics[3]; //hues that are harmonic but still a littl random + uint8_t type = random8(5); //choose a harmony type + + switch (type) { + case 0: // analogous + harmonics[0] = basehue + random8(30, 50); + harmonics[1] = basehue + random8(10, 30); + harmonics[2] = basehue - random8(10, 30); + break; + + case 1: // triadic + harmonics[0] = basehue + 110 + random8(20); + harmonics[1] = basehue + 230 + random8(20); + harmonics[2] = basehue + random8(30)-15; + break; + + case 2: // split-complementary + harmonics[0] = basehue + 140 + random8(20); + harmonics[1] = basehue + 200 + random8(20); + harmonics[2] = basehue + random8(30)-15; + break; + + case 3: // 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; + } + + //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; + } + + //now set the hues + int j=0; + for (int i = 0; i<4; i++) { + if(i==keepcolorposition) continue; //skip the base color + palettecolors[i].hue = harmonics[j]; + j++; + } + + return CRGBPalette16( palettecolors[0], + palettecolors[1], + palettecolors[2], + palettecolors[3]); + +} + void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb { float h = ((float)hue)/65535.0f; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index e256ceb5f..3eda4ff82 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -1,6 +1,7 @@ #ifndef WLED_FCN_DECLARE_H #define WLED_FCN_DECLARE_H +#include "FastLED.h" /* * All globally accessible functions are declared here */ @@ -65,6 +66,7 @@ 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); 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);