OSDN Git Service

first
[psychlops/cpp.git] / psychlops / core / graphic / psychlops_g_color.cpp
1 /*
2  *  psychlops_g_color.cpp
3  *  Psychlops Standard Library (Universal)
4  *
5  *  Last Modified 2006/01/04 by Kenchi HOSOKAWA
6  *  (C) 2006 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
7  */
8
9
10 #include <Math.h>
11 #include <float.h>
12 #include <vector>
13 #include <map>
14
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"
19
20
21 namespace Psychlops {
22
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_;
31
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_) {
37                         case GAMMA_VALUE:
38                                 set_ = &set_correct_value;
39                                 get_ = &get_restore_gamma;
40                                 calibration_mode_ = SOFTWARE_GAMMA_VALUE;
41                                 break;
42                         case TABLE:
43                                 set_ = &set_correct_table;
44                                 get_ = &get_restore_table;
45                                 calibration_mode_ = SOFTWARE_TABLE;
46                                 break;
47                         default:
48                                 break;
49                         }
50                 } else {
51                         switch(calibration_mode_) {
52                         case SOFTWARE_GAMMA_VALUE:
53                                 setGammaValue(gamma_r_, gamma_g_, gamma_b_);
54                                 break;
55                         case SOFTWARE_TABLE:
56                                 setGammaTable(table_r_, table_g_, table_b_);
57                                 break;
58                         default:
59                                 break;
60                         }
61                 }
62         }
63         void Color::setGammaValue(double r, double g, double b) {
64                 bool mismatched = force_software_calibration_;
65                 gamma_r_ = r;
66                 gamma_g_ = g;
67                 gamma_b_ = b;
68                 if(!force_software_calibration_) {
69                         try {
70                                 Display::setGammaValue(r, g, b);
71                                 set_ = &set_direct;
72                                 get_ = &get_direct;
73                                 calibration_mode_ = GAMMA_VALUE;
74                         } catch(Exception e) {
75                                 mismatched = true;
76                         }
77                 }
78                 if(mismatched) {
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;
87                 }
88         }
89         void Color::setGammaValue(const double r, const double g, const double b, const CALIBRATION_MODE mode) {
90                 switch(mode) {
91                         case GAMMA_VALUE:
92                                 force_software_calibration_ = false;
93                                 break;
94                         case SOFTWARE_GAMMA_VALUE:
95                                 force_software_calibration_ = true;
96                                 break;
97                         case BITS_MONO:
98                                 force_software_calibration_ = true;
99                                 break;
100                         case NOTHING:
101                         case TABLE:
102                         case SOFTWARE_TABLE:
103                         default:
104                                 throw Exception("Color::setGammaValue: Specified color calibration mode and value type are mismatched.");
105                                 break;
106                 }
107
108                 setGammaValue(r, g, b);
109
110                 switch(mode) {
111                         case BITS_MONO:
112                                 calibration_mode_ = BITS_MONO;
113                                 set_ = &set_correct_bits_mono;
114                                 get_ = &get_restore_bits_mono;
115                                 break;
116                         case NOTHING:
117                         case GAMMA_VALUE:
118                         case TABLE:
119                         case SOFTWARE_GAMMA_VALUE:
120                         case SOFTWARE_TABLE:
121                                 break;
122                 }
123         }
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++) {
127                         tr[i] = table_r[i];
128                         tg[i] = table_g[i];
129                         tb[i] = table_b[i];
130                 }
131                 setGammaTable(tr, tg, tb);
132         }
133 inline int max_int(int a, int b) {
134         return (a>b ? a : b);
135 }
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_;
138
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);
142
143                 interpolateDiscreteSamplesInLinearFunction(table_r, table_r_);
144                 interpolateDiscreteSamplesInLinearFunction(table_g, table_g_);
145                 interpolateDiscreteSamplesInLinearFunction(table_b, table_b_);
146
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)) );
151                 }
152
153                 if(!force_software_calibration_) {
154                         try {
155                                 Display::setGammaTable(table_r_, table_g_, table_b_);
156                                 set_ = &set_direct;
157                                 get_ = &get_direct;
158                                 calibration_mode_ = TABLE;
159                         } catch(Exception e) {
160                                 mismatched = true;
161                         }
162                 }
163                 if(mismatched) {
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;
168                 }
169         }
170         void Color::interpolateDiscreteSamplesInLinearFunction(const std::vector<double> &source, std::vector<double> &target) {
171                 double full, integer, fraction;
172                 if(source.size()<table_size_) {
173                         target.clear();
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]);
180                                 } else {
181                                         target[i] = limitvalue((1.0-fraction)*source[(int)integer] + (fraction)*source[(int)integer+1]);
182                                 }
183                         }
184                 } else {
185                         target.clear();
186                         target.resize(table_size_);
187                         for(int i=0; i<table_size_; i++) {
188                                 target[i] = limitvalue(source[i]);
189                         }
190                 }
191         }
192         Color::CALIBRATION_MODE Color::getCalibrationMode() {
193                 return calibration_mode_;
194         }
195
196
197
198         inline double Color::Int8toFloat64(int value) {
199                 return value/255.0;
200         }
201         inline double Color::limitvalue(double value) {
202                 if( value<0.0 ) {
203                         if(strict_match) throw new Exception("Color.set : STRICT MATCH FAILED : Argument was under 0.0 .");
204                         value = 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 .");
207                         value = 1.0;
208                 }
209                 return value;
210         }
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; }
217
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);
223         }
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);
229         }
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);
235         }
236         void (*Color::set_)(Color * col, double r, double g, double b, double a) = &set_direct;
237
238         void Color::get_direct(const Color &col, double &r, double &g, double &b, double &a) {
239                 r = col.Red;
240                 g = col.Green;
241                 b = col.Blue;
242                 a = col.Alpha;
243         }
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_);
248                 a = col.Alpha;
249         }
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;
254                 a = col.Alpha;
255         }
256         void (*Color::get_)(const Color &col, double &r, double &g, double &b, double &a) = &get_direct;
257
258
259
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; }
267
268         double Color::getR() const {
269                 double r, g, b, a;
270                 get_(*this, r, g, b, a);
271                 return r;
272         }
273         double Color::getG() const {
274                 double r, g, b, a;
275                 get_(*this, r, g, b, a);
276                 return g;
277         }
278         double Color::getB() const {
279                 double r, g, b, a;
280                 get_(*this, r, g, b, a);
281                 return b;
282         }
283         double Color::getA() const {
284                 return Alpha;
285         }
286         void Color::get(double &r, double &g, double &b, double &a) const {
287                 get_(*this, r, g, b, a);
288         }
289
290
291         Color Color::dup() const {
292                 return *this;
293         }
294
295         bool Color::operator ==(Color rhs) {
296                 if(Red==rhs.Red && Green==rhs.Green && Blue==rhs.Blue && Alpha==rhs.Alpha) {
297                         return true;
298                 } else {
299                         return false;
300                 }
301         }
302         Color Color::operator +(Color rhs) {
303                 return dup()+=rhs;
304         }
305         Color Color::operator -(Color rhs) {
306                 return dup()-=rhs;
307         }
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);
313                 return (*this);
314         }
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);
320                 return (*this);
321         }
322
323
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);
333
334         const Color Color::null_color(0,0,0,0,false);
335
336
337
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);
343                 col->Blue = 0;
344                 col->Alpha = 1;
345         }
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_);
349                 g = r;
350                 b = r;
351                 a = 1;
352         }
353
354 }       /*      <- namespace Psycholops         */
355
356