Skip to content

Commit

Permalink
Use custom color converter for HSL, to make color more accurate
Browse files Browse the repository at this point in the history
  • Loading branch information
DrA1ex committed Sep 6, 2024
1 parent 49a163a commit a78b652
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 11 deletions.
17 changes: 10 additions & 7 deletions src/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "fx/palette.h"

#include "misc/ntp_time.h"
#include "utils/color.h"
#include "utils/palette.h"


Expand Down Expand Up @@ -158,9 +159,14 @@ void Application::change_color(uint32_t color) {
preset.color_effect = ColorEffectEnum::SOLID;
config.preset_id = preset_index;

auto hsv = rgb2hsv_approximate(color);
preset.speed = hsv.hue;
preset.scale = hsv.sat;
auto rgb = CRGB(color);
auto hsv = RGBToHSL(color);

D_PRINTF("Change Color: RGB: #%0.2x%0.2x%0.2x, HSL: (%uº, %u%%, %u%%)\n", rgb.r, rgb.g, rgb.b,
hsv.h * 360 / 255, hsv.s * 100 / 255, hsv.l * 100 / 255);

preset.speed = hsv.h;
preset.scale = hsv.s;

load();
}
Expand All @@ -170,10 +176,7 @@ uint32_t Application::current_color() {
auto &preset = preset_configs.presets[preset_index];

if (preset.color_effect == ColorEffectEnum::SOLID) {
CRGB color{};
hsv2rgb_rainbow(CHSV(preset.speed, preset.scale, 255), color);

return static_cast<uint32_t>(color) & 0xffffff;
return HSLToRGB({preset.speed, preset.scale, 127});
}

return 0xffffff;
Expand Down
5 changes: 2 additions & 3 deletions src/fx/color_efect.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#include "color_effect.h"

#include "sys_macro.h"

#include "misc/led.h"
#include "utils/palette.h"
#include "utils/color.h"

ColorEffectManager::ColorEffectManager() {
static constexpr std::initializer_list<ColorEffectEntry> fx_init = {
Expand Down Expand Up @@ -81,7 +80,7 @@ void ColorEffectManager::solid(Led &led, ColorEffectState &state) {
gamma_correction, gamma
] = state.params;

auto color = CHSV(speed, scale, 255);
auto color = HSLToRGB({speed, scale, 127});

led.fill_solid(color);
if (gamma_correction) led.apply_gamma_correction(gamma);
Expand Down
3 changes: 2 additions & 1 deletion src/network/protocol/server/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ void ApiWebServer::begin(WebServer &server) {

return response_with_json(request, JsonPropListT{
{"status", "ok"},
{"value", color}
{"value", color},
{"rgb", String(color, 16).c_str()}
});
}

Expand Down
80 changes: 80 additions & 0 deletions src/utils/color.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#pragma once

#include <algorithm>
#include <cstdint>
#include <cmath>

struct HSL {
uint8_t h;
uint8_t s;
uint8_t l;
};

inline HSL RGBToHSL(uint32_t rgb) {
// Extract the red, green, and blue components
uint8_t r = (rgb >> 16) & 0xFF;
uint8_t g = (rgb >> 8) & 0xFF;
uint8_t b = rgb & 0xFF;

// Normalize the values to [0, 1]
float rN = r / 255.0f;
float gN = g / 255.0f;
float bN = b / 255.0f;

float maxC = std::max({ rN, gN, bN });
float minC = std::min({ rN, gN, bN });
float delta = maxC - minC;

float h = 0, s = 0, l = (maxC + minC) / 2;

if (delta > 0) {
if (maxC == rN) {
h = fmod(((gN - bN) / delta), 6.0);
} else if (maxC == gN) {
h = ((bN - rN) / delta) + 2.0;
} else {
h = ((rN - gN) / delta) + 4.0;
}
h *= 60.0;
if (h < 0) h += 360;

s = (maxC == 0) ? 0 : (delta / (1 - std::abs(2 * l - 1)));
}

return HSL{
static_cast<uint8_t>(h / 360.0 * 255), // Normalize h to [0, 255]
static_cast<uint8_t>(s * 255), // Normalize s to [0, 255]
static_cast<uint8_t>(l * 255) // Normalize l to [0, 255]
};
}

inline uint32_t HSLToRGB(const HSL& hsl) {
float h = hsl.h / 255.0f * 360; // Normalize back to [0, 360]
float s = hsl.s / 255.0f; // Normalize to [0, 1]
float l = hsl.l / 255.0f; // Normalize to [0, 1]

float c = (1 -std::abs(2 * l - 1)) * s; // Chroma
float x = c * (1 - std::abs(fmod(h / 60.0, 2) - 1));
float m = l - (c / 2);

float rN, gN, bN;
if (h < 60) {
rN = c; gN = x; bN = 0;
} else if (h < 120) {
rN = x; gN = c; bN = 0;
} else if (h < 180) {
rN = 0; gN = c; bN = x;
} else if (h < 240) {
rN = 0; gN = x; bN = c;
} else if (h < 300) {
rN = x; gN = 0; bN = c;
} else {
rN = c; gN = 0; bN = x;
}

uint8_t r = static_cast<uint8_t>((rN + m) * 255);
uint8_t g = static_cast<uint8_t>((gN + m) * 255);
uint8_t b = static_cast<uint8_t>((bN + m) * 255);

return (r << 16) | (g << 8) | b; // Combine r, g, b into a uint32_t
}

0 comments on commit a78b652

Please sign in to comment.