OSDN Git Service

first
[psychlops/cpp.git] / psychlops / platform / gl / psychlops_g_image_GL.cpp
1 /*
2  *  psychlops_g_image_Win32_GL.cpp
3  *  Psychlops Standard Library (Universal)
4  *
5  *  Last Modified 2007/07/07 by Kenchi HOSOKAWA
6  *  (C) 2006 Kenchi HOSOKAWA, Kazushi MARUYA and Takao SATO
7  */
8
9
10
11 #include <stdlib.h>
12 #include <Math.h>
13
14
15 #define PSYCHLOPS_WINDOW_API_PLATFORM
16 #include "../psychlops_platform_selector.h"
17 #include "../../core/graphic/psychlops_g_image.h"
18
19
20
21 namespace Psychlops {
22
23         const int APIImageProperties::PixCompGL_[3] = { GL_LUMINANCE, GL_RGB, GL_RGBA };
24         const int APIImageProperties::PixPrecGL_[2] = { GL_UNSIGNED_BYTE, GL_FLOAT };
25
26
27         class ImageManipulator {
28                 friend class Image;
29                 inline static int pix_offset(const Image &img, const int x, const int iy) {
30                         int y = img.height_-iy-1;
31                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
32                         return y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
33                 }
34                 inline static unsigned char round8bit(double value) {
35                         double val = value*255.0+0.5, integer_part, frac;
36                         frac = modf(val, &integer_part);
37                         if(frac!=0.0) return (unsigned char)integer_part;
38                         if((int)(integer_part)%2==0) return (unsigned char)integer_part; else return (unsigned char)integer_part-1;
39                 }
40
41
42
43                 inline static void pix_gen_ub_1(unsigned char *p, const Color &col) { *(p) = round8bit(col.Red); }
44                 inline static void pix_gen_ub_3(unsigned char *p, const Color &col) { *(p) = round8bit(col.Red); *(++p) = round8bit(col.Green); *(++p) = round8bit(col.Blue); }
45                 inline static void pix_gen_ub_4(unsigned char *p, const Color &col) { *(p) = round8bit(col.Red); *(++p) = round8bit(col.Green); *(++p) = round8bit(col.Blue); *(++p) = round8bit(col.Alpha); }\r
46                 inline static void pix_gen_f_1(float *p, const Color &col) { *(p) = (float)(col.Red); }
47                 inline static void pix_gen_f_3(float *p, const Color &col) { *(p) = (float)(col.Red); *(++p) = (float)(col.Green); *(++p) = (float)(col.Blue); }
48                 inline static void pix_gen_f_4(float *p, const Color &col) { *(p) = (float)(col.Red); *(++p) = (float)(col.Green); *(++p) = (float)(col.Blue); *(++p) = (float)(col.Alpha); }
49
50 //      through
51
52                 static void (*(pix_direct_[2][3]))(const Image &, const int, const int, const Color&);// = { { &pix_d_ub_l_, &pix_d_ub_rgb_ , &pix_d_ub_rgba_ } , { &pix_d_f_l_, &pix_d_f_rgb_ , &pix_d_f_rgba_ }  };
53
54                 static void pix_d_ub_l_   (const Image &img, const int ix, const int iy, const Color &col) { pix_gen_ub_1( img.bitmapub_ + pix_offset(img, ix, iy), col ); }
55                 static void pix_d_f_l_    (const Image &img, const int ix, const int iy, const Color &col) { pix_gen_f_1 ( img.bitmapf_  + pix_offset(img, ix, iy), col ); }
56                 static void pix_d_ub_rgb_ (const Image &img, const int ix, const int iy, const Color &col) { pix_gen_ub_3( img.bitmapub_ + pix_offset(img, ix, iy), col ); }
57                 static void pix_d_f_rgb_  (const Image &img, const int ix, const int iy, const Color &col) { pix_gen_f_3 ( img.bitmapf_  + pix_offset(img, ix, iy), col ); }
58                 static void pix_d_ub_rgba_(const Image &img, const int ix, const int iy, const Color &col) { pix_gen_ub_4( img.bitmapub_ + pix_offset(img, ix, iy), col ); }
59                 static void pix_d_f_rgba_ (const Image &img, const int ix, const int iy, const Color &col) { pix_gen_f_4 ( img.bitmapf_  + pix_offset(img, ix, iy), col ); }
60
61
62 // ALPHA BLENDING INCLUDED
63
64                 static void (*(pix_[2][3]))(const Image &, const int, const int, const Color&);// = { { &pix_ub_l_, &pix_ub_rgb_ , &pix_ub_rgba_ } , { &pix_f_l_, &pix_f_rgb_ , &pix_f_rgba_ }  };
65
66                 static void pix_ub_l_(const Image &img, const int ix, const int iy, const Color &col) {
67                         pix_gen_ub_1(img.bitmapub_ + pix_offset(img, ix, iy), col);
68                 }
69                 static void pix_f_l_(const Image &img, const int ix, const int iy, const Color &col) {
70                         pix_gen_f_1(img.bitmapf_ + pix_offset(img, ix, iy), col);
71                 }
72                 static void pix_ub_rgb_(const Image &img, const int ix, const int iy, const Color &col) {
73                         unsigned char *p = img.bitmapub_ + pix_offset(img, ix, iy);
74                         if(Color::getCalibrationMode()==Color::SOFTWARE_GAMMA_VALUE || Color::getCalibrationMode()==Color::SOFTWARE_TABLE) {
75                                 double red, green, blue, alpha;
76                                 col.get(red, green, blue, alpha);
77                                 Color xcol = getpix_ub_rgb_(img, ix, iy);
78                                 double xred, xgreen, xblue, xalpha;
79                                 xcol.get(xred, xgreen, xblue, xalpha);
80                                 Color ycol(
81                                         (1.0-alpha)*xred   + alpha*red,
82                                         (1.0-alpha)*xgreen + alpha*green,
83                                         (1.0-alpha)*xblue  + alpha*blue,
84                                         (1.0-alpha)*xalpha + alpha*alpha
85                                 );
86                                 *(p)   = round8bit(ycol.Red);
87                                 *(++p) = round8bit(ycol.Green);
88                                 *(++p) = round8bit(ycol.Blue);
89                         } else {
90                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Red)); p++;
91                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Green)); p++;
92                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Blue)); p++;
93                         }
94                 }
95                 static void pix_f_rgb_(const Image &img, const int ix, const int iy, const Color &col) {
96                         float *p = img.bitmapf_ + pix_offset(img, ix, iy);
97                         if(Color::getCalibrationMode()==Color::SOFTWARE_GAMMA_VALUE || Color::getCalibrationMode()==Color::SOFTWARE_TABLE) {
98                                 double red, green, blue, alpha;
99                                 col.get(red, green, blue, alpha);
100                                 Color xcol = getpix_f_rgba_(img, ix, iy);
101                                 double xred, xgreen, xblue, xalpha;
102                                 xcol.get(xred, xgreen, xblue, xalpha);
103                                 Color ycol(
104                                         (1.0-alpha)*xred   + alpha*red,
105                                         (1.0-alpha)*xgreen + alpha*green,
106                                         (1.0-alpha)*xblue  + alpha*blue,
107                                         (1.0-alpha)*xalpha + alpha*alpha
108                                 );
109                                 *(p)   = (float)(ycol.Red);
110                                 *(++p) = (float)(ycol.Green);
111                                 *(++p) = (float)(ycol.Blue);
112                         } else {
113                                 *(p)   = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Red);
114                                 *(++p) = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Green);
115                                 *(++p) = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Blue);
116                         }
117                 }
118                 static void pix_ub_rgba_(const Image &img, const int ix, const int iy, const Color &col) {
119                         unsigned char *p = img.bitmapub_ + pix_offset(img, ix, iy);
120                         if(Color::getCalibrationMode()==Color::SOFTWARE_GAMMA_VALUE || Color::getCalibrationMode()==Color::SOFTWARE_TABLE) {
121                                 double red, green, blue, alpha;
122                                 col.get(red, green, blue, alpha);
123                                 Color xcol = getpix_ub_rgba_(img, ix, iy);
124                                 double xred, xgreen, xblue, xalpha;
125                                 xcol.get(xred, xgreen, xblue, xalpha);
126                                 Color ycol(
127                                         (1.0-alpha)*xred   + alpha*red,
128                                         (1.0-alpha)*xgreen + alpha*green,
129                                         (1.0-alpha)*xblue  + alpha*blue,
130                                         (1.0-alpha)*xalpha + alpha*alpha
131                                 );
132                                 *(p)   = round8bit(ycol.Red);
133                                 *(++p) = round8bit(ycol.Green);
134                                 *(++p) = round8bit(ycol.Blue);
135                                 *(++p) = round8bit(ycol.Alpha);
136                         } else {
137                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Red)); p++;
138                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Green)); p++;
139                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Blue)); p++;
140                                 *(p) = round8bit(((1.0-col.Alpha)*(*p/255.0) + col.Alpha*col.Alpha));
141                         }
142                 }
143                 static void pix_f_rgba_(const Image &img, const int ix, const int iy, const Color &col) {
144                         float *p = img.bitmapf_ + pix_offset(img, ix, iy);
145                         if(Color::getCalibrationMode()==Color::SOFTWARE_GAMMA_VALUE || Color::getCalibrationMode()==Color::SOFTWARE_TABLE) {
146                                 double red, green, blue, alpha;
147                                 col.get(red, green, blue, alpha);
148                                 Color xcol = getpix_f_rgba_(img, ix, iy);
149                                 double xred, xgreen, xblue, xalpha;
150                                 xcol.get(xred, xgreen, xblue, xalpha);
151                                 Color ycol(
152                                         (1.0-alpha)*xred   + alpha*red,
153                                         (1.0-alpha)*xgreen + alpha*green,
154                                         (1.0-alpha)*xblue  + alpha*blue,
155                                         (1.0-alpha)*xalpha + alpha*alpha
156                                 );
157                                 *(p)   = (float)(ycol.Red);
158                                 *(++p) = (float)(ycol.Green);
159                                 *(++p) = (float)(ycol.Blue);
160                                 *(++p) = (float)(ycol.Alpha);
161                         } else {
162                                 *(p)   = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Red);
163                                 *(++p) = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Green);
164                                 *(++p) = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Blue);
165                                 *(++p) = (float)((1.0-col.Alpha)*(*p) + col.Alpha*col.Alpha);
166                         }
167                 }
168
169
170                 static void (*(pix_alpha_[2][3]))(const Image &, const int, const int, const double);//    = { { &alpha_null_, &alpha_null_ , &alpha_ub_rgba_ } , { &alpha_null_, &alpha_null_ , &alphs_f_rgba_ }  };
171
172                 static void alpha_null_(const Image &img, const int ix, const int iy, const double alpha) {
173                         int x = ix, y = img.height_-iy-1;
174                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
175                 }
176                 static void alpha_ub_rgba_(const Image &img, const int ix, const int iy, const double alpha) {
177                         int x = ix, y = img.height_-iy-1;
178                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
179                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
180                         unsigned char *p = img.bitmapub_ + offset;
181                         *(p+3) = round8bit(alpha);
182                 }
183                 static void alpha_f_rgba_(const Image &img, const int ix, const int iy, const double alpha) {
184                         int x = ix, y = img.height_-iy-1;
185                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
186                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
187                         float *p = img.bitmapf_ + offset;
188                         *(p+3) = (float)alpha;
189                 }
190
191
192
193                 static Color (*(getpix_[2][3]))(const Image &, int, int);// = { { &getpix_ub_l_, &getpix_ub_rgb_ , &getpix_ub_rgba_ } , { &getpix_f_l_, &getpix_f_rgb_ , &getpix_f_rgba_ }  };
194
195                 static Color getpix_ub_l_(const Image &img, int ix, int iy) {
196                         int x = ix, y = img.height_-iy-1;
197                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
198                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
199                         return Color(*(img.bitmapub_+offset)/255.0, *(img.bitmapub_+offset)/255.0, *(img.bitmapub_+offset)/255.0, 1.0, false);
200                 }
201                 static Color getpix_f_l_(const Image &img, int ix, int iy) {
202                         int x = ix, y = img.height_-iy-1;
203                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
204                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
205                         return Color(*(img.bitmapf_+offset), *(img.bitmapf_+offset), *(img.bitmapf_+offset), 1.0, false);
206                 }
207                 static Color getpix_ub_rgb_(const Image &img, int ix, int iy) {
208                         int x = ix, y = img.height_-iy-1;
209                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
210                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
211                         unsigned char *bitmapub_ = img.bitmapub_ + offset;
212                         return Color(*(bitmapub_)/255.0, *(bitmapub_+1)/255.0, *(bitmapub_+2)/255.0, 1.0, false);
213                 }
214                 static Color getpix_f_rgb_(const Image &img, int ix, int iy) {
215                         int x = ix, y = img.height_-iy-1;
216                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
217                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
218                         float *bitmapf_ = img.bitmapf_ + offset;
219                         return Color(*(bitmapf_), *(bitmapf_+1), *(bitmapf_+2), 1.0, false);
220                 }
221                 static Color getpix_ub_rgba_(const Image &img, int ix, int iy) {
222                         int x = ix, y = img.height_-iy-1;
223                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
224                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
225                         unsigned char *bitmapub_ = img.bitmapub_ + offset;
226                         return Color(*(bitmapub_)/255.0, *(bitmapub_+1)/255.0, *(bitmapub_+2)/255.0, *(bitmapub_+3)/255.0 , false);
227                 }
228                 static Color getpix_f_rgba_(const Image &img, int ix, int iy) {
229                         int x = ix, y = img.height_-iy-1;
230                         if(0>x || x>img.width_-1 || y<0 || y>img.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
231                         int offset = y*img.lineValue_ + x*img.PixCompSize_[img.pixcomp_];
232                         float *bitmapf_ = img.bitmapf_ + offset;
233                         return Color(*(bitmapf_), *(bitmapf_+1), *(bitmapf_+2), *(bitmapf_+3), false);
234                 }
235         };
236         void (*(ImageManipulator::pix_[2][3]))(const Image &, const int, const int, const Color&)    = { { &pix_ub_l_, &pix_ub_rgb_ , &pix_ub_rgba_ } , { &pix_f_l_, &pix_f_rgb_ , &pix_f_rgba_ }  };
237         void (*(ImageManipulator::pix_direct_[2][3]))(const Image &, const int, const int, const Color&)    = { { &pix_d_ub_l_, &pix_d_ub_rgb_ , &pix_d_ub_rgba_ } , { &pix_d_f_l_, &pix_d_f_rgb_ , &pix_d_f_rgba_ }  };
238         void (*(ImageManipulator::pix_alpha_[2][3]))(const Image &, const int, const int, const double)    = { { &alpha_null_, &alpha_null_ , &alpha_ub_rgba_ } , { &alpha_null_, &alpha_null_ , &alpha_f_rgba_ }  };
239         Color (*(ImageManipulator::getpix_[2][3]))(const Image &, int, int) = { { &getpix_ub_l_, &getpix_ub_rgb_ , &getpix_ub_rgba_ } , { &getpix_f_l_, &getpix_f_rgb_ , &getpix_f_rgba_ }  };
240
241 /*
242         Image& Image::pix(const int ix, const int iy, const Color &col) {
243                 pix_(*this, ix, iy, col);
244                 return *this;
245         }
246
247         Color Image::getPix(int ix, int iy) const {
248                 return getpix_(*this, ix, iy);
249         }
250 */
251
252         void Image::line_direct_copy_(const Image &src, Image &tgt, const int iy, const int jy) {
253                 int sy = src.height_-iy-1, ty = jy<0 ? tgt.height_-iy-1 : tgt.height_-jy-1;
254                 if(sy<0 || sy>src.height_-1) throw Exception(typeid(Image), "Out Of Bound Exception", "Specified coordinate is out of bound.");
255                 size_t bytes = ( src.lineBytes_>tgt.lineBytes_ ? tgt.lineBytes_ : src.lineBytes_ );
256                 switch(src.pixprec_) {
257                         case Image::BYTE:
258                                 memcpy((void *)(tgt.bitmapub_+ty*tgt.lineValue_), (void *)(src.bitmapub_+sy*src.lineValue_), bytes);
259                                 break;
260                         case Image::FLOAT:
261                                 memcpy((void *)(tgt.bitmapf_+ty*tgt.lineValue_), (void *)(src.bitmapf_+sy*src.lineValue_), bytes);
262                                 break;
263                         default:
264                                 throw Exception(typeid(Image), "Format Error", "Class Image recieved unknown format for pixels.");
265                                 break;
266                 }
267         }
268
269
270         void Image::set(long ix, long iy, PixelComponentsCnt pixcomp, PixelComponentsPrecision pixprec) {
271                 if(have_instance_) throw Exception(typeid(*this), "Memory Error", "Image object already has its bitmap.");
272
273                 //      init basic properties
274                 if(ix<=0) throw Exception(typeid(*this), "FORMAT ERROR", "The specified width is illegal");
275                         else width_ = ix;
276                 if(iy<=0) throw Exception(typeid(*this), "FORMAT ERROR", "The specified height is illegal");
277                         else height_ = iy;
278                 if(pixcomp<0) throw Exception(typeid(*this), "FORMAT ERROR", "The specified pixel component is illegal"); else
279                 if(pixcomp>=3) throw Exception(typeid(*this), "FORMAT ERROR", "The specified pixel component is illegal"); else
280                         pixcomp_ = pixcomp;
281                 if(pixprec<0) throw Exception(typeid(*this), "FORMAT ERROR", "The specified precision is illegal"); else
282                 if(pixprec>=2) throw Exception(typeid(*this), "FORMAT ERROR", "The specified precision is illegal"); else
283                         pixprec_ = pixprec;
284
285                 //      init calculable parameters
286                 targetarea_ = localarea_ = area_ = Rectangle(width_, height_);
287                 pixBytes_    = PixCompSize_[pixcomp_] * PixPrecSize_[pixprec_];
288                 lineBytes_   = pixBytes_ * width_;
289                 lineBytes_   = ( (lineBytes_%lineBytesAlingnment_==0 ? 0 : 1) + ((int)lineBytes_ / (int)lineBytesAlingnment_) ) * lineBytesAlingnment_;
290                 bitmapBytes_ = lineBytes_ * height_;
291                 lineValue_   = lineBytes_ / PixPrecSize_[pixprec_];
292                 bitmapValue_ = lineValue_ * height_;
293
294                 switch(pixprec_) {
295                         case BYTE:
296                                 if(NULL==(bitmapub_ = new GLubyte[bitmapValue_])) throw Exception(typeid(*this), "Memory Error", "Image failed to allocate memory.");
297                                 bitmapf_ = NULL;
298                                 break;
299                         case FLOAT:
300                                 if(NULL==(bitmapf_ = new GLfloat[bitmapValue_])) throw Exception(typeid(*this), "Memory Error", "Image failed to allocate memory.");
301                                 bitmapub_ = NULL;
302                                 break;
303                         default:
304                                 throw Exception(typeid(*this), "Format Error", "Class Image recieved unknown format for pixels.");
305                                 break;
306                 }
307                 api_ = new APIImageProperties(this);
308                 pix_ = ImageManipulator::pix_[pixprec_][pixcomp_];
309                 pix_direct_ = ImageManipulator::pix_direct_[pixprec_][pixcomp_];
310                 pix_alpha_ = ImageManipulator::pix_alpha_[pixprec_][pixcomp_];
311                 getpix_ = ImageManipulator::getpix_[pixprec_][pixcomp_];
312                 have_instance_ = true;
313                 if(!setWithoutClear_) clear(Color::black);
314         }
315
316         void Image::from(const Image &readimage) {
317                 release();
318                 *this = readimage;
319                 api_ = new APIImageProperties(this);
320                 caches.clear();
321                 void *target_bitmap, *source_bitmap;
322                 if(have_instance_) {
323                         switch(pixprec_) {
324                                 case BYTE:
325                                         if(NULL==(bitmapub_ = new GLubyte[bitmapValue_])) throw Exception(typeid(*this), "Memory Error", "Image failed to allocate memory.");
326                                         target_bitmap = (void *)(bitmapub_);
327                                         source_bitmap = (void *)(readimage.bitmapub_);
328                                         break;
329                                 case FLOAT:
330                                         if(NULL==(bitmapf_ = new GLfloat[bitmapValue_])) throw Exception(typeid(*this), "Memory Error", "Image failed to allocate memory.");
331                                         target_bitmap = (void *)(bitmapf_);
332                                         source_bitmap = (void *)(readimage.bitmapf_);
333                                         break;
334                                 default:
335                                         throw Exception(typeid(*this), "Format Error", "Class Image recieved unknown format for pixels.");
336                                         break;
337                         }
338                         memcpy(target_bitmap, source_bitmap, bitmapBytes_);
339                         have_instance_ = true;
340                 }
341         }
342
343
344
345 }       /*      <- namespace Psycholops         */
346