/*------------------------------------------------------------------------------------- base
*-------*/
#define FixMinMax( x,min,max) MIN( (max), MAX( (min), (x)))
typedef struct ColorRGB_f {
float red;
float green;
float blue;
} ColorRGB_f;
/*------------------------------------------------------------------------------------- variant A
* source: http://en.wikipedia.org/wiki/HSL_and_HSV
* input : H,S,L: all normalized into [0...1] in respect of: [0...360°],[0...100%],[0...100%]
* output: R,G,B: all normalized into [0...1]
*-------*/
ColorRGB_f colorRGB_f_withHSL_vA(float hue, float saturation, float lightness)
{
/*------------------------------------- prepare */
float hue6 = hue * 6; /* normalize hue [0...6) */
while (hue6 < 0) hue6 += 6;
while (hue6 >= 360) hue6 -= 6;
if (hue6 < 0) hue6 = 0;
saturation = FixMinMax( saturation, 0, 1);
lightness = FixMinMax( lightness , 0, 1);
/*-------------------------------------*/
float ll = 2 * lightness - 1;
float C = (1 - ABS( ll)) * saturation;
float tt = fmod( hue6, 2) - 1;
float X = C * (1 - ABS( tt));
/*-------------------------------------*/
float rr = 0, gg = 0, bb = 0;
if( 0 <= hue6 && hue6 < 1)
{
rr = C;
gg = X;
}
else if( 1 <= hue6 && hue6 < 2)
{
rr = X;
gg = C;
}
else if( 2 <= hue6 && hue6 < 3)
{
gg = C;
bb = X;
}
else if( 3 <= hue6 && hue6 < 4)
{
gg = X;
bb = C;
}
else if( 4 <= hue6 && hue6 < 5)
{
rr = X;
bb = C;
}
else /* if( 5 <= hue6 && hue6 < 6) */
{
rr = C;
bb = X;
}
/*-------------------------------------*/
ColorRGB_f rgb;
float m = lightness - C / 2;
rgb.red = rr + m;
rgb.green = gg + m;
rgb.blue = bb + m;
return rgb;
}
/*------------------------------------------------------------------------------------- variant B
* source: http://www.w3.org/TR/2011/REC-css3-color-20110607/#hsl-color
* input : H,S,L: all normalized into [0...1] in respect of: [0...360°],[0...100%],[0...100%]
* output: R,G,B: all normalized into [0...1]
*-------*/
ColorRGB_f colorRGB_f_withHSL_vB(float hue, float saturation, float lightness)
{
saturation = FixMinMax( saturation, 0, 1);
lightness = FixMinMax( lightness , 0, 1);
float m2 = 0;
if (lightness <= 0.5)
m2 = lightness * (1 + saturation);
else
m2 = lightness * (1 - saturation) + saturation;
float m1 = 2 * lightness - m2;
ColorRGB_f rgb = {0,0,0};
rgb.red = colorValue_f_withHue_vB( m1, m2, hue + 1./3.);
rgb.green = colorValue_f_withHue_vB( m1, m2, hue);
rgb.blue = colorValue_f_withHue_vB( m1, m2, hue - 1./3.);
return rgb;
}
float colorValue_f_withHue_vB(float m1, float m2, float hue)
{
while (hue >= 1) hue -= 1;
while (hue < 0) hue += 1;
if (1 > 6 * hue) return m1 + (m2 - m1) * hue * 6;
if (1 > 2 * hue) return m2;
if (2 > 3 * hue) return m1 + (m2 - m1) * (2./3. - hue) * 6;
return m1;
}
/* original in ABC:
*
* HOW TO RETURN hsl.to.rgb(h, s, l):
* SELECT:
* l<=0.5: PUT l*(s+1) IN m2
* ELSE: PUT l+s-l*s IN m2
* PUT l*2-m2 IN m1
* PUT hue.to.rgb(m1, m2, h+1/3) IN r
* PUT hue.to.rgb(m1, m2, h ) IN g
* PUT hue.to.rgb(m1, m2, h-1/3) IN b
* RETURN (r, g, b)
*
* HOW TO RETURN hue.to.rgb(m1, m2, h):
* IF h<0: PUT h+1 IN h
* IF h>1: PUT h-1 IN h
* IF h*6<1: RETURN m1+(m2-m1)*h*6
* IF h*2<1: RETURN m2
* IF h*3<2: RETURN m1+(m2-m1)*(2/3-h)*6
* RETURN m1
*/
/*------------------------------------------------------------------------------------- variant C
* it is very simple optimization of variant B
*-------*/
ColorRGB_f colorRGB_f_withHSL_vC(float hue, float saturation, float lightness)
{
saturation = FixMinMax( saturation, 0, 1);
lightness = FixMinMax( lightness , 0, 1);
if (saturation > 0)
return colorRGB_f_withHSL_vB( hue, saturation, lightness);
ColorRGB_f rgb = { lightness, lightness, lightness};
return rgb;
}
/*------------------------------------------------------------------------------------- variant D
* input : H,S,L: all normalized into [0...1] in respect of: [0...360°],[0...100%],[0...100%]
* output: R,G,B: all normalized into [0...1]
*-------*/
ColorRGB_f colorRGB_f_withHSL_vD(float hue, float saturation, float lightness)
{
while (hue >= 1) hue -= 1;
while (hue < 0) hue += 1;
saturation = FixMinMax( saturation, 0, 1);
lightness = FixMinMax( lightness , 0, 1);
float v = 0;
if (lightness <= 0.5)
v = lightness * (1 + saturation);
else
v = lightness + saturation - lightness * saturation;
if (v <= 0)
{
ColorRGB_f rgb = { lightness, lightness, lightness};
return rgb;
}
ColorRGB_f rgb;
float hue6 = fmod( hue * 6, 6); /* normalize hue [0...6) */
int sextant = floorf( hue6);
float fract = hue6 - sextant;
float min = 2 * lightness - v;
float sv = (v - min) / v;
float vsf = v * sv * fract;
switch (sextant)
{
case 0: rgb.red = v; rgb.green = min + vsf; rgb.blue = min; break;
case 1: rgb.red = v - vsf; rgb.green = v; rgb.blue = min; break;
case 2: rgb.red = min; rgb.green = v; rgb.blue = min + vsf; break;
case 3: rgb.red = min; rgb.green = v - vsf; rgb.blue = v; break;
case 4: rgb.red = min + vsf; rgb.green = min; rgb.blue = v; break;
case 5:
default: rgb.red = v; rgb.green = min; rgb.blue = v - vsf; break;
}
return rgb;
}
/*-----------------------------------------------------------------------------------------------*/