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

added function to generate random palette based on harmonic color theory #3729

Merged
merged 11 commits into from
Feb 6, 2024
11 changes: 3 additions & 8 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = CRGBPalette16(DEFAULT_COLOR);
CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR);
CRGBPalette16 Segment::_randomPalette = generateRandomPalette(_randomPalette);
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(_randomPalette);
unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment

#ifndef WLED_DISABLE_MODE_BLEND
Expand Down Expand Up @@ -223,12 +223,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint
case 1: {//periodically replace palette with a random one
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);
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
_lastPaletteChange = millis();
handleRandomPalette(); // do a 1st pass of blend
}
Expand Down
107 changes: 107 additions & 0 deletions wled00/colors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,113 @@ 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
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
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
DedeHai marked this conversation as resolved.
Show resolved Hide resolved

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;
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
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
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
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];
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
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
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
palettecolors[i].hue = harmonics[j];
j++;
}

//apply gamma correction
CRGB RGBpalettecolors[4];
for (int i = 0; i<4; i++) {
RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB
RGBpalettecolors[i] = gamma32((uint32_t)RGBpalettecolors[i]);
blazoncek marked this conversation as resolved.
Show resolved Hide resolved
}

return CRGBPalette16( RGBpalettecolors[0],
RGBpalettecolors[1],
RGBpalettecolors[2],
RGBpalettecolors[3]);

}

void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
{
float h = ((float)hue)/65535.0f;
Expand Down
1 change: 1 addition & 0 deletions wled00/fcn_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,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);
Expand Down
3 changes: 3 additions & 0 deletions wled00/wled.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
#define PSRAMDynamicJsonDocument DynamicJsonDocument
#endif

#define FASTLED_INTERNAL //remove annoying pragma messages
#define USE_GET_MILLISECOND_TIMER
#include "FastLED.h"
#include "const.h"
DedeHai marked this conversation as resolved.
Show resolved Hide resolved
#include "fcn_declare.h"
#include "NodeStruct.h"
Expand Down