colour: add hsv/rgb conversions
This commit is contained in:
parent
e7fba43935
commit
a7f96a127d
73
colour.cpp
73
colour.cpp
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
using util::colour;
|
using util::colour;
|
||||||
|
using util::colour3f;
|
||||||
using util::colour4f;
|
using util::colour4f;
|
||||||
|
|
||||||
|
|
||||||
@ -271,6 +272,78 @@ colour<S,T>::from_x11 (const std::string &name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
colour3f
|
||||||
|
util::rgb_to_hsv (colour3f rgb)
|
||||||
|
{
|
||||||
|
// Calculate chroma
|
||||||
|
auto M = max (rgb);
|
||||||
|
auto m = min (rgb);
|
||||||
|
auto C = M - m;
|
||||||
|
|
||||||
|
// Undefined for zero chroma
|
||||||
|
if (almost_zero (C))
|
||||||
|
return { -1.f, 0.f, M };
|
||||||
|
|
||||||
|
// Calculate hue
|
||||||
|
float H = exactly_equal (rgb.r, M) ? (rgb.g - rgb.b) :
|
||||||
|
exactly_equal (rgb.g, M) ? 2 + (rgb.b - rgb.r) :
|
||||||
|
exactly_equal (rgb.b, M) ? 4 + (rgb.r - rgb.g) :
|
||||||
|
0 ;
|
||||||
|
|
||||||
|
H /= C;
|
||||||
|
H *= 60;
|
||||||
|
|
||||||
|
if (H < 0)
|
||||||
|
H += 360;
|
||||||
|
|
||||||
|
// Calculate value
|
||||||
|
auto V = M;
|
||||||
|
|
||||||
|
// Calculate saturation
|
||||||
|
auto S = almost_zero (V) ? 0.f : C / V;
|
||||||
|
|
||||||
|
return { H, S, V };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
colour3f
|
||||||
|
util::hsv_to_rgb (colour3f hsv)
|
||||||
|
{
|
||||||
|
CHECK_GE (hsv.h, 0);
|
||||||
|
CHECK_LT (hsv.h, 360);
|
||||||
|
CHECK_GE (hsv.s, 0);
|
||||||
|
CHECK_LE (hsv.s, 1);
|
||||||
|
CHECK_GE (hsv.v, 0);
|
||||||
|
CHECK_LE (hsv.v, 1);
|
||||||
|
|
||||||
|
float C = hsv.v * hsv.s;
|
||||||
|
float H = hsv.h / 60;
|
||||||
|
float X = C * (1 - std::abs (std::fmod (H, 2.f) - 1));
|
||||||
|
|
||||||
|
// monochromatic'ish
|
||||||
|
if (almost_zero (hsv.s))
|
||||||
|
return colour3f { hsv.v };
|
||||||
|
|
||||||
|
colour3f rgb;
|
||||||
|
|
||||||
|
unsigned hex = (unsigned)H;
|
||||||
|
switch (hex) {
|
||||||
|
case 0: rgb = { C, X, 0 }; break;
|
||||||
|
case 1: rgb = { X, C, 0 }; break;
|
||||||
|
case 2: rgb = { 0, C, X }; break;
|
||||||
|
case 3: rgb = { 0, X, C }; break;
|
||||||
|
case 4: rgb = { X, 0, C }; break;
|
||||||
|
case 5: rgb = { C, 0, X }; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto m = hsv.v - C;
|
||||||
|
|
||||||
|
return rgb + m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///----------------------------------------------------------------------------
|
///----------------------------------------------------------------------------
|
||||||
//! Extract a colour object from a JSON node.
|
//! Extract a colour object from a JSON node.
|
||||||
|
@ -50,6 +50,11 @@ namespace util {
|
|||||||
|
|
||||||
// Convenience types
|
// Convenience types
|
||||||
typedef colour<4,float> colour4f;
|
typedef colour<4,float> colour4f;
|
||||||
|
typedef colour<3,float> colour3f;
|
||||||
|
|
||||||
|
// RGB <-> HSV
|
||||||
|
colour3f rgb_to_hsv (colour3f);
|
||||||
|
colour3f hsv_to_rgb (colour3f);
|
||||||
|
|
||||||
// Serialisation
|
// Serialisation
|
||||||
const json::tree::node& operator>> (const json::tree::node&, util::colour4f&);
|
const json::tree::node& operator>> (const json::tree::node&, util::colour4f&);
|
||||||
|
@ -22,4 +22,32 @@ main (int, char**)
|
|||||||
// Check lookups are working
|
// Check lookups are working
|
||||||
CHECK_EQ (util::colour4f::from_html ("white"), util::colour4f::WHITE);
|
CHECK_EQ (util::colour4f::from_html ("white"), util::colour4f::WHITE);
|
||||||
CHECK_EQ (util::colour4f::from_x11 ("white"), util::colour4f::WHITE);
|
CHECK_EQ (util::colour4f::from_x11 ("white"), util::colour4f::WHITE);
|
||||||
|
|
||||||
|
// Check HSV conversions
|
||||||
|
{
|
||||||
|
// white: hue is undefined
|
||||||
|
auto white = util::rgb_to_hsv ({1,1,1});
|
||||||
|
CHECK_EQ (white.s, 0);
|
||||||
|
CHECK_EQ (white.v, 1);
|
||||||
|
|
||||||
|
// black: hue is undefined
|
||||||
|
auto black = util::rgb_to_hsv ({0,0,0});
|
||||||
|
CHECK_EQ (black.s, 0);
|
||||||
|
CHECK_EQ (black.v, 0);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
util::colour3f rgb;
|
||||||
|
util::colour3f hsv;
|
||||||
|
} TESTS[] = {
|
||||||
|
{ { 1, 0, 0, }, { 0, 1, 1, } }, // red
|
||||||
|
{ { 0, 1, 0, }, { 120, 1, 1, } }, // green
|
||||||
|
{ { 0, 0, 1, }, { 240, 1, 1, } }, // blue
|
||||||
|
{ { 0.75f, 0.25f, 0.75f }, { 300, 2/3.f, 0.75f } },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto i: TESTS) {
|
||||||
|
CHECK_EQ (util::rgb_to_hsv (i.rgb), i.hsv);
|
||||||
|
CHECK_EQ (util::hsv_to_rgb (i.hsv), i.rgb);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user