00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "color.h"
00025 #include "geometry/matrix3x3.h"
00026
00027 using namespace lux;
00028
00029 namespace lux
00030 {
00031
00032 static float dot(const float a[3], const float b[3])
00033 {
00034 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
00035 }
00036
00053 ColorSystem::ColorSystem(float xR, float yR, float xG, float yG, float xB, float yB,
00054 float xW, float yW, float lum)
00055 : xRed(xR), yRed(yR), xGreen(xG), yGreen(yG), xBlue(xB), yBlue(yB),
00056 xWhite(xW), yWhite(yW), luminance(lum)
00057 {
00058 float red[3] = {xRed / yRed, 1.f, (1.f - xRed - yRed) / yRed};
00059 float green[3] = {xGreen / yGreen, 1.f, (1.f - xGreen - yGreen) / yGreen};
00060 float blue[3] = {xBlue / yBlue, 1.f, (1.f - xBlue - yBlue) / yBlue};
00061 float white[3] = {xWhite / yWhite, 1.f, (1.f - xWhite - yWhite) / yWhite};
00062 float rgb[3][3];
00063 rgb[0][0] = red[0]; rgb[1][0] = red[1]; rgb[2][0] = red[2];
00064 rgb[0][1] = green[0]; rgb[1][1] = green[1]; rgb[2][1] = green[2];
00065 rgb[0][2] = blue[0]; rgb[1][2] = blue[1]; rgb[2][2] = blue[2];
00066 Invert3x3(rgb, rgb);
00067 float y[3];
00068 Transform3x3(rgb, white, y);
00069 float x[3] = {y[0] * red[0], y[1] * green[0], y[2] * blue[0]};
00070 float z[3] = {y[0] * red[2], y[1] * green[2], y[2] * blue[2]};
00071 rgb[0][0] = x[0] + white[0]; rgb[1][0] = x[1] + white[0]; rgb[2][0] = x[2] + white[0];
00072 rgb[0][1] = y[0] + white[1]; rgb[1][1] = y[1] + white[1]; rgb[2][1] = y[2] + white[1];
00073 rgb[0][2] = z[0] + white[2]; rgb[1][2] = z[1] + white[2]; rgb[2][2] = z[2] + white[2];
00074 float matrix[3][3];
00075 matrix[0][0] = (dot(x, x) + white[0] * white[0]) * luminance;
00076 matrix[1][0] = (dot(x, y) + white[1] * white[0]) * luminance;
00077 matrix[2][0] = (dot(x, z) + white[2] * white[0]) * luminance;
00078 matrix[0][1] = (dot(y, x) + white[0] * white[1]) * luminance;
00079 matrix[1][1] = (dot(y, y) + white[1] * white[1]) * luminance;
00080 matrix[2][1] = (dot(y, z) + white[2] * white[1]) * luminance;
00081 matrix[0][2] = (dot(z, x) + white[0] * white[2]) * luminance;
00082 matrix[1][2] = (dot(z, y) + white[1] * white[2]) * luminance;
00083 matrix[2][2] = (dot(z, z) + white[2] * white[2]) * luminance;
00084 Invert3x3(matrix, matrix);
00085
00086 Multiply3x3(rgb, matrix, XYZToRGB);
00087 Invert3x3(XYZToRGB, RGBToXYZ);
00088 }
00089
00097 static inline bool LowGamut(const RGBColor &color)
00098 {
00099 return color.c[0] < 0.f || color.c[1] < 0.f || color.c[2] < 0.f;
00100 }
00101
00109 static inline bool HighGamut(const RGBColor &color)
00110 {
00111 return color.c[0] > 1.f || color.c[1] > 1.f || color.c[2] > 1.f;
00112 }
00113
00133 bool ColorSystem::Constrain(float lum, RGBColor &rgb) const
00134 {
00135 bool constrain = false;
00136
00137 if (LowGamut(rgb)) {
00138 if (lum < 0.f) {
00139 rgb = 0.f;
00140 return true;
00141 }
00142
00143
00144
00145
00146 float l = lum / luminance;
00147 float parameter;
00148 if (rgb.c[0] < rgb.c[1] && rgb.c[0] < rgb.c[2]) {
00149 parameter = l / (l - rgb.c[0]);
00150 } else if (rgb.c[1] < rgb.c[2]) {
00151 parameter = l / (l - rgb.c[1]);
00152 } else {
00153 parameter = l / (l - rgb.c[2]);
00154 }
00155
00156
00157 rgb = Lerp(parameter, RGBColor(l), rgb).Clamp();
00158 constrain = true;
00159 }
00160
00161 return constrain;
00162 }
00163
00164 RGBColor ColorSystem::Limit(const RGBColor &rgb, int method) const
00165 {
00166 if (HighGamut(rgb)) {
00167 if (method == 2)
00168 return rgb.Clamp(0.f, 1.f);
00169 const float lum = method == 0 ? RGBToXYZ[1][0] * rgb.c[0] + RGBToXYZ[1][1] * rgb.c[1] + RGBToXYZ[1][2] * rgb.c[2] : luminance / 3.f;
00170 if (lum > luminance)
00171 return RGBColor(1.f);
00172
00173
00174
00175
00176 float l = lum / luminance;
00177 float parameter;
00178 if (rgb.c[0] > rgb.c[1] && rgb.c[0] > rgb.c[2]) {
00179 parameter = (1.f - l) / (rgb.c[0] - l);
00180 } else if (rgb.c[1] > rgb.c[2]) {
00181 parameter = (1.f - l) / (rgb.c[1] - l);
00182 } else {
00183 parameter = (1.f - l) / (rgb.c[2] - l);
00184 }
00185
00186
00187 return Lerp(parameter, RGBColor(l), rgb);
00188 }
00189 return rgb;
00190 }
00191
00192 }
00193