120 lines
4.0 KiB
C++
120 lines
4.0 KiB
C++
#pragma once
|
|
|
|
#include "config.hpp"
|
|
#include <windows.h>
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cwctype>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace color_picker_math {
|
|
|
|
struct Hsv {
|
|
float h = 0.0f; // [0, 360)
|
|
float s = 0.0f; // [0, 1]
|
|
float v = 0.0f; // [0, 1]
|
|
};
|
|
|
|
inline Hsv rgbToHsv(BYTE red, BYTE green, BYTE blue) {
|
|
const float r = static_cast<float>(red) / 255.0f;
|
|
const float g = static_cast<float>(green) / 255.0f;
|
|
const float b = static_cast<float>(blue) / 255.0f;
|
|
const float maximum = std::max({r, g, b});
|
|
const float minimum = std::min({r, g, b});
|
|
const float delta = maximum - minimum;
|
|
|
|
Hsv result;
|
|
result.v = maximum;
|
|
result.s = maximum <= 0.0f ? 0.0f : delta / maximum;
|
|
if (delta <= 0.00001f) {
|
|
result.h = 0.0f;
|
|
} else if (maximum == r) {
|
|
result.h = 60.0f * std::fmod((g - b) / delta, 6.0f);
|
|
} else if (maximum == g) {
|
|
result.h = 60.0f * (((b - r) / delta) + 2.0f);
|
|
} else {
|
|
result.h = 60.0f * (((r - g) / delta) + 4.0f);
|
|
}
|
|
if (result.h < 0.0f) result.h += 360.0f;
|
|
if (result.h >= 360.0f) result.h = std::fmod(result.h, 360.0f);
|
|
return result;
|
|
}
|
|
|
|
inline COLORREF hsvToRgb(float hue, float saturation, float value) {
|
|
hue = std::fmod(hue, 360.0f);
|
|
if (hue < 0.0f) hue += 360.0f;
|
|
saturation = std::clamp(saturation, 0.0f, 1.0f);
|
|
value = std::clamp(value, 0.0f, 1.0f);
|
|
|
|
const float chroma = value * saturation;
|
|
const float section = hue / 60.0f;
|
|
const float x = chroma * (1.0f - std::fabs(std::fmod(section, 2.0f) - 1.0f));
|
|
const float m = value - chroma;
|
|
|
|
float r = 0.0f;
|
|
float g = 0.0f;
|
|
float b = 0.0f;
|
|
if (section < 1.0f) { r = chroma; g = x; }
|
|
else if (section < 2.0f) { r = x; g = chroma; }
|
|
else if (section < 3.0f) { g = chroma; b = x; }
|
|
else if (section < 4.0f) { g = x; b = chroma; }
|
|
else if (section < 5.0f) { r = x; b = chroma; }
|
|
else { r = chroma; b = x; }
|
|
|
|
const auto channel = [m](float component) -> BYTE {
|
|
return static_cast<BYTE>(std::clamp(static_cast<int>(std::lround((component + m) * 255.0f)), 0, 255));
|
|
};
|
|
return RGB(channel(r), channel(g), channel(b));
|
|
}
|
|
|
|
inline std::uint32_t toArgb(COLORREF color, BYTE alpha) {
|
|
return (static_cast<std::uint32_t>(alpha) << 24u) |
|
|
(static_cast<std::uint32_t>(GetRValue(color)) << 16u) |
|
|
(static_cast<std::uint32_t>(GetGValue(color)) << 8u) |
|
|
static_cast<std::uint32_t>(GetBValue(color));
|
|
}
|
|
|
|
inline COLORREF colorFromArgb(std::uint32_t argb) {
|
|
return RGB((argb >> 16u) & 0xFFu, (argb >> 8u) & 0xFFu, argb & 0xFFu);
|
|
}
|
|
|
|
inline BYTE alphaFromArgb(std::uint32_t argb) {
|
|
return static_cast<BYTE>((argb >> 24u) & 0xFFu);
|
|
}
|
|
|
|
inline std::wstring hexRgba(COLORREF color, BYTE alpha) {
|
|
std::wostringstream stream;
|
|
stream << L'#' << std::uppercase << std::hex << std::setfill(L'0')
|
|
<< std::setw(2) << static_cast<unsigned int>(GetRValue(color))
|
|
<< std::setw(2) << static_cast<unsigned int>(GetGValue(color))
|
|
<< std::setw(2) << static_cast<unsigned int>(GetBValue(color))
|
|
<< std::setw(2) << static_cast<unsigned int>(alpha);
|
|
return stream.str();
|
|
}
|
|
|
|
inline bool parseHexRgba(std::wstring text, COLORREF& color, BYTE& alpha) {
|
|
if (!text.empty() && text.front() == L'#') text.erase(text.begin());
|
|
if (text.size() != 6 && text.size() != 8) return false;
|
|
for (wchar_t ch : text) {
|
|
if (!std::iswxdigit(static_cast<wint_t>(ch))) return false;
|
|
}
|
|
wchar_t* end = nullptr;
|
|
const unsigned long long value = std::wcstoull(text.c_str(), &end, 16);
|
|
if (!end || *end != L'\0') return false;
|
|
if (text.size() == 6) {
|
|
color = RGB((value >> 16u) & 0xFFu, (value >> 8u) & 0xFFu, value & 0xFFu);
|
|
alpha = 255;
|
|
} else {
|
|
color = RGB((value >> 24u) & 0xFFu, (value >> 16u) & 0xFFu, (value >> 8u) & 0xFFu);
|
|
alpha = static_cast<BYTE>(value & 0xFFu);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace color_picker_math
|