00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef OLENA_CONVERT_NRGBHSL_HH
00030 # define OLENA_CONVERT_NRGBHSL_HH
00031
00032 # include <oln/basics.hh>
00033 # include <oln/convert/abstract/colorconv.hh>
00034
00035 # include <ntg/basics.hh>
00036 # include <ntg/color/nrgb.hh>
00037 # include <ntg/color/hsl.hh>
00038
00039 # include <mlc/contract.hh>
00040
00041 # include <cstdlib>
00042 # include <sstream>
00043
00049 namespace oln {
00050
00051 using namespace ntg;
00052
00053 namespace convert {
00082 template<unsigned inbits, unsigned outbits>
00083 struct f_rgb_to_hsl
00084 : public abstract::color_conversion<3, inbits, rgb_traits,
00085 3, outbits, hsl_traits, f_rgb_to_hsl<inbits, outbits> >
00086 {
00087 color<3, outbits, hsl_traits>
00088 doit(const color<3, inbits, rgb_traits>& v) const
00089 {
00090 vec<3, float> in = v.to_float();
00091 vec<3, float> out;
00092
00093 float max_in = ntg::max(in[rgb_R], std::max(in[rgb_B], in[rgb_G]));
00094 float min_in = ntg::min(in[rgb_R], std::min(in[rgb_B], in[rgb_G]));
00095 float diff = max_in-min_in;
00096
00097 out[hsl_L] = (max_in + min_in) / 2;
00098 if (std::abs(diff) <= FLT_EPSILON){
00099 out[hsl_S] = 0;
00100 out[hsl_H] = 0;
00101 }
00102 else {
00103 if (out[hsl_L] <= 0.5)
00104 out[hsl_S] = diff / (max_in + min_in);
00105 else
00106 out[hsl_S] = diff / (2 - max_in - min_in);
00107
00108
00109 float r_dist = (max_in - in[rgb_R]) / diff;
00110 float g_dist = (max_in - in[rgb_G]) / diff;
00111 float b_dist = (max_in - in[rgb_B]) / diff;
00112
00113 if (in[rgb_R] == max_in)
00114 out[hsl_H] = b_dist - g_dist;
00115 else if(in[rgb_G] == max_in)
00116 out[hsl_H] = 2 + r_dist - b_dist;
00117 else if(in[rgb_B] == max_in)
00118 out[hsl_H] = 4 + g_dist - r_dist;
00119
00120 out[hsl_H] *= 60;
00121 if(out[hsl_H] < 0)
00122 out[hsl_H] += 360;
00123 }
00124 return out;
00125 }
00126
00127 static std::string
00128 name()
00129 {
00130 std::ostringstream s;
00131 s << "f_rgb_to_hsl<" << inbits << ", " << outbits << '>';
00132 s.str();
00133 }
00134 };
00135
00140 template <unsigned inbits, unsigned outbits>
00141 color<3, inbits, hsl_traits>
00142 rgb_to_hsl(const color<3, outbits, rgb_traits>& v)
00143 {
00144 f_rgb_to_hsl<inbits, outbits> f;
00145 return f(v);
00146 }
00147
00148 namespace internal {
00149 float
00150 RGB(float q1, float q2, float hue)
00151 {
00152 if (hue >= 360)
00153 hue -= 360;
00154 if (hue < 0)
00155 hue += 360;
00156 if (hue < 60)
00157 return q1 + (q2 - q1) * hue / 60;
00158 else if (hue < 180)
00159 return q2;
00160 else if (hue < 240)
00161 return q1 + (q2 - q1) * (240 - hue) / 60;
00162 else
00163 return q1;
00164 }
00165 }
00166
00171 template<unsigned inbits, unsigned outbits>
00172 struct f_hsl_to_rgb
00173 : public abstract::color_conversion<3, inbits, hsl_traits,
00174 3, outbits, rgb_traits, f_hsl_to_rgb<inbits, outbits> >
00175 {
00176 color<3, outbits, rgb_traits>
00177 doit(const color<3, inbits, hsl_traits>& v) const
00178 {
00179 vec<3, float> in = v.to_float();
00180 vec<3, float> out;
00181 float p2;
00182
00183 if(in[hsl_L] < 0.5)
00184 p2 = in[hsl_L] * (1+in[hsl_S]);
00185 else
00186 p2 = in[hsl_L] + in[hsl_S] - (in[hsl_L] * in[hsl_S]);
00187
00188 float p1 = 2 * in[hsl_L] - p2;
00189
00190 if(in[hsl_S] == 0)
00191 out[rgb_R] = out[rgb_G] = out[rgb_B] = in[hsl_L];
00192 else
00193 {
00194 out[rgb_R] = internal::RGB(p1, p2, in[hsl_H] + 120);
00195 out[rgb_G] = internal::RGB(p1, p2, in[hsl_H]);
00196 out[rgb_B] = internal::RGB(p1, p2, in[hsl_H] - 120);
00197 }
00198
00199 return out;
00200 }
00201
00202 static std::string
00203 name()
00204 {
00205 std::ostringstream s;
00206 s << "f_hsl_to_rgb<" << inbits << ", " << outbits << '>';
00207 s.str();
00208 }
00209 };
00210
00215 template<unsigned inbits, unsigned outbits>
00216 color<3, outbits, rgb_traits>
00217 hsl_to_rgb(const color<3, inbits, hsl_traits>& v)
00218 {
00219 f_hsl_to_rgb<inbits, outbits> f;
00220 return f(v);
00221 }
00222
00223 }
00224 }
00225
00226 #endif // OLENA_CONVERT_RGBHSL_HH