From a78b652cea4024215c1b2c4c0ff7c69b0919e709 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 6 Sep 2024 21:15:32 +0500 Subject: [PATCH] Use custom color converter for HSL, to make color more accurate --- src/application.cpp | 17 +++--- src/fx/color_efect.cpp | 5 +- src/network/protocol/server/api.cpp | 3 +- src/utils/color.h | 80 +++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 src/utils/color.h diff --git a/src/application.cpp b/src/application.cpp index fab3419..6c4760a 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -7,6 +7,7 @@ #include "fx/palette.h" #include "misc/ntp_time.h" +#include "utils/color.h" #include "utils/palette.h" @@ -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(); } @@ -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(color) & 0xffffff; + return HSLToRGB({preset.speed, preset.scale, 127}); } return 0xffffff; diff --git a/src/fx/color_efect.cpp b/src/fx/color_efect.cpp index fcc80ef..8c97d35 100644 --- a/src/fx/color_efect.cpp +++ b/src/fx/color_efect.cpp @@ -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 fx_init = { @@ -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); diff --git a/src/network/protocol/server/api.cpp b/src/network/protocol/server/api.cpp index 6b0642c..d4862b8 100644 --- a/src/network/protocol/server/api.cpp +++ b/src/network/protocol/server/api.cpp @@ -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()} }); } diff --git a/src/utils/color.h b/src/utils/color.h new file mode 100644 index 0000000..53fef94 --- /dev/null +++ b/src/utils/color.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include + +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(h / 360.0 * 255), // Normalize h to [0, 255] + static_cast(s * 255), // Normalize s to [0, 255] + static_cast(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((rN + m) * 255); + uint8_t g = static_cast((gN + m) * 255); + uint8_t b = static_cast((bN + m) * 255); + + return (r << 16) | (g << 8) | b; // Combine r, g, b into a uint32_t +} \ No newline at end of file