2015-08-17 12:10:08 +00:00
|
|
|
|
|
|
|
#ifndef BASE_COLOR_H
|
|
|
|
#define BASE_COLOR_H
|
|
|
|
|
2021-08-26 10:05:36 +00:00
|
|
|
#include <base/math.h>
|
|
|
|
#include <base/vmath.h>
|
2015-08-17 12:10:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
Title: Color handling
|
|
|
|
*/
|
2019-04-26 12:06:32 +00:00
|
|
|
/*
|
|
|
|
Function: RgbToHue
|
|
|
|
Determines the hue from RGB values
|
|
|
|
*/
|
2019-04-26 21:47:34 +00:00
|
|
|
inline float RgbToHue(float r, float g, float b)
|
2015-08-17 12:10:08 +00:00
|
|
|
{
|
2019-04-26 21:47:34 +00:00
|
|
|
float h_min = minimum(r, g, b);
|
|
|
|
float h_max = maximum(r, g, b);
|
2015-08-17 12:10:08 +00:00
|
|
|
|
|
|
|
float hue = 0.0f;
|
2019-04-21 16:20:53 +00:00
|
|
|
if(h_max != h_min)
|
|
|
|
{
|
|
|
|
float c = h_max - h_min;
|
2019-04-26 21:47:34 +00:00
|
|
|
if(h_max == r)
|
|
|
|
hue = (g - b) / c + (g < b ? 6 : 0);
|
|
|
|
else if(h_max == g)
|
|
|
|
hue = (b - r) / c + 2;
|
2019-04-21 16:20:53 +00:00
|
|
|
else
|
2019-04-26 21:47:34 +00:00
|
|
|
hue = (r - g) / c + 4;
|
2019-04-21 16:20:53 +00:00
|
|
|
}
|
2015-08-17 12:10:08 +00:00
|
|
|
|
2019-04-21 16:20:53 +00:00
|
|
|
return hue / 6.0f;
|
2015-08-17 12:10:08 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:18:50 +00:00
|
|
|
// Curiously Recurring Template Pattern for type safety
|
2020-09-26 19:41:58 +00:00
|
|
|
template<typename DerivedT>
|
2019-04-26 21:47:34 +00:00
|
|
|
class color4_base
|
2019-04-25 11:48:53 +00:00
|
|
|
{
|
2019-04-25 15:21:35 +00:00
|
|
|
public:
|
2020-09-26 19:41:58 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
float x, r, h;
|
|
|
|
};
|
|
|
|
union
|
|
|
|
{
|
|
|
|
float y, g, s;
|
|
|
|
};
|
|
|
|
union
|
|
|
|
{
|
|
|
|
float z, b, l, v;
|
|
|
|
};
|
|
|
|
union
|
|
|
|
{
|
|
|
|
float w, a;
|
|
|
|
};
|
2019-04-25 15:21:35 +00:00
|
|
|
|
2019-04-25 17:38:11 +00:00
|
|
|
color4_base() {}
|
2019-04-25 16:59:04 +00:00
|
|
|
|
2019-04-25 15:21:35 +00:00
|
|
|
color4_base(const vec4 &v4)
|
|
|
|
{
|
|
|
|
x = v4.x;
|
|
|
|
y = v4.y;
|
|
|
|
z = v4.z;
|
|
|
|
a = v4.w;
|
|
|
|
}
|
|
|
|
|
2019-04-26 12:06:32 +00:00
|
|
|
color4_base(const vec3 &v3)
|
|
|
|
{
|
|
|
|
x = v3.x;
|
|
|
|
y = v3.y;
|
|
|
|
z = v3.z;
|
|
|
|
a = 1.0f;
|
|
|
|
}
|
|
|
|
|
2019-04-25 15:21:35 +00:00
|
|
|
color4_base(float nx, float ny, float nz, float na)
|
|
|
|
{
|
|
|
|
x = nx;
|
|
|
|
y = ny;
|
|
|
|
z = nz;
|
|
|
|
a = na;
|
|
|
|
}
|
|
|
|
|
2019-04-26 21:47:34 +00:00
|
|
|
color4_base(float nx, float ny, float nz)
|
|
|
|
{
|
|
|
|
x = nx;
|
|
|
|
y = ny;
|
|
|
|
z = nz;
|
|
|
|
a = 1.0f;
|
|
|
|
}
|
|
|
|
|
2019-04-26 22:34:20 +00:00
|
|
|
color4_base(unsigned col, bool alpha = false)
|
2019-04-25 15:21:35 +00:00
|
|
|
{
|
2019-04-26 22:34:20 +00:00
|
|
|
a = alpha ? ((col >> 24) & 0xFF) / 255.0f : 1.0f;
|
2019-04-25 15:21:35 +00:00
|
|
|
x = ((col >> 16) & 0xFF) / 255.0f;
|
|
|
|
y = ((col >> 8) & 0xFF) / 255.0f;
|
|
|
|
z = ((col >> 0) & 0xFF) / 255.0f;
|
|
|
|
}
|
|
|
|
|
2022-03-08 19:01:26 +00:00
|
|
|
vec4 v4() const { return vec4(x, y, z, a); }
|
2019-04-26 21:47:34 +00:00
|
|
|
|
2019-07-02 12:54:06 +00:00
|
|
|
unsigned Pack(bool Alpha = true)
|
2019-04-25 15:21:35 +00:00
|
|
|
{
|
2019-07-02 12:54:06 +00:00
|
|
|
return (Alpha ? ((unsigned)(a * 255.0f) << 24) : 0) + ((unsigned)(x * 255.0f) << 16) + ((unsigned)(y * 255.0f) << 8) + (unsigned)(z * 255.0f);
|
2019-04-25 15:21:35 +00:00
|
|
|
}
|
2019-04-26 21:47:34 +00:00
|
|
|
|
2019-12-02 09:18:50 +00:00
|
|
|
DerivedT WithAlpha(float alpha)
|
2019-04-26 21:47:34 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
DerivedT col(static_cast<DerivedT &>(*this));
|
2019-04-26 21:47:34 +00:00
|
|
|
col.a = alpha;
|
|
|
|
return col;
|
|
|
|
}
|
2019-04-25 15:21:35 +00:00
|
|
|
};
|
|
|
|
|
2019-12-02 09:18:50 +00:00
|
|
|
class ColorHSLA : public color4_base<ColorHSLA>
|
2019-04-25 15:21:35 +00:00
|
|
|
{
|
2019-04-26 13:38:16 +00:00
|
|
|
public:
|
2019-04-25 15:21:35 +00:00
|
|
|
using color4_base::color4_base;
|
2020-09-26 19:41:58 +00:00
|
|
|
ColorHSLA(){};
|
2019-04-26 21:47:34 +00:00
|
|
|
|
2020-06-18 16:59:21 +00:00
|
|
|
constexpr static const float DARKEST_LGT = 0.5f;
|
|
|
|
|
|
|
|
ColorHSLA UnclampLighting(float Darkest = DARKEST_LGT)
|
2019-04-25 20:29:31 +00:00
|
|
|
{
|
2019-04-26 13:38:16 +00:00
|
|
|
ColorHSLA col = *this;
|
2020-06-18 16:47:46 +00:00
|
|
|
col.l = Darkest + col.l * (1.0f - Darkest);
|
2019-04-26 13:38:16 +00:00
|
|
|
return col;
|
2020-06-18 16:47:46 +00:00
|
|
|
}
|
2019-05-01 19:45:02 +00:00
|
|
|
|
2020-06-18 16:47:46 +00:00
|
|
|
unsigned Pack(bool Alpha = true)
|
2019-05-01 19:45:02 +00:00
|
|
|
{
|
2020-06-18 16:47:46 +00:00
|
|
|
return color4_base::Pack(Alpha);
|
2019-05-01 20:35:29 +00:00
|
|
|
}
|
|
|
|
|
2020-06-18 16:47:46 +00:00
|
|
|
unsigned Pack(float Darkest, bool Alpha = false)
|
2019-05-01 20:35:29 +00:00
|
|
|
{
|
2020-06-18 16:47:46 +00:00
|
|
|
ColorHSLA col = *this;
|
2020-09-26 19:41:58 +00:00
|
|
|
col.l = (l - Darkest) / (1 - Darkest);
|
2020-06-18 16:47:46 +00:00
|
|
|
col.l = clamp(col.l, 0.0f, 1.0f);
|
|
|
|
return col.Pack(Alpha);
|
2019-05-01 19:45:02 +00:00
|
|
|
}
|
2019-04-25 15:21:35 +00:00
|
|
|
};
|
|
|
|
|
2019-12-02 09:18:50 +00:00
|
|
|
class ColorHSVA : public color4_base<ColorHSVA>
|
2019-04-26 12:06:32 +00:00
|
|
|
{
|
2019-04-26 21:47:34 +00:00
|
|
|
public:
|
2019-04-26 12:06:32 +00:00
|
|
|
using color4_base::color4_base;
|
2020-09-26 19:41:58 +00:00
|
|
|
ColorHSVA(){};
|
2019-04-26 12:06:32 +00:00
|
|
|
};
|
|
|
|
|
2019-12-02 09:18:50 +00:00
|
|
|
class ColorRGBA : public color4_base<ColorRGBA>
|
2019-04-25 15:21:35 +00:00
|
|
|
{
|
2019-04-26 21:47:34 +00:00
|
|
|
public:
|
2019-04-25 15:21:35 +00:00
|
|
|
using color4_base::color4_base;
|
2020-09-26 19:41:58 +00:00
|
|
|
ColorRGBA(){};
|
2019-04-25 15:21:35 +00:00
|
|
|
};
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<typename T, typename F>
|
2022-01-22 13:27:29 +00:00
|
|
|
T color_cast(const F &) = delete;
|
2019-04-26 12:06:32 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<>
|
2019-04-25 15:21:35 +00:00
|
|
|
inline ColorHSLA color_cast(const ColorRGBA &rgb)
|
|
|
|
{
|
2019-04-26 19:36:49 +00:00
|
|
|
float Min = minimum(rgb.r, rgb.g, rgb.b);
|
|
|
|
float Max = maximum(rgb.r, rgb.g, rgb.b);
|
2019-04-25 15:21:35 +00:00
|
|
|
|
|
|
|
float c = Max - Min;
|
2019-04-26 21:47:34 +00:00
|
|
|
float h = RgbToHue(rgb.r, rgb.g, rgb.b);
|
2019-04-25 15:21:35 +00:00
|
|
|
float l = 0.5f * (Max + Min);
|
2020-09-26 19:41:58 +00:00
|
|
|
float s = (Max != 0.0f && Min != 1.0f) ? (c / (1 - (absolute(2 * l - 1)))) : 0;
|
2019-04-25 15:21:35 +00:00
|
|
|
|
|
|
|
return ColorHSLA(h, s, l, rgb.a);
|
2019-04-25 11:48:53 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<>
|
2019-04-25 15:21:35 +00:00
|
|
|
inline ColorRGBA color_cast(const ColorHSLA &hsl)
|
2019-04-21 16:20:53 +00:00
|
|
|
{
|
2019-04-25 15:21:35 +00:00
|
|
|
vec3 rgb = vec3(0, 0, 0);
|
|
|
|
|
|
|
|
float h1 = hsl.h * 6;
|
|
|
|
float c = (1 - absolute(2 * hsl.l - 1)) * hsl.s;
|
|
|
|
float x = c * (1 - absolute(fmod(h1, 2) - 1));
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
switch(round_truncate(h1))
|
|
|
|
{
|
2019-04-25 15:21:35 +00:00
|
|
|
case 0:
|
|
|
|
rgb.r = c, rgb.g = x;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
rgb.r = x, rgb.g = c;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
rgb.g = c, rgb.b = x;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
rgb.g = x, rgb.b = c;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
rgb.r = x, rgb.b = c;
|
|
|
|
break;
|
|
|
|
case 5:
|
2019-04-26 18:01:41 +00:00
|
|
|
case 6:
|
2019-04-25 15:21:35 +00:00
|
|
|
rgb.r = c, rgb.b = x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
float m = hsl.l - (c / 2);
|
2019-04-25 15:21:35 +00:00
|
|
|
return ColorRGBA(rgb.r + m, rgb.g + m, rgb.b + m, hsl.a);
|
2019-04-21 16:20:53 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<>
|
2019-04-26 12:06:32 +00:00
|
|
|
inline ColorHSLA color_cast(const ColorHSVA &hsv)
|
|
|
|
{
|
|
|
|
float l = hsv.v * (1 - hsv.s * 0.5f);
|
2020-09-26 19:41:58 +00:00
|
|
|
return ColorHSLA(hsv.h, (l == 0.0f || l == 1.0f) ? 0 : (hsv.v - l) / minimum(l, 1 - l), l);
|
2019-04-26 12:06:32 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<>
|
2019-04-26 12:06:32 +00:00
|
|
|
inline ColorHSVA color_cast(const ColorHSLA &hsl)
|
|
|
|
{
|
2019-04-26 19:36:49 +00:00
|
|
|
float v = hsl.l + hsl.s * minimum(hsl.l, 1 - hsl.l);
|
2019-04-26 12:06:32 +00:00
|
|
|
return ColorHSVA(hsl.h, v == 0.0f ? 0 : 2 - (2 * hsl.l / v), v);
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<>
|
2019-04-26 12:06:32 +00:00
|
|
|
inline ColorRGBA color_cast(const ColorHSVA &hsv)
|
|
|
|
{
|
|
|
|
return color_cast<ColorRGBA>(color_cast<ColorHSLA>(hsv));
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<>
|
2019-04-26 12:06:32 +00:00
|
|
|
inline ColorHSVA color_cast(const ColorRGBA &rgb)
|
|
|
|
{
|
|
|
|
return color_cast<ColorHSVA>(color_cast<ColorHSLA>(rgb));
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<typename T>
|
2019-12-02 09:18:50 +00:00
|
|
|
T color_scale(const T &col, float s)
|
2019-04-26 21:47:34 +00:00
|
|
|
{
|
|
|
|
return T(col.x * s, col.y * s, col.z * s, col.a * s);
|
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
template<typename T>
|
2019-12-02 09:18:50 +00:00
|
|
|
T color_invert(const T &col)
|
|
|
|
{
|
|
|
|
return T(1.0f - col.x, 1.0f - col.y, 1.0f - col.z, 1.0f - col.a);
|
|
|
|
}
|
|
|
|
|
2015-08-17 12:10:08 +00:00
|
|
|
#endif
|