9#include <glm/common.hpp>
13#include "constexpr_math.h"
50#define DEF_COLOR(name, r, g, b) \
51 [[nodiscard]] constexpr color_t get_##name(float alpha) { return color_t{ float(r), float(g), float(b), alpha }; } \
52 constexpr inline color_t name = get_##name(1.0f);
53#define DEF_COLORS(name, r, g, b) \
54 DEF_COLOR(name, r, g, b) \
55 [[nodiscard]] constexpr color_t get_dark_##name(float alpha) { return color_t{ float(r) * 0.5f, float(g) * 0.5f, float(b) * 0.5f, alpha }; } \
56 constexpr inline color_t dark_##name = get_dark_##name(1.0f); \
57 [[nodiscard]] constexpr color_t get_light_##name(float alpha) { return color_t{ r + float(1.0f-r) * 0.5f, g + float(1.0f-g) * 0.5f, b + float(1.0f-b) * 0.5f, alpha }; } \
58 constexpr inline color_t light_##name = get_light_##name(1.0f);
60 DEF_COLORS(red, 1, 0, 0)
61 DEF_COLORS(green, 0, 1, 0)
62 DEF_COLORS(blue, 0, 0, 1)
63 DEF_COLORS(yellow, 1, 1, 0)
64 DEF_COLORS(magenta, 1, 0, 1)
65 DEF_COLORS(cyan, 0, 1, 1)
66 DEF_COLORS(gray, 0.5f, 0.5f, 0.5f)
67 DEF_COLORS(grey, 0.5f, 0.5f, 0.5f)
69 DEF_COLORS(orange, 1, 0.65f, 0)
70 DEF_COLORS(brown, 0.59f, 0.29f, 0)
72 DEF_COLOR(black, 0, 0, 0)
73 DEF_COLOR(white, 1, 1, 1)
74 constexpr inline color_t transparent = get_black(0.0f);
83 return { color.x * color.w, color.y * color.w, color.z * color.w, color.w };
87 [[nodiscard]]
constexpr color_t with_alpha(
color_t const& color,
float a)
89 return color_t{ color.r, color.g, color.b, a };
95 return glm::clamp(
color_t(color.x, color.y, color.z, color.w),
color_t{ 0,0,0,0 },
color_t{ 1,1,1,1 });
101 const auto rgb_max = glm::max(color.x, glm::max(color.y, color.z));
102 const auto lighter = color * (1.0f / rgb_max);
103 const auto dif = rgb_max;
104 return saturated(
color_t(lighter.x + dif * coef, lighter.y + dif * coef, lighter.z + dif * coef, 1.0f) * rgb_max);
112 const auto t = (1.0f -
contrast) * 0.5f;
122 constexpr double m = 1.0156862745098039215686274509804;
124 return color_t(t * (color.x - 0.5f) + 0.5f, t * (color.y - 0.5f) + 0.5f, t * (color.z - 0.5f) + 0.5f, color.w);
137 return color_t(1.0f - color.x, 1.0f - color.y, 1.0f - color.z, color.w);
143 const float gamma = 2.2f;
144 const float L = 0.2126f * cem::pow(color.r, gamma) + 0.7152f * cem::pow(color.g, gamma) + 0.0722f * cem::pow(color.b, gamma);
145 return (L > cem::pow(0.5f, gamma)) ? colors::black : colors::white;
151 return color.x * 0.3f + color.y * 0.59f + color.z * 0.11f;
158 return glm::mix(color,
color_t{l, l, l, color.w}, desaturation);
163 constexpr float b2f(uint32_t
byte) {
return (
byte & 0xFF) / 255.0f; }
164 constexpr uint32_t f2b(
float f) {
return uint8_t(0.5f + f * 255.0f); }
165 constexpr uint32_t f2u4(
float b1,
float b2,
float b3,
float b4) {
return (f2b(b1) << 24) | (f2b(b2) << 16) | (f2b(b3) << 8) | f2b(b4); }
166 constexpr uint32_t f2u4(
float b1,
float b2,
float b3) {
return (f2b(b1) << 16) | (f2b(b2) << 8) | f2b(b3); }
169 template <
typename T>
constexpr auto min(
const T& x,
const T& y,
const T& z) {
return glm::min(glm::min(x, y), z); }
170 template <
typename T>
constexpr auto max(
const T& x,
const T& y,
const T& z) {
return glm::max(glm::max(x, y), z); }
174 [[nodiscard]]
constexpr color_t from_u32_rgb(uint32_t rgb) {
return color_t(detail::b2f(rgb >> 16), detail::b2f(rgb >> 8), detail::b2f(rgb), 1.0f); }
176 [[nodiscard]]
constexpr color_t from_u32_bgr(uint32_t rgb) {
return color_t(detail::b2f(rgb), detail::b2f(rgb >> 8), detail::b2f(rgb >> 16), 1.0f); }
178 [[nodiscard]]
constexpr color_t from_u32_rgba(uint32_t rgb) {
return color_t(detail::b2f(rgb >> 24), detail::b2f(rgb >> 16), detail::b2f(rgb >> 8), detail::b2f(rgb)); }
180 [[nodiscard]]
constexpr color_t from_u32_bgra(uint32_t rgb) {
return color_t(detail::b2f(rgb >> 8), detail::b2f(rgb >> 16), detail::b2f(rgb >> 24), detail::b2f(rgb)); }
182 [[nodiscard]]
constexpr color_t from_u32_argb(uint32_t rgb) {
return color_t(detail::b2f(rgb >> 16), detail::b2f(rgb >> 8), detail::b2f(rgb), detail::b2f(rgb >> 24)); }
184 [[nodiscard]]
constexpr color_t from_u32_abgr(uint32_t rgb) {
return color_t(detail::b2f(rgb), detail::b2f(rgb >> 8), detail::b2f(rgb >> 16), detail::b2f(rgb >> 24)); }
187 [[nodiscard]]
constexpr color_t from_u8_rgb(uint8_t r, uint8_t g, uint8_t b) {
return color_t(detail::b2f(r), detail::b2f(g), detail::b2f(b), 1.0f); }
189 [[nodiscard]]
constexpr color_t from_u8_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return color_t(detail::b2f(r), detail::b2f(g), detail::b2f(b), detail::b2f(a)); }
192 [[nodiscard]]
constexpr uint32_t
to_u32_argb(
color_t const& rgba) {
return detail::f2u4(rgba.w, rgba.x, rgba.y, rgba.z); }
194 [[nodiscard]]
constexpr uint32_t
to_u32_abgr(
color_t const& rgba) {
return detail::f2u4(rgba.w, rgba.z, rgba.y, rgba.x); }
196 [[nodiscard]]
constexpr uint32_t
to_u32_rgba(
color_t const& rgba) {
return detail::f2u4(rgba.x, rgba.y, rgba.z, rgba.w); }
198 [[nodiscard]]
constexpr uint32_t
to_u32_bgra(
color_t const& rgba) {
return detail::f2u4(rgba.z, rgba.y, rgba.x, rgba.w); }
200 [[nodiscard]]
constexpr uint32_t
to_u32_rgb(
color_t const& rgba) {
return detail::f2u4(rgba.x, rgba.y, rgba.z); }
202 [[nodiscard]]
constexpr uint32_t
to_u32_bgr(
color_t const& rgba) {
return detail::f2u4(rgba.z, rgba.y, rgba.x); }
204 template <std::same_as<color_rgba_u32_t> TO>
205 [[nodiscard]]
constexpr TO named_cast(
color_rgba_t const& from)
210 template <std::same_as<color_abgr_u32_t> TO>
211 [[nodiscard]]
constexpr TO named_cast(
color_rgba_t const& from)
216 template <
typename TO,
typename FROM>
217 [[nodiscard]]
constexpr TO color_cast(FROM
const& from)
219 return named_cast<TO>(from);
223 [[nodiscard]]
constexpr glm::tvec4<uint8_t>
to_u8(
color_t const& rgba) {
return { detail::f2b(rgba.x), detail::f2b(rgba.y), detail::f2b(rgba.z), detail::f2b(rgba.w) }; }
228 const auto hue = hsva->r;
229 const auto saturation = hsva->g;
230 const auto value = hsva->b;
231 const auto alpha = hsva->a;
232 const auto i = (int)hue;
233 float fraction = hue - (float)i;
234 if (!(i & 1)) fraction = 1.0f - fraction;
235 const auto m = value * (1.0f - saturation);
236 const auto n = value * (1.0f - saturation * fraction);
240 case 0:
return color_t(value, n, m, alpha);
241 case 1:
return color_t(n, value, m, alpha);
242 case 2:
return color_t(m, value, n, alpha);
243 case 3:
return color_t(m, n, value, alpha);
244 case 4:
return color_t(n, m, value, alpha);
245 case 5:
return color_t(value, m, n, alpha);
246 default:
return color_t(value, value, value, alpha);
253 const auto min = detail::min(rgba.x, rgba.y, rgba.z);
254 const auto max = detail::max(rgba.x, rgba.y, rgba.z);
255 const auto delta = max - min;
262 h = fmod((rgba.y - rgba.z) / delta, 6.0f);
263 else if (rgba.y == max)
264 h = 2 + (rgba.z - rgba.x) / delta;
266 h = 4 + (rgba.x - rgba.y) / delta;
271 (max != 0) ? (delta / max) : 0,
294 std::from_chars(str + 3, str + 4, a, 16); a = a << 4 | a;
297 std::from_chars(str + 0, str + 1, r, 16); r = r << 4 | r;
298 std::from_chars(str + 1, str + 2, g, 16); g = g << 4 | g;
299 std::from_chars(str + 2, str + 3, b, 16); b = b << 4 | b;
302 std::from_chars(str + 6, str + 8, a, 16);
305 std::from_chars(str + 0, str + 2, r, 16);
306 std::from_chars(str + 2, str + 4, g, 16);
307 std::from_chars(str + 4, str + 6, b, 16);
309 default:
throw "invalid number of characters";
311 return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
315 [[nodiscard]]
consteval color_rgba_t operator ""_rgb(
const char* str,
size_t n)
323 return from_html(html.data(), html.size());
330 float GetDotProduct()
const {
331 return R*R + G*G + B*B;
333 float GetFullDotProduct()
const {
334 return R*R + G*G + B*B + A*A;
337 const Color* FindClosestColor(ArrayView<Color> palette)
const {
338 return std::min_element(palette.begin(), palette.end(), [
this](
const Color& a,
const Color& b) {
339 const auto diff_a = a - *this;
340 const auto diff_b = b - *this;
341 return diff_a.GetDotProduct() < diff_b.GetDotProduct();
345 const Color* FindClosestFullColor(ArrayView<Color> palette)
const {
346 return std::min_element(palette.begin(), palette.end(), [
this](
const Color& a,
const Color& b) {
347 const auto diff_a = a.FullDifference(*this);
348 const auto diff_b = b.FullDifference(*this);
349 return diff_a.GetFullDotProduct() < diff_b.GetFullDotProduct();
354 enum class GrayscaleType
361 template <GrayscaleType TYPE = GrayscaleType::Luminosity>
362 Color Grayscale()
const {
365 case GrayscaleType::Lightness:
return Color((Max3(R, G, B) + Min3(R, G, B))*0.5, A);
366 case GrayscaleType::Average:
return Color((R+G+B)/3.0, A);
368 case GrayscaleType::Luminosity:
return Color(R*0.21 + G*0.72 + B*0.07, A);
372 Color BlendedOver(
const Color& other)
const {
373 const auto oma = 1.0f - A;
374 return *
this * A + other * oma;
377 template <
typename FUNC>
378 Color BlendWithAlpha(
const Color& other, FUNC func)
const {
379 return Lerp(func(*
this, other), other, A);
431 static Color FromHTML(StringView str)
436 uint32_t hex = StringToUnsignedLong(str,
nullptr, 16);
437 return colors::FromRGBInt(hex);
439 else if (str.size() == 8)
441 uint32_t hex = StringToUnsignedLong(str,
nullptr, 16);
442 return colors::FromRGBAInt(hex);
444 else if (str.size() == 3)
446 uint32_t hex = StringToUnsignedLong(str,
nullptr, 16);
447 hex = ((hex << 12) & 0xF00000) | ((hex << 8) & 0xF000) | ((hex << 4) & 0xF0);
448 hex = hex | (hex >> 4);
449 return colors::FromRGBInt(hex);
456 uint8_t GetR8()
const {
return uint8_t(R*255.0f); }
457 uint8_t GetG8()
const {
return uint8_t(G*255.0f); }
458 uint8_t GetB8()
const {
return uint8_t(B*255.0f); }
459 uint8_t GetA8()
const {
return uint8_t(A*255.0f); }
constexpr auto to_u8(FROM byte) noexcept
Bit-casts the given bytelike to a uint8_t.
constexpr float luminance(color_t const &color)
Get brightness of color.
constexpr uint32_t to_u32_bgra(color_t const &rgba)
Creates an 8bpp BGRA integer from a color.
color_space
Implementation note: These functions use the .xyzw members instead of the .rgba members because acces...
constexpr uint32_t to_u32_rgb(color_t const &rgba)
Creates a 32 bitbpp RGB integer from a color, with the most significant 8 bits set to 0.
constexpr color_t premultiplied(color_t const &color)
Returns the color multiplied by its own alpha.
named< uint32_t, "color_abgr_u32"> color_abgr_u32_t
Represent a packed ABGR color with 8 bits per pixel.
constexpr color_t from_u32_rgba(uint32_t rgb)
Gets a color from an RGBA 8bpp integer, with R being most significant.
constexpr color_t from_u32_bgr(uint32_t rgb)
Gets a color from an BGR 8bpp integer, with R being least significant.
constexpr color_t lighten(color_t const &color, float coef)
Returns a color lightened by a coefficient.
constexpr color_t saturated(color_t const &color)
Returns a color with all elements clamped between 0 and 1.
constexpr color_t to_rgb(color_hsva_t const &hsva)
Converts a HSVA color to RGBA space.
constexpr uint32_t to_u32_rgba(color_t const &rgba)
Creates an 8bpp RGBA integer from a color.
constexpr uint32_t to_u32_abgr(color_t const &rgba)
Creates an 8bpp ABGR integer from a color.
named< uint32_t, "color_rgba_u32"> color_rgba_u32_t
Represent a packed RGBA color with 8 bits per pixel.
constexpr color_t contrast(color_t const &color, float contrast)
Returns a color with its contrast changed.
constexpr color_t contrast2(color_t const &color, float contrast)
Returns a color with its contrast changed This uses a differen algorithm and contrast value than cont...
constexpr color_t from_u32_abgr(uint32_t rgb)
Gets a color from an ABGR 8bpp integer, with A being most significant, and R being least significant.
constexpr color_t from_u32_argb(uint32_t rgb)
Gets a color from an ARGB 8bpp integer, with A being most significant, and B being least significant.
constexpr color_rgba_t from_html(const char *str, size_t n)
Converts a HTML color string (like #FBA or fafafa) to an RGBA color.
constexpr color_t gamma_correct(color_t const &color, const float gamma)
Returns a gamma corrected color.
glm::vec4 color_rgba_t
Represents a color in RGBA color space, with 0.0-1.0 float elements.
color_rgba_t color_t
Default color_t type is RGBA.
constexpr color_t contrasting(color_t const &color)
Returns a color that's a good contrasting color for the original.
constexpr color_hsva_t to_hsv(color_t const &rgba)
Converts an RGBA color to HSVA space.
constexpr color_t inverted(color_t const &color)
Returns an inverted color, i.e. with (1.0-x) on all of its elements, excluding its alpha.
constexpr uint32_t to_u32_argb(color_t const &rgba)
Creates an 8bpp ARGB integer from a color.
constexpr color_t desaturated(color_t const &color, float desaturation)
Returns a color sapped of desaturation percent (0-1) of its saturation.
named< glm::vec4, "color_hsva"> color_hsva_t
Represents a color in HSVA color space, with H=0.0-6.0, S=0.0-1.0, V=0.0-1.0, A=0....
constexpr color_t from_u32_rgb(uint32_t rgb)
Gets a color from an RGB 8bpp integer, with R being most significant.
constexpr color_t from_u32_bgra(uint32_t rgb)
Gets a color from an BGRA 8bpp integer, with A being least significant, and B being most significant.
constexpr uint32_t to_u32_bgr(color_t const &rgba)
Creates a 32 bitbpp BGR integer from a color, with the most significant 8 bits set to 0.
The below code is based on Sun's libm library code, which is licensed under the following license:
Contains the basic colors as variables and functions.
Primary namespace for everything in this library.
Used to create a strong typedef of T.