OSDN Git Service

first
[psychlops/cpp.git] / psychlops / platform / gl / psychlops_g_canvas_gl.cpp
1 /*
2  *  psychlops_g_canvas_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 #include <stdlib.h>
10 #include <Math.h>
11 #include <string>
12
13
14 #include "psychlops_g_GL_h.h"
15
16 #include "../../core/ApplicationInterfaces/psychlops_app_info.h"
17 #include "../../core/ApplicationInterfaces/psychlops_app_thread.h"
18 #include "../../core/devices/psychlops_io_hid.h"
19 #include "../../core/math/psychlops_math.h"
20 #include "../../core/graphic/psychlops_g_fundamental.h"
21 #include "../../core/graphic/psychlops_g_color.h"
22 #include "../../core/graphic/psychlops_g_module.h"
23 #include "../../core/graphic/psychlops_g_shape.h"
24 #include "../../core/graphic/psychlops_g_canvas.h"
25 #include "../../core/graphic/psychlops_g_image.h"
26
27 #define PSYCHLOPS_WINDOW_API_PLATFORM
28 #include "../../platform/psychlops_platform_selector.h"
29
30
31 namespace Psychlops {
32
33
34
35         GLuint font_LCD[128];
36         GLuint fillOvalPrimitives[4], drawOvalPrimitives[4];
37         int Canvas::font_LCD_height;
38
39
40         ////////        Construct and Destruct  ////////
41         class DirectGetColor {
42                 public:
43                 inline static unsigned char round8bit(double value) {
44                         double val = value*255.0+0.5, integer_part, frac;
45                         frac = modf(val, &integer_part);
46                         if(frac!=0.0) return (unsigned char)integer_part;
47                         if((int)(integer_part)%2==0) return (unsigned char)integer_part; else return (unsigned char)integer_part-1;
48                 }
49                 static void setColor4ub(const Color &color) {
50                         glColor4ub(round8bit(color.Red), round8bit(color.Green), round8bit(color.Blue), round8bit(color.Alpha));
51                 }
52                 static void setColorClear4ub(const Color &color) {
53                         glClearColor((GLclampf)round8bit(color.Red)/255.0, (GLclampf)round8bit(color.Green)/255.0, (GLclampf)round8bit(color.Blue)/255.0, (GLclampf)round8bit(color.Alpha)/255.0);
54                 }
55                 static void setColor4Through(const Color &color) {
56                         glColor4d(color.Red, color.Green, color.Blue, color.Alpha);
57                 }
58                 static void setColorClaer4Through(const Color &color) {
59                         glClearColor(color.Red, color.Green, color.Blue, color.Alpha);
60                 }
61         };
62
63         void Canvas::popMatrices() {
64                 glMatrixMode(GL_MODELVIEW);
65                 glPopMatrix();
66                 glMatrixMode(GL_PROJECTION);
67                 glPopMatrix();
68         }
69         void Canvas::pushPixToPixProjection() {
70                 glMatrixMode(GL_PROJECTION);
71                 glPushMatrix();
72                 glLoadIdentity();
73                 glOrtho(-0.375, Width-0.375, Height-0.375, -0.375, -1000, 1000);
74                 glMatrixMode(GL_MODELVIEW);
75                 glPushMatrix();
76                 glLoadIdentity();
77                 glDisable(GL_LIGHTING);
78                 glDisable(GL_DEPTH_TEST);
79         }
80         void Canvas::RenderModeSmooth2D() {
81                 glShadeModel(GL_SMOOTH);
82                 glEnable(GL_POINT_SMOOTH);
83                 glEnable(GL_LINE_SMOOTH);
84                 //        glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
85                 //        glEnable(GL_POLYGON_SMOOTH_HINT);
86                 //        glEnable(GL_POLYGON_SMOOTH);
87         }
88         void Canvas::RenderModeSmooth3D(double left, double right, double top, double bottom, double near, double far) {
89                 glMatrixMode(GL_PROJECTION);
90                 glPushMatrix();
91                 glLoadIdentity();
92                 //gluPerspective(left, top, near, far);
93                 //glFrustum(left, right, top, bottom, near, far);
94                 glRotated(180, 0, 1, 0);
95
96                 glMatrixMode(GL_MODELVIEW);
97                 glPushMatrix();
98                 glLoadIdentity();
99
100                 //glShadeModel(GL_SMOOTH);
101                 //glEnable(GL_POINT_SMOOTH);
102                 //glEnable(GL_LINE_SMOOTH);
103                 //        glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
104                 //        glEnable(GL_POLYGON_SMOOTH_HINT);
105                 //        glEnable(GL_POLYGON_SMOOTH);
106                 glEnable(GL_DEPTH_TEST);
107                 //        glEnable(GL_FOG);
108                 //        glEnable(GL_LIGHTING);
109                 glDisable(GL_LIGHTING);
110         }
111
112         void Canvas::initAPIprop() {
113                 switch(colordepth) {
114                 case 24:
115                 case 32:
116                         APIsetColor = &(DirectGetColor::setColor4ub);
117                         APIsetColorClear = &(DirectGetColor::setColorClear4ub);
118                         break;
119                 default:
120                         APIsetColor = &(DirectGetColor::setColor4Through);
121                         APIsetColorClear = &(DirectGetColor::setColorClaer4Through);
122                         break;
123                 }
124
125                 glDrawBuffer(GL_BACK);
126                 glReadBuffer(GL_BACK);
127                 //glMatrixMode(GL_PROJECTION);
128                 //glLoadIdentity();
129 //              glOrtho(0, Width, Height, 0, -1, 1);
130                 //glOrtho(-0.375, Width-0.375, Height-0.375, 0-0.375, -1, 1);
131                 //glMatrixMode(GL_MODELVIEW);
132                 //glLoadIdentity();
133 //              glTranslated(0.375, 0.375, 0.0);
134 //              glPushMatrix();
135
136         pushPixToPixProjection();
137                 initAPIattributes();
138
139                 GLclampf red=0.0, green=0.0, blue=0.0, alpha=1.0;
140 //              default_drawing_mode_ = GL_POINTS;
141                 glClearColor(red,green,blue,alpha);
142                 clear();
143                 flip(2);
144                 clear();
145                 flip(2);
146         }
147
148         void Canvas::initAPIattributes() {
149                 glPushAttrib(GL_ALL_ATTRIB_BITS);
150
151                 ////    default settings        ////
152                 glShadeModel(GL_FLAT);
153                 glEnable(GL_ALPHA_TEST);
154                 glEnable(GL_BLEND);
155                 glEnable(GL_LINE_STIPPLE);
156                 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
157                 glDisable(GL_POINT_SMOOTH);
158                 glDisable(GL_LINE_SMOOTH);
159                 glDisable(GL_POLYGON_SMOOTH);
160                 glDisable(GL_DEPTH_TEST);
161                 glDisable(GL_DITHER);
162                 glDisable(GL_FOG);
163                 glDisable(GL_LIGHTING);
164                 glDisable(GL_LOGIC_OP);
165                 glDisable(GL_STENCIL_TEST);
166                 glDisable(GL_TEXTURE_1D);
167                 glDisable(GL_TEXTURE_2D);
168                 glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
169                 glPixelTransferi(GL_MAP_STENCIL, GL_FALSE);
170                 glPixelTransferi(GL_RED_SCALE, 1);
171                 glPixelTransferi(GL_RED_BIAS, 0);
172                 glPixelTransferi(GL_GREEN_SCALE, 1);
173                 glPixelTransferi(GL_GREEN_BIAS, 0);
174                 glPixelTransferi(GL_BLUE_SCALE, 1);
175                 glPixelTransferi(GL_BLUE_BIAS, 0);
176                 glPixelTransferi(GL_ALPHA_SCALE, 1);
177                 glPixelTransferi(GL_ALPHA_BIAS, 0);
178                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
179                 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
180                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
181                 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
182                 glPixelStoref(GL_UNPACK_ALIGNMENT, 4);
183                 glPixelStorei(GL_PACK_ALIGNMENT, 4);
184                 glPixelStoref(GL_PACK_ALIGNMENT, 4);
185                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
186         }
187         void Canvas::popAPIattributes() {
188                 glPopAttrib();
189         }
190
191
192         ////    release
193
194         ////    Prepare Primitives
195
196
197
198
199
200         ////////        Drawing Graphical Elements   ////////
201         inline void Canvas::setStrokeState(const Stroke& strk) {
202                 APIsetColor(strk.color);
203                 glLineWidth(strk.width);
204                 glLineStipple((int)Math::round(strk.width), strk.pattern);
205         }
206
207
208         Drawable& Canvas::pix(double x, double y, const Color &col) {
209                 APIsetColor(col);
210                 glBegin(GL_POINTS);
211                         glVertex2d(x,y);
212                 glEnd();
213                 return *this;
214         }
215         Canvas& Canvas::pix(const Point &po, const Color &col) {
216                 pix(po.x, po.y, col);
217                 return *this;
218         }
219         void Canvas::pix(int dotsCnt, double x[], double y[], const Color col[]) {
220                 glBegin(GL_POINTS);
221                 for(int i=0; i<dotsCnt; i++) {
222                         APIsetColor(col[i]);
223                         glVertex2d(x[i], y[i]);
224                 }
225                 glEnd();
226         }
227         void Canvas::pix(int dotsCnt, double x[], double y[], const Color &col=Color::white) {
228                 APIsetColor(col);
229                 glBegin(GL_POINTS);
230                 for(int i=0; i<dotsCnt; i++) {
231                         glVertex2d(x[i], y[i]);
232                 }
233                 glEnd();
234         }
235         void Canvas::pix(int dotsCnt, const Point po[], const Color col[]) {
236                 glBegin(GL_POINTS);
237                 for(int i=0; i<dotsCnt; i++) {
238                         APIsetColor(col[i]);
239                         glVertex3d(po[i].x, po[i].y, po[i].z);
240                 }
241                 glEnd();
242         }
243         void Canvas::line(double x1, double y1, double x2, double y2, const Color &col) {
244                 APIsetColor(col);
245                 glBegin(GL_LINES);
246                         glVertex2d(x1, y1);
247                         glVertex2d(x2, y2);
248                 glEnd();
249         }
250         void Canvas::line(const Point &po1, const Point &po2, const Color &col) {
251                 line(po1.x, po1.y, po2.x, po2.y, col);
252         }
253         void Canvas::line(double x1, double y1, double x2, double y2, const Stroke &strk) {
254                 glPushAttrib(GL_ALL_ATTRIB_BITS);
255                 setStrokeState(strk);
256                 glBegin(GL_LINES);
257                         glVertex2d(x1, y1);
258                         glVertex2d(x2, y2);
259                 glEnd();
260                 glPopAttrib();
261         }
262         void Canvas::line(const Point &po1, const Point &po2, const Stroke &strk) {
263                 line(po1.x, po1.y, po2.x, po2.y, strk);
264         }
265         Canvas& Canvas::line(const Line &drawee, const Color &col) {
266                 line(drawee.datum.x, drawee.datum.y, drawee.end.x, drawee.end.y, col);
267                 return *this;
268         }
269         Canvas& Canvas::line(const Line &drawee, const Stroke &strk) {
270                 line(drawee.datum.x, drawee.datum.y, drawee.end.x, drawee.end.y, strk);
271                 return *this;
272         }
273         Canvas& Canvas::rect(const Rectangle &rec, const Color &col) {
274                 if(APIsetColor!=0) APIsetColor(col);
275 //              DirectGetColor::setColor4ub(col);
276                 glRectd(rec.left, rec.top, rec.right+1, rec.bottom+1);
277                 return *this;
278         }
279         Canvas& Canvas::rect(const int nRects, const Rectangle *rec, const Color &col) {
280                 APIsetColor(col);
281                 for(unsigned int i=0; i<nRects; i++) {
282                         glRectd(rec[i].left, rec[i].top, rec[i].right+1, rec[i].bottom+1);
283                 }
284                 return *this;
285         }
286         Canvas& Canvas::rect(const int nRects, const Rectangle *rec, const Color *col) {
287                 for(unsigned int i=0; i<nRects; i++) rect(rec[i], col[i]);
288                 return *this;
289         }
290         Canvas& Canvas::rect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Color *col) {
291                 for(unsigned int i=nRectsBegin; i<nRectsEnd; i++) rect(rec[i], col[i]);
292                 return *this;
293         }
294         Canvas& Canvas::rect(const Rectangle &rec, const Stroke &strk) {
295                 glPushAttrib(GL_ALL_ATTRIB_BITS);
296                 setStrokeState(strk);
297                 glBegin(GL_LINE_LOOP);
298                 glVertex2d(rec.left, rec.top);
299                 glVertex2d(rec.right, rec.top);
300                 glVertex2d(rec.right, rec.bottom);
301                 glVertex2d(rec.left, rec.bottom);
302                 glEnd();
303                 glPopAttrib();
304                 return *this;
305         }
306         Canvas& Canvas::rect(const int nRects, const Rectangle *rec, const Stroke &strk) {
307                 glPushAttrib(GL_ALL_ATTRIB_BITS);
308                 setStrokeState(strk);
309                 for(int i=0; i<nRects; i++) {
310                         glBegin(GL_LINE_LOOP);
311                         glVertex2d(rec[i].left, rec[i].top);
312                         glVertex2d(rec[i].right, rec[i].top);
313                         glVertex2d(rec[i].right, rec[i].bottom);
314                         glVertex2d(rec[i].left, rec[i].bottom);
315                         glEnd();
316                 }
317                 glPopAttrib();
318                 return *this;
319         }
320         Canvas& Canvas::rect(const int nRects, const Rectangle *rec, const Stroke *strk) {
321                 for(int i=0; i<nRects; i++) rect(rec[i], strk[i]);
322                 return *this;
323         }
324         Canvas& Canvas::rect(const unsigned int nRectsBegin, const unsigned int nRectsEnd, const Rectangle *rec, const Stroke *strk) {
325                 for(unsigned int i=nRectsBegin; i<nRectsEnd; i++) rect(rec[i], strk[i]);
326                 return *this;
327         }
328         Canvas& Canvas::ellipse(const Ellipse &ell) {\r
329                 ellipse(ell, ell.fill);\r
330                 ellipse(ell, ell.stroke);\r
331                 return *this;
332         }
333         Canvas& Canvas::ellipse(const Ellipse &ovl, const Color &col) {\r
334                 const double wi = ovl.radius;
335                 glPushMatrix();
336                 glPushAttrib(GL_ALL_ATTRIB_BITS);
337                         APIsetColor(col);
338                         glTranslatef(ovl.datum.x-ovl.radius/2, ovl.datum.y-ovl.v_radius/2, 0);
339                         glScalef(wi, ovl.v_radius+1, 1.0);
340                         if(wi<8) {
341                                 glCallList(fillOvalPrimitives[0]);
342                         } else if(wi<64) {
343                                 glCallList(fillOvalPrimitives[1]);
344                         } else if(wi<512) {
345                                 glCallList(fillOvalPrimitives[2]);
346                         } else {
347                                 glCallList(fillOvalPrimitives[3]);
348                         }
349                 glPopAttrib();
350                 glPopMatrix();
351                 return *this;
352         }
353         Canvas& Canvas::ellipse(const Ellipse &ovl, const Stroke &strk) {
354                 const double wi = ovl.radius;
355                 glPushMatrix();
356                 glPushAttrib(GL_ALL_ATTRIB_BITS);
357                         setStrokeState(strk);
358                         glTranslatef(ovl.datum.x-ovl.radius/2, ovl.datum.y-ovl.v_radius/2, 0);
359                         glScalef(wi, ovl.v_radius+1, 1.0);
360                         if(wi<8) {
361                                 glCallList(drawOvalPrimitives[0]);
362                         } else if(wi<64) {
363                                 glCallList(drawOvalPrimitives[1]);
364                         } else if(wi<512) {
365                                 glCallList(drawOvalPrimitives[2]);
366                         } else {
367                                 glCallList(drawOvalPrimitives[3]);
368                         }
369                 glPopAttrib();
370                 glPopMatrix();
371                 return *this;
372         }
373         Canvas& Canvas::ellipse(const Rectangle &rect, const Color &col) {
374                 const double wi = rect.getWidth();
375                 glPushMatrix();
376                 glPushAttrib(GL_ALL_ATTRIB_BITS);
377                         APIsetColor(col);
378                         glTranslatef(rect.left, rect.top, 0);
379                         glScalef(wi, rect.getHeight()+1, 1.0);
380                         if(wi<8) {
381                                 glCallList(fillOvalPrimitives[0]);
382                         } else if(wi<64) {
383                                 glCallList(fillOvalPrimitives[1]);
384                         } else if(wi<512) {
385                                 glCallList(fillOvalPrimitives[2]);
386                         } else {
387                                 glCallList(fillOvalPrimitives[3]);
388                         }
389                 glPopAttrib();
390                 glPopMatrix();
391                 return *this;
392         }
393         Canvas& Canvas::ellipse(const Rectangle &rect, const Stroke &strk) {
394                 const double wi = rect.getWidth();
395                 glPushMatrix();
396                 glPushAttrib(GL_ALL_ATTRIB_BITS);
397                         setStrokeState(strk);
398                         glTranslatef(rect.left, rect.top, 0);
399                         glScalef(wi, rect.getHeight()+1, 1.0);
400                         if(wi<8) {
401                                 glCallList(drawOvalPrimitives[0]);
402                         } else if(wi<64) {
403                                 glCallList(drawOvalPrimitives[1]);
404                         } else if(wi<512) {
405                                 glCallList(drawOvalPrimitives[2]);
406                         } else {
407                                 glCallList(drawOvalPrimitives[3]);
408                         }
409                 glPopAttrib();
410                 glPopMatrix();
411                 return *this;
412         }
413         void Canvas::polygon(Point *vertices, unsigned int nVertices, const Color &col) {
414                 APIsetColor(col);
415                 glBegin(GL_POLYGON);
416                         for(unsigned int i=0; i<nVertices; i++) {
417                                 glVertex2d(vertices[i].x, vertices[i].y);
418                         }
419                 glEnd();
420         }
421         void Canvas::polygon(Point *vertices, unsigned int nVertices, const Stroke &strk) {
422                 glPushAttrib(GL_ALL_ATTRIB_BITS);
423                 setStrokeState(strk);
424                 glBegin(GL_LINE_LOOP);
425                         for(unsigned int i=0; i<nVertices; i++) {
426                                 glVertex2d(vertices[i].x, vertices[i].y);
427                         }
428                 glEnd();
429                 glPopAttrib();
430         }
431         Canvas& Canvas::polygon(const Polygon &drawee) {
432                 if(drawee.vertices.empty()) return *this;
433                 glPushMatrix();
434                 const Point datum = drawee.getDatum();
435                 glTranslatef(datum.x, datum.y, datum.z);
436                 glBegin(GL_POLYGON);
437                 for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
438                         glVertex3d((*v).x, (*v).y, (*v).z);
439                 }
440                 glEnd();
441                 glPopMatrix();
442                 return *this;
443         }
444         Canvas& Canvas::polygon(const Polygon &drawee, const Color &col) {
445                 if(drawee.vertices.empty()) return *this;
446                 APIsetColor(col);
447                 glPushMatrix();
448                 const Point datum = drawee.getDatum();
449                 glTranslatef(datum.x, datum.y, datum.z);
450                 glBegin(GL_POLYGON);
451                 for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
452                         glVertex3d((*v).x, (*v).y, (*v).z);
453                 }
454                 glEnd();
455                 glPopMatrix();
456                 return *this;
457         }
458         Canvas& Canvas::polygon(const Polygon &drawee, const Stroke &strk) {
459                 if(drawee.vertices.empty()) return *this;
460                 glPushAttrib(GL_ALL_ATTRIB_BITS);
461                 setStrokeState(strk);
462                 glPushMatrix();
463                 const Point datum = drawee.getDatum();
464                 glTranslatef(datum.x, datum.y, datum.z);
465                 glBegin(GL_LINE_LOOP);
466                 for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
467                         glVertex3d((*v).x, (*v).y, (*v).z);
468                 }
469                 glEnd();
470                 glPopMatrix();
471                 glPopAttrib();
472                 return *this;
473         }
474         Canvas& Canvas::polyline(const PolyLine &drawee) {
475                 polyline(drawee, drawee.stroke);
476                 return *this;
477         }
478         Canvas& Canvas::polyline(const PolyLine &drawee, const Color &col) {
479                 Stroke strk(col, 1, Stroke::SOLID);
480                 polyline(drawee, strk);
481                 return *this;
482         }
483         Canvas& Canvas::polyline(const PolyLine &drawee, const Stroke &strk) {
484                 if(drawee.vertices.empty()) return *this;
485                 glPushAttrib(GL_ALL_ATTRIB_BITS);
486                 setStrokeState(strk);
487                 glPushMatrix();
488                 const Point datum = drawee.getDatum();
489                 glTranslatef(datum.x, datum.y, datum.z);
490                 glBegin(GL_LINE_STRIP);
491                 for(std::deque<Point>::const_iterator v=drawee.vertices.begin(); v!=drawee.vertices.end(); v++) {
492                         glVertex3d((*v).x, (*v).y, (*v).z);
493                 }
494                 glEnd();
495                 glPopMatrix();
496                 glPopAttrib();
497                 return *this;
498         }
499
500         Canvas& Canvas::figures(const Group &drawee) {
501                 const Color zero_alpha(1,1,1,0,false);
502                 const Point datum = drawee.getDatum();
503                 bool clipper_cached ;
504                 glPushAttrib(GL_ALL_ATTRIB_BITS);
505                 if(drawee.clip_type==Group::ALPHA) {
506                         clipper_cached = drawee.alpha_mask->caches.count(this);
507                         if(!clipper_cached) drawee.alpha_mask->cache(*this);
508                         glEnable(GL_BLEND);
509                         // nulling alpha value in buffer
510                         glBlendFunc(GL_ZERO, GL_SRC_COLOR);
511                         Rectangle fullcanvas(getWidth(), getHeight());
512                         fullcanvas.draw(zero_alpha);
513                 }
514                 glPushMatrix();
515                 if(drawee.clip_type==Group::RECT) {
516                         glEnable(GL_SCISSOR_TEST);
517                         glScissor((int)(drawee.scissor_left+datum.x), (int)(drawee.scissor_top+datum.y),
518                                   (int)(drawee.scissor_width), (int)(drawee.scissor_height));
519                 }
520                 glTranslated(datum.x, datum.y, datum.z);
521                 if(drawee.scaling.x!=0.0 || drawee.scaling.y!=0.0 || drawee.scaling.z!=0.0) glScaled(drawee.scaling.x, drawee.scaling.y, drawee.scaling.z);
522                 if(drawee.rotation!=0.0) glRotated(drawee.rotation, drawee.axis.x, drawee.axis.y, drawee.axis.z);
523                 if(drawee.clip_type==Group::ALPHA) {
524                         // nulling alpha value in buffer
525                         //glBlendFunc(GL_ZERO, GL_SRC_COLOR);
526                         //drawee.alpha_mask->targetarea_.draw(zero_alpha);
527                         // write alpha value to buffer
528                         glBlendFunc(GL_ONE, GL_ONE);
529                         drawee.alpha_mask->draw();
530                         //
531                         glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
532                         if(!clipper_cached) drawee.alpha_mask->uncache(*this);
533                 }
534                 if(!drawee.contents.empty()) {
535                         for(int i=0; i<drawee.contents.size(); i++) {
536                                 drawee.contents[i]->draw(*this);
537                         }
538                 }
539                 if(drawee.clip_type==Group::RECT) {
540                         glDisable(GL_SCISSOR_TEST);
541                 }
542                 if(drawee.clip_type==Group::ALPHA) {
543                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
544                 }
545                 glPopMatrix();
546                 glPopAttrib();
547                 return *this;
548         }
549
550         Canvas& Canvas::image(const Image &img, const double alpha) {
551                 const Color zero_alpha(1,1,1,0,false), alpha_mask(0,0,0,alpha);
552                 Rectangle area = img.targetarea_;
553                 area.set(area.left-1, area.top-1, area.right+1, area.bottom+1);
554                 glPushAttrib(GL_ALL_ATTRIB_BITS);
555
556                 glEnable(GL_BLEND);
557                 // nulling alpha value in buffer
558                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
559                 rect(area, zero_alpha);
560                 // write alpha value to buffer
561                 glBlendFunc(GL_ONE, GL_ONE);
562                 rect(area, alpha_mask);
563                 glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
564
565                 image(img);
566
567                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
568                 glPopAttrib();
569                 //glPopMatrix(); can't found corresponding glPushMatrix
570                 return *this;
571         }
572
573
574         ////    Drawing Images
575
576
577         void Canvas::copy(const Rectangle &source, const Rectangle &target, bool doesdeletesource, const Color &delcol) {
578                 glReadBuffer(GL_BACK);
579                 glDrawBuffer(GL_BACK);
580                 glRasterPos2d(target.left, target.bottom);
581                 glCopyPixels((GLuint)source.left, (GLuint)(Height-source.bottom-1), (GLuint)source.getWidth(), (GLuint)source.getHeight(), GL_COLOR);
582                 if(doesdeletesource) {
583                         fillRect(source, delcol);
584                 }
585         }
586         void Canvas::to(Image &img, const Rectangle &srcrect) const {\r
587                 Rectangle src = srcrect, cvsr(getWidth(), getHeight());\r
588                 cvsr.clip(src);\r
589                 int sw=(GLuint)srcrect.getWidth(), sh=(GLuint)srcrect.getHeight();\r
590                 int tw=(GLuint)img.getWidth(), th=(GLuint)img.getHeight();\r
591                 if(!(img.hasInstance()) || (tw!=sw || th!=sh)) {\r
592                         img.release();
593                         img.set(src);\r
594                 }\r
595 //              glReadBuffer(GL_BACK);
596                 glReadPixels((GLuint)(src.getLeft()), (GLuint)(Height-src.getBottom()-1), (GLuint)src.getWidth(), (GLuint)src.getHeight(), APIImageProperties::PixCompGL_[img.pixcomp_], APIImageProperties::PixPrecGL_[img.pixprec_], const_cast<void *>(img.getBitmapPtr()) );
597         }
598
599 /*      void Canvas::to(Image &img, const Rectangle &srcrect, const Rectangle &tgtrect) const {
600                 if(!img.hasInstance()) img.set(srcrect);
601                 Rectangle src = srcrect, tgt = tgtrect, imgrect(img.getWidth(), img.getHeight());
602                 tgt.cripped(img);
603                 GLuint sw=(GLuint)srcrect.getWidth(), sh=(GLuint)srcrect.getHeight(), tw=(GLuint)tgt.getWidth(), th=(GLuint)tgt.getHeight(), iw=(GLuint)img.getWidth(), ih=(GLuint)img.getHeight();
604                 if(tw!=sw || th!=sh) {
605                         src.resize(tw<sw?tw:sw, th<sh?th:sh).centering(srcrect);
606                 }
607                 glReadBuffer(GL_BACK);
608                 glReadPixels((GLuint)(srcrect.left), (GLuint)(Height-srcrect.bottom), (GLuint)src.getWidth(), (GLuint)src.getHeight(), Image::PixCompGL_[img.pixcomp_], Image::PixPrecGL_[img.pixprec_], const_cast<void *>(img.getBitmapPtr()) );
609                 unsigned int lines, sl, sr, sb, tl, tr, tb;
610                 for(int l=0; l<lines; l++)
611
612         }*/
613
614
615         ////    Drawing String
616
617         void Canvas::var_(std::string str, double x, double y, const Color &col, bool fillForward) {
618                 glPushMatrix();
619                 glPushAttrib(GL_ALL_ATTRIB_BITS);
620                 APIsetColor(col);
621                 if(fillForward) {
622                         std::string::iterator itr=str.begin(), end=str.end();
623                         glTranslatef(x-12,y,0);
624                         do {
625                                 glTranslatef(12,0,0);
626                                 glCallList(font_LCD[(int)(*itr)]);
627                                 itr++;
628                         } while(itr<end);
629                 } else {
630                         std::string::reverse_iterator itr=str.rbegin(), end=str.rend();
631                         glTranslatef(x,y,0);
632                         do {
633                                 glTranslatef(-12,0,0);
634                                 glCallList(font_LCD[(int)(*itr)]);
635                                 itr++;
636                         } while(itr<end);
637                 }
638                 glPopAttrib();
639                 glPopMatrix();
640         }
641         int Canvas::msg(const char* str, const double x, const double y, const Color &col, const int horiz_align, const int vertical_align, const double max__width) {
642                 Rectangle mask;
643                 const Color zero_alpha(1,1,1,0,false), alpha_mask(1,1,1,col.getA(),false);
644 //              glPushMatrix();
645                 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT);
646                 glEnable(GL_BLEND);
647
648                 int i=0, line_begin_i=0, num_lines=0, cursol_xpos=0;
649                 double line_x, line_y=0, max_width=0;
650
651                 switch(horiz_align) {
652                 case Letters::TEXT_ALIGN_RIGHT:
653                         max_width = (max__width>0) ? (int)max__width : (int)(x);
654                         break;
655                 case Letters::TEXT_ALIGN_CENTER:
656                         if(max__width>0) max_width = (int)max__width;
657                         else max_width = (x>Width/2) ? (int)(Width-x)*2 : (int)(x)*2;
658                         break;
659                 case Letters::TEXT_ALIGN_LEFT:
660                 default:
661                         max_width = (max__width>0) ? (int)max__width : (int)(Width-x);
662                         break;
663                 }
664
665                 while(str[i]!=0) {
666                         //line count
667                         line_begin_i = i;
668                         cursol_xpos = 0;
669                         while(cursol_xpos<max_width && str[i]!=0 && str[i]!='\r' && str[i]!='\n') {
670                                 cursol_xpos += Font::font_minimum_proportion[str[i++]];
671                         }
672                         switch(horiz_align) {
673                         case Letters::TEXT_ALIGN_RIGHT:
674                                 line_x = x - cursol_xpos + 3;
675                                 break;
676                         case Letters::TEXT_ALIGN_CENTER:
677                                 line_x = x - cursol_xpos/2.0 + 3;
678                                 break;
679                         case Letters::TEXT_ALIGN_LEFT:
680                         default:
681                                 line_x = x + 3;
682                                 break;
683                         }
684
685                         // draw
686                         line_y = y + num_lines*8 - 8;
687                         mask.set(line_x-4, line_y, line_x+cursol_xpos, line_y+8);
688                         glBlendFunc(GL_ZERO, GL_SRC_COLOR);     // clear destination alpha
689                         rect(mask, zero_alpha);
690                         glBlendFunc(GL_ONE, GL_ONE); // draw font in alpha channel
691                         cursol_xpos = 0;
692                         for(int c=line_begin_i; c<i; c++) {
693                                 if(str[c]<128) {
694                                         drawImage(Font::font_minimum[str[c]], line_x+cursol_xpos, line_y);
695                                         cursol_xpos+=Font::font_minimum_proportion[str[c]];
696                                 }
697                         }
698
699                         if(col.getA()!=1) { // apply alpha factor
700                                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
701                                 rect(mask, alpha_mask);
702                         }
703                         glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA); // drawing in specified color by destination alpha
704                         rect(mask, col);
705                         if( str[i]=='\r') i++;
706                         if( str[i]=='\n') i++;
707                         num_lines++;
708                 }
709
710                 glPopAttrib();
711 //              glPopMatrix();
712                 return num_lines;
713         }
714
715
716         ////////        Critical Operations ////////
717         void Canvas::flip(const int frame_duration_by_vsyncs) {
718                 Clock time_thisFrame, elapsed;
719                 double wait_time;
720
721                 if(frame_duration_by_vsyncs<1) throw Exception(typeid(*this), "ARGUMENT ERROR", "frame duration must be more than zero.");
722
723                 if(!billboard.empty()) {
724                         for(int i=0; i<billboard.size(); i++) billboard[i]->draw(*this);
725                 }
726                 if(displayingFPS) displayFPS();
727                 if(Mouse::showLocalPointer()) Mouse::drawPointer(mouse(), *this);
728
729
730                 glFinish();
731
732                 if(rest_wating_vsyncs_>1) {
733
734                         time_thisFrame.update();
735                         elapsed = time_thisFrame - time_lastFrame_before_flip_;
736
737                         //      HYBRID ROUTINE
738 /*                      do {
739                                 api->waitRefresh();
740                                 time_thisFrame.update();
741                                 elapsed = time_thisFrame - time_lastFrame_before_flip_;
742                         } while(elapsed.at_msec()<frameIntervalAccurate*(rest_wating_vsyncs_-0.5));
743 */
744                         //      TIME BASED ROUTINE
745                         wait_time = frameIntervalAccurate*(rest_wating_vsyncs_);
746                         do {
747                                 if(not_time_critical_) Prototype::Thread::sleep(1000);
748                                 time_thisFrame.update();
749                                 elapsed = time_thisFrame - time_lastFrame_before_flip_;
750                         } while(elapsed.at_msec()<wait_time);
751
752                         //      VSYNC BASED ROUTINE
753 /*                      int rest_frames = rest_wating_vsyncs_ - (int)( elapsed.at_msec() / frameIntervalAccurate );
754                         //int rest_frames = (int)(((rest_wating_vsyncs_)*frameIntervalAccurate - elapsed.at_msec())/frameIntervalAccurate);
755                         if(rest_frames>0) {
756                                 glReadBuffer(GL_BACK);
757                                 glDrawBuffer(GL_AUX0);
758                                 glRasterPos2d(0, Height-0.625);
759                                 glCopyPixels(0, 0, Width, Height, GL_COLOR);
760                                 glReadBuffer(GL_FRONT);
761                                 glDrawBuffer(GL_BACK);
762                                 glRasterPos2d(0, Height-0.625);
763                                 glCopyPixels(0, 0, Width, Height, GL_COLOR);
764 //                              glDrawBuffer(GL_AUX0);
765                                 for(int i=0; i<rest_frames; i++) {
766                                  rect(Rectangle(Width, Height), Color(0.0,0.0,0.0,0.5)); glFinish(); api->flip(); }
767                                 glReadBuffer(GL_AUX0);
768                                 glDrawBuffer(GL_BACK);
769                                 glRasterPos2d(0, Height-0.625);
770                                 glCopyPixels(0, 0, Width, Height, GL_COLOR);
771                         }
772 */
773                 } else {
774                         wait_time = frameIntervalAccurate*0.1;
775                         do {
776                                 if(not_time_critical_) Prototype::Thread::sleep(1000);
777                                 time_thisFrame.update();
778                                 elapsed = time_thisFrame - time_lastFrame_before_flip_;
779                         } while(elapsed.at_msec()<wait_time);
780                 }
781
782
783                 time_lastFrame_before_flip_.update();
784
785                 api->flip();
786
787                 //int rest_wating_vsyncs_before = rest_wating_vsyncs_;
788                 rest_wating_vsyncs_ = frame_duration_by_vsyncs;
789
790                 time_thisFrame.update();
791                 elapsed = time_thisFrame - time_lastFrame;
792                 frameInterval = elapsed.at_msec();
793                 time_lastFrame = time_thisFrame;
794
795                 if(checkingFPS) {
796                         displayedFrames+=frame_duration_by_vsyncs;
797                         if(checkingFPS_last) {
798                                 lastFailedFrames_ = (long)floor( ((frameInterval-1.0-(frameIntervalAccurate*((double)rest_wating_vsyncs_-1)) ) / frameIntervalAccurate) );
799                                 failedFrames += lastFailedFrames_;
800                                 DISPLAYED_FRAMES = displayedFrames;
801                                 FAILED_FRAMES = failedFrames;
802                                 FAILED_FLIPS += ( lastFailedFrames_==0 ? 0 : 1);
803                                 TOTAL_REFRESH = failedFrames+displayedFrames;
804                                 LAST_FAILED_FRAMES = lastFailedFrames_;
805                         } else {
806                                 checkingFPS_last = true;
807                         }
808                 }
809         }
810
811         Canvas& Canvas::clear(const Color &col, TargetSurface target) {
812                 APIsetColorClear(col);
813                 switch(target) {
814                         case ALL:
815                                 glDrawBuffer(GL_FRONT || GL_BACK);
816                                 //rect(clear_area_, col);
817                                 glClear(GL_COLOR_BUFFER_BIT);
818                                 break;
819                         case FRONT:
820                                 glDrawBuffer(GL_FRONT);
821                                 //rect(clear_area_, col);
822                                 glClear(GL_COLOR_BUFFER_BIT);
823                                 break;
824                         case BACK:
825                                 glDrawBuffer(GL_BACK);
826                                 //rect(clear_area_, col);
827                                 glClear(GL_COLOR_BUFFER_BIT);
828                                 break;
829                 }
830                 glDrawBuffer(GL_BACK);
831                 return *this;
832         }
833
834
835         ////////        Utilities   ////////
836
837         void Canvas::progressbar(double percentage) {
838                 Rectangle filledrect;
839                 Color fillcolor = progressbarfillcolor;
840                 if( percentage>1.0 ) {
841                          fillcolor = progressbarerrorcolor;
842                          percentage=1.0;
843                 }
844                 glDrawBuffer(GL_FRONT);
845                         fillRect(progressbarrect, progressbaremptycolor);
846                         if(percentage>0.0) {
847                                 filledrect.set(progressbarrect.left, progressbarrect.top, progressbarrect.left+(long)(progressbarrect.getWidth()*percentage), progressbarrect.bottom);
848                                 fillRect(filledrect, progressbarfillcolor);
849                         }
850                         glFlush();
851                 glDrawBuffer(GL_BACK);
852         }
853
854
855
856         ////////        Properties   ////////
857
858         ////////        Element Preparation     ////////
859
860         void Canvas::setfontLCD() {
861                 /*
862                         LCD FONT ....
863                         LIST:   0123456789AbCdEF+-* /=<>.,%
864                 */
865                 int len = 8;
866
867                 // 0
868                 //1 2
869                 // 3
870                 //4 5
871                 // 6
872                 //int font_LCD_vertices[7*4] = { 2,2+len+len,2+len,2+len+len , 1,2+len,1,2+len+len , 2+len,2+len,2+len,2+len+len , 2,1+len,2+len,1+len , 1,1,1,1+len , 2+len,1,2+len,1+len , 2,0,2+len,0 };
873                 int font_LCD_vertices[7*4] = {
874                                         0,0,1,0,
875                         0,0,0,1,                1,0,1,1,
876                                         0,1,1,1,
877                         0,1,0,2,                1,1,1,2,
878                                         0,2,1,2
879                 };
880                 for(int i=0; i<7*4; i+=4) {
881                         if(font_LCD_vertices[i+0]==font_LCD_vertices[i+2]) {
882                                 font_LCD_vertices[i+0] = font_LCD_vertices[i+0]*len;
883                                 font_LCD_vertices[i+2] = font_LCD_vertices[i+2]*len;
884                         } else {
885                                 font_LCD_vertices[i+0] = font_LCD_vertices[i+0]*len+1;
886                                 font_LCD_vertices[i+2] = font_LCD_vertices[i+2]*len;
887                         }
888                         if(font_LCD_vertices[i+1]==font_LCD_vertices[i+3]) {
889                                 font_LCD_vertices[i+1] = font_LCD_vertices[i+1]*len;
890                                 font_LCD_vertices[i+3] = font_LCD_vertices[i+3]*len;
891                         } else {
892                                 font_LCD_vertices[i+1] = font_LCD_vertices[i+1]*len+1;
893                                 font_LCD_vertices[i+3] = font_LCD_vertices[i+3]*len;
894                         }
895                         font_LCD_vertices[i+1] -= len*2;
896                         font_LCD_vertices[i+3] -= len*2;
897                 }
898                 //int font_LCD_GEN[16] = { 119,36,93,109,46,107,123,39,127,47,63,122,83,124,91,27 };
899                 int font_LCD_GEN[128] = {
900                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
901                         0,// SPC
902                         119,// !
903                         0,// "
904                         0,// #
905                         0,// $
906                         0,// %
907                         0,// &
908                         0,// '
909                         0,// (
910                         0,// )
911                         0,// *
912                         0,// +
913                         0,// ,
914                         8,// -
915                         0,// .
916                         0,// /
917                         119,36,93,109,46,107,123,39,127,47,// 0123456789
918                         0,0,0,0,0,0,0,// :;<=>?@
919                         63,122,83,124,91,27,115,62,32,100,// AbCdEFGHiJ
920                         0,0,0,0,119,//KLMNO
921                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
922                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
923                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
924                 };
925
926                 font_LCD[0] = glGenLists(128);
927                 if(font_LCD[0]!=0) {
928                         for(int i=0; i<128; i++) {
929                                 font_LCD[i] = font_LCD[0]+i;
930                                 if(font_LCD_GEN[i] != 0) {
931                                         glNewList(font_LCD[i], GL_COMPILE);
932                                                 glBegin(GL_LINES);
933                                                         for(int j=0; j<7; j++) {
934                                                                 if( font_LCD_GEN[i] >> j & 1 != 0 ) {
935                                                                         glVertex2i(font_LCD_vertices[j*4 + 0], font_LCD_vertices[j*4 + 1]);
936                                                                         glVertex2i(font_LCD_vertices[j*4 + 2], font_LCD_vertices[j*4 + 3]);
937                                                                 }
938                                                         }
939                                                 glEnd();
940                                         glEndList();
941                                 } else {
942                                         glNewList(font_LCD[i], GL_COMPILE);
943                                                 glBegin(GL_POINTS);
944                                                         glVertex2i(font_LCD_vertices[6*4 + 2], font_LCD_vertices[6*4 + 3]);
945                                                 glEnd();
946                                         glEndList();
947                                 }
948                         }
949                 }
950                 font_LCD_height = len*2+3;
951         }
952
953         void Canvas::setFillOvalPrimitives() {
954                 //  set display-lists index
955                 fillOvalPrimitives[0] = glGenLists(4);
956                 for(int i=1; i<4; i++) { fillOvalPrimitives[i]=fillOvalPrimitives[0]+i; }
957                 drawOvalPrimitives[0] = glGenLists(4);
958                 for(int i=1; i<4; i++) { drawOvalPrimitives[i]=drawOvalPrimitives[0]+i; }
959
960                 //  implement
961                 double k=0.0;
962                 for(int i=0; i<4; i++) {
963                         glNewList(fillOvalPrimitives[i], GL_COMPILE);
964                         glBegin(GL_POLYGON);
965                                 for(int j=0; j<(k=pow(5.0, 2.0+i*0.2)); j++) {
966                                         glVertex2f(cos(2.0*(j/k)*PI)/2.0+0.5, sin(2.0*(j/k)*PI)/2.0+0.5);       }
967                                         glVertex2f(cos(2.0*(0)*PI)/2.0+0.5, sin(2.0*(0)*PI)/2.0+0.5);
968                         glEnd();
969                         glEndList();
970                 }
971                 for(int i=0; i<4; i++) {
972                         glNewList(drawOvalPrimitives[i], GL_COMPILE);
973                         glBegin(GL_LINE_LOOP);
974                                 for(int j=0; j<(k=pow(5.0, 2.0+i*0.2)); j++) {
975                                         glVertex2f(cos(2.0*(j/k)*PI)/2.0+0.5, sin(2.0*(j/k)*PI)/2.0+0.5);       }
976                                         glVertex2f(cos(2.0*(0)*PI)/2.0+0.5, sin(2.0*(0)*PI)/2.0+0.5);
977                         glEnd();
978                         glEndList();
979                 }
980         }
981
982
983
984 }       /*      <- namespace Psycholops         */
985