00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef LUX_COLOR_H
00024 #define LUX_COLOR_H
00025
00026 #include "lux.h"
00027
00028
00029 namespace lux
00030 {
00031
00032
00033 class Color {
00034
00035 friend class boost::serialization::access;
00036
00037 public:
00038
00039 Color() {};
00040
00041
00042
00043 friend ostream &operator<<(ostream &, const Color &);
00044 Color &operator+=(const Color &s2) {
00045 c[0] += s2.c[0]; c[1] += s2.c[1]; c[2] += s2.c[2];
00046 return *this;
00047 }
00048 Color &operator+=(float f) {
00049 c[0] += f; c[1] += f; c[2] += f;
00050 return *this;
00051 }
00052 Color operator+(const Color &s2) const {
00053 Color ret = *this;
00054 ret.c[0] += s2.c[0]; ret.c[1] += s2.c[1]; ret.c[2] += s2.c[2];
00055 return ret;
00056 }
00057 Color &operator-=(const Color &s2) {
00058 c[0] -= s2.c[0]; c[1] -= s2.c[1]; c[2] -= s2.c[2];
00059 return *this;
00060 }
00061 Color &operator-=(float f) {
00062 c[0] -= f; c[1] -= f; c[2] -= f;
00063 return *this;
00064 }
00065 Color operator-(const Color &s2) const {
00066 Color ret = *this;
00067 ret.c[0] -= s2.c[0]; ret.c[1] -= s2.c[1]; ret.c[2] -= s2.c[2];
00068 return ret;
00069 }
00070 Color operator/(const Color &s2) const {
00071 Color ret = *this;
00072 ret.c[0] /= s2.c[0]; ret.c[1] /= s2.c[1]; ret.c[2] /= s2.c[2];
00073 return ret;
00074 }
00075 Color operator*(const Color &sp) const {
00076 Color ret = *this;
00077 ret.c[0] *= sp.c[0]; ret.c[1] *= sp.c[1]; ret.c[2] *= sp.c[2];
00078 return ret;
00079 }
00080 Color &operator*=(const Color &sp) {
00081 c[0] *= sp.c[0]; c[1] *= sp.c[1]; c[2] *= sp.c[2];
00082 return *this;
00083 }
00084 Color operator*(float a) const {
00085 Color ret = *this;
00086 ret.c[0] *= a; ret.c[1] *= a; ret.c[2] *= a;
00087 return ret;
00088 }
00089 Color &operator*=(float a) {
00090 c[0] *= a; c[1] *= a; c[2] *= a;
00091 return *this;
00092 }
00093 friend inline
00094 Color operator*(float a, const Color &s) {
00095 return s * a;
00096 }
00097 Color operator/(float a) const {
00098 return *this * (1.f / a);
00099 }
00100 Color &operator/=(float a) {
00101 float inv = 1.f / a;
00102 c[0] *= inv; c[1] *= inv; c[2] *= inv;
00103 return *this;
00104 }
00105 void AddWeighted(float w, const Color &s) {
00106 c[0] += w * s.c[0]; c[1] += w * s.c[1]; c[2] += w * s.c[2];
00107 }
00108 bool operator==(const Color &sp) const {
00109 if (c[0] != sp.c[0]) return false;
00110 if (c[1] != sp.c[1]) return false;
00111 if (c[2] != sp.c[2]) return false;
00112 return true;
00113 }
00114 bool operator!=(const Color &sp) const {
00115 return !(*this == sp);
00116 }
00117 bool Black() const {
00118 if (c[0] != 0.) return false;
00119 if (c[1] != 0.) return false;
00120 if (c[2] != 0.) return false;
00121 return true;
00122 }
00123 Color Sqrt() const {
00124 Color ret;
00125 ret.c[0] = sqrtf(c[0]);
00126 ret.c[1] = sqrtf(c[1]);
00127 ret.c[2] = sqrtf(c[2]);
00128 return ret;
00129 }
00130 Color Pow(const Color &e) const {
00131 Color ret;
00132 ret.c[0] = c[0] > 0 ? powf(c[0], e.c[0]) : 0.f;
00133 ret.c[1] = c[1] > 0 ? powf(c[1], e.c[1]) : 0.f;
00134 ret.c[2] = c[2] > 0 ? powf(c[2], e.c[2]) : 0.f;
00135 return ret;
00136 }
00137 Color Pow(float f) const {
00138 Color ret;
00139 ret.c[0] = c[0] > 0 ? powf(c[0], f) : 0.f;
00140 ret.c[1] = c[1] > 0 ? powf(c[1], f) : 0.f;
00141 ret.c[2] = c[2] > 0 ? powf(c[2], f) : 0.f;
00142 return ret;
00143 }
00144 Color operator-() const {
00145 Color ret;
00146 ret.c[0] = -c[0];
00147 ret.c[1] = -c[1];
00148 ret.c[2] = -c[2];
00149 return ret;
00150 }
00151 friend Color Exp(const Color &s) {
00152 Color ret;
00153 ret.c[0] = expf(s.c[0]);
00154 ret.c[1] = expf(s.c[1]);
00155 ret.c[2] = expf(s.c[2]);
00156 return ret;
00157 }
00158 Color Clamp(float low = 0.f,
00159 float high = INFINITY) const {
00160 Color ret;
00161 ret.c[0] = ::Clamp(c[0], low, high);
00162 ret.c[1] = ::Clamp(c[1], low, high);
00163 ret.c[2] = ::Clamp(c[2], low, high);
00164 return ret;
00165 }
00166 bool IsNaN() const {
00167 if (isnan(c[0])) return true;
00168 if (isnan(c[1])) return true;
00169 if (isnan(c[2])) return true;
00170 return false;
00171 }
00172 void Print(FILE *f) const {
00173 for (int i = 0; i < 3; ++i)
00174 fprintf(f, "%f ", c[i]);
00175 }
00176
00177 float Y() const {
00178 return 0.;
00179 }
00180
00181 bool operator<(const Color &s2) const {
00182 return Y() < s2.Y();
00183 }
00184 friend class lux::ParamSet;
00185
00186
00187 float c[3];
00188
00189 private:
00190 template<class Archive>
00191 void serialize(Archive & ar, const unsigned int version)
00192 {
00193 for (int i = 0; i < 3; ++i)
00194 ar & c[i];
00195 }
00196 };
00197
00198
00199 class RGBColor : public Color {
00200 public:
00201
00202 RGBColor(float v = 0.f) {
00203 c[0] = v; c[1] = v; c[2] = v;
00204 }
00205 RGBColor(const float cs[3]) {
00206 c[0] = cs[0]; c[1] = cs[1]; c[2] = cs[2];
00207 }
00208 RGBColor(const Color &color) {
00209 c[0] = color.c[0]; c[1] = color.c[1]; c[2] = color.c[2];
00210 }
00211
00212 float Y() const {
00213 return 0.212671f * c[0] + 0.715160f * c[1] + 0.072169f * c[2];
00214 }
00215 };
00216
00217
00218 class XYZColor : public Color {
00219
00220 friend class boost::serialization::access;
00221
00222 public:
00223
00224 XYZColor(float v = 0.f) {
00225 c[0] = v; c[1] = v; c[2] = v;
00226 }
00227 XYZColor(float cs[3]) {
00228 c[0] = cs[0]; c[1] = cs[1]; c[2] = cs[2];
00229 }
00230 XYZColor(const Color &color) {
00231 c[0] = color.c[0]; c[1] = color.c[1]; c[2] = color.c[2];
00232 }
00233
00234 float Y() const {
00235 return c[1];
00236 }
00237 };
00238
00246 class ColorSystem
00247 {
00248 public:
00249 ColorSystem(float xR, float yR, float xG, float yG, float xB, float yB,
00250 float xW, float yW, float lum = 1.);
00263 RGBColor ToRGBConstrained(const XYZColor &color) const {
00264 const float lum = color.Y();
00265 float c[3];
00266 c[0] = XYZToRGB[0][0] * color.c[0] + XYZToRGB[0][1] * color.c[1] + XYZToRGB[0][2] * color.c[2];
00267 c[1] = XYZToRGB[1][0] * color.c[0] + XYZToRGB[1][1] * color.c[1] + XYZToRGB[1][2] * color.c[2];
00268 c[2] = XYZToRGB[2][0] * color.c[0] + XYZToRGB[2][1] * color.c[1] + XYZToRGB[2][2] * color.c[2];
00269 RGBColor rgb(c);
00270 Constrain(lum, rgb);
00271 return rgb;
00272 }
00277 XYZColor ToXYZ(const RGBColor &color) const {
00278 float c[3];
00279 c[0] = RGBToXYZ[0][0] * color.c[0] + RGBToXYZ[0][1] * color.c[1] + RGBToXYZ[0][2] * color.c[2];
00280 c[1] = RGBToXYZ[1][0] * color.c[0] + RGBToXYZ[1][1] * color.c[1] + RGBToXYZ[1][2] * color.c[2];
00281 c[2] = RGBToXYZ[2][0] * color.c[0] + RGBToXYZ[2][1] * color.c[1] + RGBToXYZ[2][2] * color.c[2];
00282 return XYZColor(c);
00283 }
00284
00285 bool Constrain(float lum, RGBColor &rgb) const;
00286 RGBColor Limit(const RGBColor &rgb, int method) const;
00287 float xRed, yRed;
00288 float xGreen, yGreen;
00289 float xBlue, yBlue;
00290 float xWhite, yWhite;
00291 float luminance;
00292 float XYZToRGB[3][3];
00293 float RGBToXYZ[3][3];
00294 };
00295
00296
00297 inline ostream &operator<<(ostream &os, const RGBColor &s) {
00298 for (int i = 0; i < 3; ++i) {
00299 os << s.c[i];
00300 if (i != 3-1)
00301 os << ", ";
00302 }
00303 return os;
00304 }
00305
00306
00307 inline ostream &operator<<(ostream &os, const XYZColor &s) {
00308 for (int i = 0; i < 3; ++i) {
00309 os << s.c[i];
00310 if (i != 3-1)
00311 os << ", ";
00312 }
00313 return os;
00314 }
00315
00316 }
00317
00318 #endif // LUX_COLOR_H