2 * psychlops_g_color.cpp
3 * Psychlops Standard Library (Universal)
5 * Last Modified 2006/01/04 by Kenchi HOSOKAWA
6 * (C) 2006 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
15 #include "../ApplicationInterfaces/psychlops_code_exception.h"
16 #include "../math/psychlops_m_util.h"
17 #include "psychlops_g_color.h"
18 #include "psychlops_g_canvas.h"
23 bool Color::strict_match = false;
24 bool Color::force_software_calibration_ = false;
25 Color::CALIBRATION_MODE Color::calibration_mode_ = NOTHING;
26 double Color::gamma_r_inversed_=1.0, Color::gamma_g_inversed_=1.0, Color::gamma_b_inversed_=1.0;
27 double Color::gamma_r_=1.0, Color::gamma_g_=1.0, Color::gamma_b_=1.0;
28 int Color::table_size_=0;
29 std::vector<double> Color::table_r_, Color::table_g_, Color::table_b_;
30 std::multimap<double, double> Color::restore_table_r_, Color::restore_table_g_, Color::restore_table_b_;
32 void Color::forceSoftwareCalibration(bool on_off) {
33 //bool mismatched = false;
34 force_software_calibration_ = on_off;
35 if(force_software_calibration_) {
36 switch(calibration_mode_) {
38 set_ = &set_correct_value;
39 get_ = &get_restore_gamma;
40 calibration_mode_ = SOFTWARE_GAMMA_VALUE;
43 set_ = &set_correct_table;
44 get_ = &get_restore_table;
45 calibration_mode_ = SOFTWARE_TABLE;
51 switch(calibration_mode_) {
52 case SOFTWARE_GAMMA_VALUE:
53 setGammaValue(gamma_r_, gamma_g_, gamma_b_);
56 setGammaTable(table_r_, table_g_, table_b_);
63 void Color::setGammaValue(double r, double g, double b) {
64 bool mismatched = force_software_calibration_;
68 if(!force_software_calibration_) {
70 Display::setGammaValue(r, g, b);
73 calibration_mode_ = GAMMA_VALUE;
74 } catch(Exception e) {
79 if(strict_match) throw Exception(typeid(Color), "API ERROR", "Failed to set color calibration table for the video renderer.");
80 set_ = &set_correct_value;
81 get_ = &get_restore_gamma;
82 gamma_r_inversed_ = 1.0/r;
83 gamma_g_inversed_ = 1.0/g;
84 gamma_b_inversed_ = 1.0/b;
85 gray.set(0.5,0.5,0.5);
86 calibration_mode_ = SOFTWARE_GAMMA_VALUE;
89 void Color::setGammaValue(const double r, const double g, const double b, const CALIBRATION_MODE mode) {
92 force_software_calibration_ = false;
94 case SOFTWARE_GAMMA_VALUE:
95 force_software_calibration_ = true;
98 force_software_calibration_ = true;
104 throw Exception("Color::setGammaValue: Specified color calibration mode and value type are mismatched.");
108 setGammaValue(r, g, b);
112 calibration_mode_ = BITS_MONO;
113 set_ = &set_correct_bits_mono;
114 get_ = &get_restore_bits_mono;
119 case SOFTWARE_GAMMA_VALUE:
124 void Color::setGammaTable(const double * const table_r, const double * const table_g, const double * const table_b, const int num_steps) {
125 std::vector<double> tr(num_steps), tg(num_steps), tb(num_steps);
126 for(int i=0; i<num_steps; i++) {
131 setGammaTable(tr, tg, tb);
133 inline int max_int(int a, int b) {
134 return (a>b ? a : b);
136 void Color::setGammaTable(const std::vector<double> &table_r, const std::vector<double> &table_g, const std::vector<double> &table_b) {
137 bool mismatched = force_software_calibration_;
139 if(strict_match && (table_r.size()!=table_g.size() || table_r.size()!=table_b.size()))
140 throw Exception(typeid(Color), "API ERROR", "Failed to set color calibration table because table sizes were unmatched between R/G/B tables.");
141 table_size_ = (max_int(table_r.size(), max_int( table_g.size(), table_b.size() ) ), 256);
143 interpolateDiscreteSamplesInLinearFunction(table_r, table_r_);
144 interpolateDiscreteSamplesInLinearFunction(table_g, table_g_);
145 interpolateDiscreteSamplesInLinearFunction(table_b, table_b_);
147 for(int i=0; i<table_size_; i++) {
148 restore_table_r_.insert( std::pair<double, double>(table_r_[i], i/(table_size_-1.0)) );
149 restore_table_g_.insert( std::pair<double, double>(table_g_[i], i/(table_size_-1.0)) );
150 restore_table_b_.insert( std::pair<double, double>(table_b_[i], i/(table_size_-1.0)) );
153 if(!force_software_calibration_) {
155 Display::setGammaTable(table_r_, table_g_, table_b_);
158 calibration_mode_ = TABLE;
159 } catch(Exception e) {
164 if(strict_match) throw Exception(typeid(Color), "API ERROR", "Failed to set color calibration table for the video renderer.");
165 set_ = &set_correct_table;
166 get_ = &get_restore_table;
167 calibration_mode_ = SOFTWARE_TABLE;
170 void Color::interpolateDiscreteSamplesInLinearFunction(const std::vector<double> &source, std::vector<double> &target) {
171 double full, integer, fraction;
172 if(source.size()<table_size_) {
174 target.resize(table_size_);
175 for(int i=0; i<table_size_; i++) {
176 full = ((double)i/(table_size_-1))*(source.size()-1);
177 fraction = modf(full, &integer);
178 if( integer==source.size()-1) {
179 target[i] = limitvalue(source[(int)integer]);
181 target[i] = limitvalue((1.0-fraction)*source[(int)integer] + (fraction)*source[(int)integer+1]);
186 target.resize(table_size_);
187 for(int i=0; i<table_size_; i++) {
188 target[i] = limitvalue(source[i]);
192 Color::CALIBRATION_MODE Color::getCalibrationMode() {
193 return calibration_mode_;
198 inline double Color::Int8toFloat64(int value) {
201 inline double Color::limitvalue(double value) {
203 if(strict_match) throw new Exception("Color.set : STRICT MATCH FAILED : Argument was under 0.0 .");
205 } else if( value>1.0 ) {
206 if(strict_match) throw new Exception("Color.set : STRICT MATCH FAILED : Argument was over 1.0 .");
211 // inline double Color::restoregamma_r(double value) { return pow(value,gamma_r_); }
212 // inline double Color::restoregamma_g(double value) { return pow(value,gamma_g_); }
213 // inline double Color::restoregamma_b(double value) { return pow(value,gamma_b_); }
214 // inline double Color::restoretable_r(double value) { return restore_table_r_.find(val)->second; }
215 // inline double Color::restoretable_g(double value) { return restore_table_r_.find(val)->second; }
216 // inline double Color::restoretable_b(double value) { return restore_table_r_.find(val)->second; }
218 void Color::set_direct(Color * col, double r, double g, double b, double a) {
219 col->Red = limitvalue(r);
220 col->Green = limitvalue(g);
221 col->Blue = limitvalue(b);
222 col->Alpha = limitvalue(a);
224 void Color::set_correct_value(Color * col, double r, double g, double b, double a) {
225 col->Red = limitvalue(pow(r,gamma_r_inversed_));
226 col->Green = limitvalue(pow(g,gamma_g_inversed_));
227 col->Blue = limitvalue(pow(b,gamma_b_inversed_));
228 col->Alpha = limitvalue(a);
230 void Color::set_correct_table(Color * col, double r, double g, double b, double a) {
231 col->Red = table_r_[(int)(Math::round((table_size_-1)*r))];
232 col->Green = table_g_[(int)(Math::round((table_size_-1)*g))];
233 col->Blue = table_b_[(int)(Math::round((table_size_-1)*b))];
234 col->Alpha = limitvalue(a);
236 void (*Color::set_)(Color * col, double r, double g, double b, double a) = &set_direct;
238 void Color::get_direct(const Color &col, double &r, double &g, double &b, double &a) {
244 void Color::get_restore_gamma(const Color &col, double &r, double &g, double &b, double &a) {
245 r = pow(col.Red,gamma_r_);
246 g = pow(col.Green,gamma_g_);
247 b = pow(col.Blue,gamma_b_);
250 void Color::get_restore_table(const Color &col, double &r, double &g, double &b, double &a) {
251 r = restore_table_r_.find(col.Red)->second;
252 g = restore_table_g_.find(col.Green)->second;
253 b = restore_table_b_.find(col.Blue)->second;
256 void (*Color::get_)(const Color &col, double &r, double &g, double &b, double &a) = &get_direct;
260 Color::Color() { set_(this, 0.0, 0.0, 0.0, 1.0); }
261 Color::Color(double r, double g, double b, double a) { set_(this,r,g,b,a); }
262 Color::Color(double r, double g, double b, double a, bool dummy) { set_direct(this,r,g,b,a); }
263 Color::Color(double gray) { set_(this,gray,gray,gray,1.0); }
264 Color &Color::set(double r, double g, double b, double a) { set_(this,r,g,b,a); return *this; }
265 Color &Color::set(double r, double g, double b, double a, bool dummy) { set_direct(this,r,g,b,a); return *this; }
266 Color &Color::set(double gray) { set_(this,gray,gray,gray,1.0); return *this; }
268 double Color::getR() const {
270 get_(*this, r, g, b, a);
273 double Color::getG() const {
275 get_(*this, r, g, b, a);
278 double Color::getB() const {
280 get_(*this, r, g, b, a);
283 double Color::getA() const {
286 void Color::get(double &r, double &g, double &b, double &a) const {
287 get_(*this, r, g, b, a);
291 Color Color::dup() const {
295 bool Color::operator ==(Color rhs) {
296 if(Red==rhs.Red && Green==rhs.Green && Blue==rhs.Blue && Alpha==rhs.Alpha) {
302 Color Color::operator +(Color rhs) {
305 Color Color::operator -(Color rhs) {
308 Color & Color::operator +=(Color rhs) {
309 Red += limitvalue(rhs.Red);
310 Green += limitvalue(rhs.Green);
311 Blue += limitvalue(rhs.Blue);
312 Alpha += limitvalue(rhs.Alpha);
315 Color & Color::operator -=(Color rhs) {
316 Red -= limitvalue(rhs.Red);
317 Green -= limitvalue(rhs.Green);
318 Blue -= limitvalue(rhs.Blue);
319 Alpha -= limitvalue(rhs.Alpha);
324 Color Color::white(1.0);
325 Color Color::black(0.0);
326 Color Color::gray(0.5);
327 Color Color::red(1.0,0.0,0.0);
328 Color Color::green(0.0,1.0,0.0);
329 Color Color::blue(0.0,0.0,1.0);
330 Color Color::cyan(0.0,1.0,1.0);
331 Color Color::magenta(1.0,0.0,1.0);
332 Color Color::yellow(1.0,1.0,0.0);
334 const Color Color::null_color(0,0,0,0,false);
338 void Color::set_correct_bits_mono(Color * col, double r, double g, double b, double a) {
339 if(a!=1) throw new Exception("Color.set : alpha value is disabled for Bits++.");
340 unsigned short wordlum = (unsigned short)(limitvalue(pow(r,gamma_r_inversed_))*65535);
341 col->Red = (double)((wordlum>>8)/255.0);
342 col->Green = (double)((wordlum&255)/255.0);
346 void Color::get_restore_bits_mono(const Color &col, double &r, double &g, double &b, double &a) {
347 double lum = ( ((unsigned short)(col.Red*255) << 8) + (unsigned short)(col.Green*255) ) / 65535.0;
348 r = pow(lum,gamma_r_);
354 } /* <- namespace Psycholops */