change async to 0 to fix TIVI-114
[profile/ivi/navit.git] / navit / navit / graphics / opengl / graphics_opengl.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2010 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #define USE_FLOAT 0
21 #define REQUIRES_POWER_OF_2 0
22
23 #include <glib.h>
24 #include <unistd.h>
25 #include <math.h>
26 #include <stdio.h>
27
28 #include <time.h>
29
30 #include "item.h"
31 #include "attr.h"
32 #include "config.h"
33 #include "point.h"
34 #include "graphics.h"
35 #include "color.h"
36 #include "plugin.h"
37 #include "event.h"
38 #include "debug.h"
39 #include "callback.h"
40 #include "keys.h"
41 #include "window.h"
42 #include "navit/font/freetype/font_freetype.h"
43 #include "graphics_opengl.h"
44
45 #if defined(WINDOWS) || defined(WIN32)
46 #define PIXEL_FORMAT GL_RGBA
47 #include <windows.h>
48 # define sleep(i) Sleep(i * 1000)
49 #else
50 #define PIXEL_FORMAT GL_BGRA
51 #endif
52
53 #if HAVE_FREEIMAGE
54 #include <FreeImage.h>
55 #endif
56
57 #ifdef USE_OPENGLES
58 #ifdef USE_OPENGLES2
59 #include <GLES2/gl2.h>
60 #include <EGL/egl.h>
61 #undef USE_FLOAT
62 #define USE_FLOAT 1
63 #else
64 #include <GLES/gl.h>
65 #include <GLES/egl.h>
66 #endif
67 #ifdef USE_GLUT_FOR_OPENGLES
68 #define APIENTRY
69 #define GLU_TESS_BEGIN                     100100
70 #define GLU_TESS_VERTEX                    100101
71 #define GLU_TESS_END                       100102
72 #define GLU_TESS_COMBINE                   100105
73 typedef struct GLUtesselator GLUtesselator;
74 typedef double GLdouble;
75 #endif
76 #else
77 #define glOrthof        glOrtho
78 #undef USE_FLOAT
79 #define USE_FLOAT 1
80 #ifdef __APPLE__
81 #include <GLUT/glut.h>
82 #else
83 #include <GL/glut.h>            /* glut.h includes gl.h and glu.h */
84 #endif
85 #endif
86
87 #if USE_FLOAT
88 #define glF(x)  x
89 #define glD(x)  x
90 #define GL_F    GL_FLOAT
91 typedef GLfloat GLf;
92 #else
93 #define glF(x)  ((GLfixed)((x)*(1<<16)))
94 #define glD(x)  glF(x)
95 #define GL_F    GL_FIXED
96 typedef GLfixed GLf;
97
98 #define glClearColor    glClearColorx
99 #define glTranslatef    glTranslatex
100 #define glRotatef       glRotatex
101 #define glMaterialfv    glMaterialxv
102 #define glMaterialf     glMaterialx
103 #define glOrthof        glOrthox
104 #define glScalef        glScalex
105 #define glColor4f       glColor4x
106 #endif
107
108 #define SCREEN_WIDTH 700
109 #define SCREEN_HEIGHT 700
110
111 //#define MIRRORED_VIEW 1
112
113 struct graphics_gc_priv {
114         struct graphics_priv *gr;
115         float fr, fg, fb, fa;
116         float br, bg, bb, ba;
117         int linewidth;
118         unsigned char *dash_list;
119         int dash_count;
120         int dash_mask;
121 } graphics_gc_priv;
122
123 struct graphics_priv {
124         int button_timeout;
125         struct point p;
126         int width;
127         int height;
128         int library_init;
129         int visible;
130         int overlay_enabled;
131         int overlay_autodisabled;
132         int wraparound;
133         struct graphics_priv *parent;
134         struct graphics_priv *overlays;
135         struct graphics_priv *next;
136         struct graphics_gc_priv *background_gc;
137         enum draw_mode_num mode;
138         void (*resize_callback) (void *data, int w, int h);
139         void *resize_callback_data;
140         void (*motion_callback) (void *data, struct point * p);
141         void *motion_callback_data;
142         void (*button_callback) (void *data, int press, int button,
143                                  struct point * p);
144         void *button_callback_data;
145 #ifdef USE_OPENGLES
146         GLuint program;
147         GLint mvp_location, position_location, color_location, texture_position_location, use_texture_location, texture_location;
148 #else
149         GLuint DLid;
150 #endif
151         struct callback_list *cbl;
152         struct font_freetype_methods freetype_methods;
153         struct navit *nav;
154         int timeout;
155         int delay;
156         struct window window;
157         int dirty;              //display needs to be redrawn (draw on root graphics or overlay is done)
158         int force_redraw;       //display needs to be redrawn (draw on root graphics or overlay is done)
159         time_t last_refresh_time;       //last display refresh time
160         struct graphics_opengl_window_system *window_system;
161         struct graphics_opengl_window_system_methods *window_system_methods;
162         struct graphics_opengl_platform *platform;
163         struct graphics_opengl_platform_methods *platform_methods;
164 };
165
166 static struct graphics_priv *graphics_priv_root;
167 struct graphics_image_priv {
168         int w;
169         int h;
170         int hot_x;
171         int hot_y;
172         unsigned char *data;
173         char *path;
174 } graphics_image_priv;
175
176 struct mouse_event_queue_element {
177         int button;
178         int state;
179         int x;
180         int y;
181 };
182
183 static const int mouse_event_queue_size = 100;
184 static int mouse_event_queue_begin_idx = 0;
185 static int mouse_event_queue_end_idx = 0;
186 static struct mouse_event_queue_element mouse_queue[100];
187
188 //hastable for uncompressed image data
189 static GHashTable *hImageData;
190
191 #ifdef USE_OPENGLES
192 #else
193 /*  prototypes */
194 void APIENTRY tessBeginCB(GLenum which);
195 void APIENTRY tessEndCB();
196 void APIENTRY tessErrorCB(GLenum errorCode);
197 void APIENTRY tessVertexCB(const GLvoid * data);
198 void APIENTRY tessVertexCB2(const GLvoid * data);
199 void APIENTRY tessCombineCB(GLdouble c[3], void *d[4], GLfloat w[4], void **out);
200 const char *getPrimitiveType(GLenum type);
201 #endif
202
203 static struct graphics_priv *graphics_opengl_new_helper(struct
204                                                         graphics_methods
205                                                         *meth);
206 static void display(void);
207 static void resize_callback(int w, int h);
208 static void click_notify_do(struct graphics_priv *priv, int button, int state, int x, int y);
209 static void motion_notify_do(struct graphics_priv *priv, int x, int y);
210 static void resize_callback_do(struct graphics_priv *priv, int w, int h);
211 static void glut_close();
212
213 #ifdef USE_OPENGLES2
214 const char vertex_src [] =
215 "                                        \
216    attribute vec2        position;       \
217    attribute vec2        texture_position;       \
218    uniform mat4        mvp;             \
219    varying vec2 v_texture_position; \
220                                          \
221    void main()                           \
222    {                                     \
223       v_texture_position=texture_position; \
224       gl_Position = mvp*vec4(position, 0.0, 1.0);   \
225    }                                     \
226 ";
227
228 const char fragment_src [] =
229 "                                                      \
230    uniform lowp vec4   avcolor;                        \
231    uniform sampler2D texture; \
232    uniform bool use_texture; \
233    varying vec2 v_texture_position; \
234    void  main()                                        \
235    {                                                   \
236       if (use_texture) { \
237          gl_FragColor = texture2D(texture, v_texture_position);     \
238       } else { \
239          gl_FragColor = avcolor; \
240       } \
241    }                                                   \
242 ";
243 #endif
244
245 static void
246 graphics_destroy(struct graphics_priv *gr)
247 {
248         /*FIXME graphics_destroy is never called */
249         /*TODO add destroy code for image cache(delete entries in hImageData) */
250         g_free(gr);
251         gr = NULL;
252 }
253
254 static void
255 gc_destroy(struct graphics_gc_priv *gc)
256 {
257         g_free(gc);
258         gc = NULL;
259 }
260
261 static void
262 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
263 {
264         gc->linewidth = w;
265 }
266
267 static void
268 gc_set_dashes(struct graphics_gc_priv *gc, int width, int offset,
269               unsigned char *dash_list, int n)
270 {
271         int i;
272         const int cOpenglMaskBits = 16;
273         gc->dash_count = n;
274         if (1 == n) {
275                 gc->dash_mask = 0;
276                 for (i = 0; i < cOpenglMaskBits; ++i) {
277                         gc->dash_mask <<= 1;
278                         gc->dash_mask |= (i / n) % 2;
279                 }
280         } else if (1 < n) {
281                 unsigned char *curr = dash_list;
282                 int cnt = 0;    //dot counter
283                 int dcnt = 0;   //dash element counter
284                 int sum_dash = 0;
285                 gc->dash_mask = 0;
286
287                 for (i = 0; i < n; ++i) {
288                         sum_dash += dash_list[i];
289                 }
290
291                 //scale dashlist elements to max size
292                 if (sum_dash > cOpenglMaskBits) {
293                         int num_error[2] = { 0, 0 };    //count elements rounded to 0 for odd(drawn) and even(masked) for compensation
294                         double factor = (1.0 * cOpenglMaskBits) / sum_dash;
295                         for (i = 0; i < n; ++i) {       //calculate dashlist max and largest common denomiator for scaling
296                                 dash_list[i] *= factor;
297                                 if (dash_list[i] == 0) {
298                                         ++dash_list[i];
299                                         ++num_error[i % 2];
300                                 } else if (0 < num_error[i % 2]
301                                            && 2 < dash_list[i]) {
302                                         ++dash_list[i];
303                                         --num_error[i % 2];
304                                 }
305                         }
306                 }
307                 //calculate mask
308                 for (i = 0; i < cOpenglMaskBits; ++i) {
309                         gc->dash_mask <<= 1;
310                         gc->dash_mask |= 1 - dcnt % 2;
311                         ++cnt;
312                         if (cnt == *curr) {
313                                 cnt = 0;
314                                 ++curr;
315                                 ++dcnt;
316                                 if (dcnt == n) {
317                                         curr = dash_list;
318                                 }
319                         }
320                 }
321         }
322 }
323
324
325 static void
326 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
327 {
328         gc->fr = c->r / 65535.0;
329         gc->fg = c->g / 65535.0;
330         gc->fb = c->b / 65535.0;
331         gc->fa = c->a / 65535.0;
332 }
333
334 static void
335 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
336 {
337         gc->br = c->r / 65535.0;
338         gc->bg = c->g / 65535.0;
339         gc->bb = c->b / 65535.0;
340         gc->ba = c->a / 65535.0;
341 }
342
343 static struct graphics_gc_methods gc_methods = {
344         gc_destroy,
345         gc_set_linewidth,
346         gc_set_dashes,
347         gc_set_foreground,
348         gc_set_background
349 };
350
351 static struct graphics_gc_priv *
352 gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
353 {
354         struct graphics_gc_priv *gc = g_new0(struct graphics_gc_priv, 1);
355
356         *meth = gc_methods;
357         gc->gr = gr;
358         gc->linewidth = 1;
359         return gc;
360 }
361
362 static struct graphics_image_priv image_error;
363
364 static struct graphics_image_priv *
365 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth,
366           char *path, int *w, int *h, struct point *hot, int rotation)
367 {
368 #if HAVE_FREEIMAGE
369         FIBITMAP *image;
370         RGBQUAD aPixel;
371         unsigned char *data;
372         int width, height, i, j;
373         struct graphics_image_priv *gi;
374         //check if image already exists in hashmap
375         struct graphics_image_priv *curr_elem =
376             g_hash_table_lookup(hImageData, path);
377         if (curr_elem == &image_error) {
378                 //found but couldn't be loaded
379                 return NULL;
380         } else if (curr_elem) {
381                 //found and OK -> use hastable entry
382                 *w = curr_elem->w;
383                 *h = curr_elem->h;
384                 hot->x = curr_elem->w / 2 - 1;
385                 hot->y = curr_elem->h / 2 - 1;
386                 return curr_elem;
387         } else {
388                 if (strlen(path) < 4) {
389                         g_hash_table_insert(hImageData, g_strdup(path),
390                                             &image_error);
391                         return NULL;
392                 }
393                 char *ext_str = path + strlen(path) - 3;
394                 if (strstr(ext_str, "png") || strstr(path, "PNG")) {
395                         if ((image =
396                              FreeImage_Load(FIF_PNG, path, 0)) == NULL) {
397                                 g_hash_table_insert(hImageData,
398                                                     g_strdup(path),
399                                                     &image_error);
400                                 return NULL;
401                         }
402                 } else if (strstr(ext_str, "xpm") || strstr(path, "XPM")) {
403                         if ((image =
404                              FreeImage_Load(FIF_XPM, path, 0)) == NULL) {
405                                 g_hash_table_insert(hImageData,
406                                                     g_strdup(path),
407                                                     &image_error);
408                                 return NULL;
409                         }
410                 } else if (strstr(ext_str, "svg") || strstr(path, "SVG")) {
411                         char path_new[256];
412                         snprintf(path_new, strlen(path) - 3, "%s", path);
413                         strcat(path_new, "_48_48.png");
414
415                         if ((image =
416                              FreeImage_Load(FIF_PNG, path_new,
417                                             0)) == NULL) {
418                                 g_hash_table_insert(hImageData,
419                                                     g_strdup(path),
420                                                     &image_error);
421                                 return NULL;
422                         }
423                 } else {
424                         g_hash_table_insert(hImageData, g_strdup(path),
425                                             &image_error);
426                         return NULL;
427                 }
428
429                 if (FreeImage_GetBPP(image) == 64) {
430                         FIBITMAP *image2;
431                         image2 = FreeImage_ConvertTo32Bits(image);
432                         FreeImage_Unload(image);
433                         image = image2;
434                 }
435 #if FREEIMAGE_MAJOR_VERSION*100+FREEIMAGE_MINOR_VERSION  >= 313
436                 if (rotation) {
437                         FIBITMAP *image2;
438                         image2 = FreeImage_Rotate(image, rotation, NULL);
439                         image = image2;
440                 }
441 #endif
442
443                 gi = g_new0(struct graphics_image_priv, 1);
444
445                 width = FreeImage_GetWidth(image);
446                 height = FreeImage_GetHeight(image);
447
448                 if ((*w != width || *h != height) && 0 < *w && 0 < *h) {
449                         FIBITMAP *image2;
450                         image2 = FreeImage_Rescale(image, *w, *h, NULL);
451                         FreeImage_Unload(image);
452                         image = image2;
453                         width = *w;
454                         height = *h;
455                 }
456
457                 data = (unsigned char *) malloc(width * height * 4);
458
459                 RGBQUAD *palette = NULL;
460                 if (FreeImage_GetBPP(image) == 8) {
461                         palette = FreeImage_GetPalette(image);
462                 }
463
464                 for (i = 0; i < height; i++) {
465                         for (j = 0; j < width; j++) {
466                                 unsigned char idx;
467                                 if (FreeImage_GetBPP(image) == 8) {
468                                         FreeImage_GetPixelIndex(image, j,
469                                                                 height -
470                                                                 i - 1,
471                                                                 &idx);
472                                         data[4 * width * i + 4 * j + 0] =
473                                             palette[idx].rgbRed;
474                                         data[4 * width * i + 4 * j + 1] =
475                                             palette[idx].rgbGreen;
476                                         data[4 * width * i + 4 * j + 2] =
477                                             palette[idx].rgbBlue;
478                                         data[4 * width * i + 4 * j + 3] =
479                                             255;
480                                 } else if (FreeImage_GetBPP(image) == 16
481                                            || FreeImage_GetBPP(image) == 24
482                                            || FreeImage_GetBPP(image) ==
483                                            32) {
484                                         FreeImage_GetPixelColor(image, j,
485                                                                 height -
486                                                                 i - 1,
487                                                                 &aPixel);
488                                         int transparent =
489                                             (aPixel.rgbRed == 0
490                                              && aPixel.rgbBlue == 0
491                                              && aPixel.rgbGreen == 0);
492                                         data[4 * width * i + 4 * j + 0] =
493                                             transparent ? 0 : (aPixel.
494                                                                rgbRed);
495                                         data[4 * width * i + 4 * j + 1] =
496                                             (aPixel.rgbGreen);
497                                         data[4 * width * i + 4 * j + 2] =
498                                             transparent ? 0 : (aPixel.
499                                                                rgbBlue);
500                                         data[4 * width * i + 4 * j + 3] =
501                                             transparent ? 0 : 255;
502
503                                 }
504                         }
505                 }
506
507                 FreeImage_Unload(image);
508
509                 *w = width;
510                 *h = height;
511                 gi->w = width;
512                 gi->h = height;
513                 gi->hot_x = width / 2 - 1;
514                 gi->hot_y = height / 2 - 1;
515                 hot->x = width / 2 - 1;
516                 hot->y = height / 2 - 1;
517                 gi->data = data;
518                 gi->path = path;
519                 //add to hashtable
520                 g_hash_table_insert(hImageData, g_strdup(path), gi);
521                 return gi;
522         }
523 #else
524         dbg(0,"FreeImage not available - cannot load any images.\n", path);
525         return NULL;
526 #endif
527 }
528
529
530 static void
531 set_color(struct graphics_priv *gr, struct graphics_gc_priv *gc)
532 {
533 #ifdef USE_OPENGLES2
534         GLfloat col[4];
535         col[0]=gc->fr;
536         col[1]=gc->fg;
537         col[2]=gc->fb;
538         col[3]=1.0;
539         glUniform4fv(gr->color_location, 1, col);
540 #else
541         glColor4f(glF(gc->fr), glF(gc->fg), glF(gc->fb), glF(gc->fa));
542 #endif
543 }
544
545 static void
546 draw_array(struct graphics_priv *gr, struct point *p, int count, GLenum mode)
547 {
548         int i;
549 #ifdef USE_OPENGLES
550         GLf x[count*2];
551 #else
552         glBegin(mode);
553 #endif
554
555         for (i = 0 ; i < count ; i++) {
556 #ifdef USE_OPENGLES
557                 x[i*2]=glF(p[i].x);
558                 x[i*2+1]=glF(p[i].y);
559 #else
560                 glVertex2f(p[i].x, p[i].y);
561 #endif
562         }
563 #ifdef USE_OPENGLES
564 #ifdef USE_OPENGLES2
565         glVertexAttribPointer (gr->position_location, 2, GL_FLOAT, 0, 0, x );
566 #else
567         glVertexPointer(2, GL_F, 0, x);
568 #endif
569         glDrawArrays(mode, 0, count);
570 #else
571         glEnd();
572 #endif
573 }
574
575 static void
576 draw_rectangle_do(struct graphics_priv *gr, struct point *p, int w, int h)
577 {
578         struct point pa[4];
579         pa[0]=pa[1]=pa[2]=pa[3]=*p;
580         pa[0].x+=w;
581         pa[1].x+=w;
582         pa[1].y+=h;
583         pa[3].y+=h;
584         draw_array(gr, pa, 4, GL_TRIANGLE_STRIP);
585 }
586
587 #ifdef USE_OPENGLES
588
589 static int next_power2(int x)
590 {
591         int r=1;
592         while (r < x) 
593                 r*=2;
594         return r;
595 }
596
597 static void
598 draw_image_es(struct graphics_priv *gr, struct point *p, int w, int h, unsigned char *data)
599 {
600         GLf x[8];
601
602         memset(x, 0, sizeof(x));
603 #if REQUIRES_POWER_OF_2
604         int w2=next_power2(w);
605         int h2=next_power2(h);
606         int y;
607         if (w2 != w || h2 != h) {
608                 char *newpix=g_malloc0(w2*h2*4);
609                 for (y=0 ; y < h ; y++) 
610                         memcpy(newpix+y*w2*4, data+y*w*4, w*4);
611                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w2, h2, 0, GL_RGBA, GL_UNSIGNED_BYTE, newpix);
612                 g_free(newpix);
613                 w=w2;
614                 h=h2;
615         } else 
616                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
617 #else
618         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
619 #endif
620         x[0]+=glF(1);
621         x[2]+=glF(1);
622         x[3]+=glF(1);
623         x[7]+=glF(1);
624 #ifdef USE_OPENGLES2
625         glUniform1i(gr->use_texture_location, 1);
626         glEnableVertexAttribArray(gr->texture_position_location);
627         glVertexAttribPointer (gr->texture_position_location, 2, GL_FLOAT, 0, 0, x );
628 #else
629         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
630         glEnable(GL_TEXTURE_2D);
631         glTexCoordPointer(2, GL_F, 0, x);
632 #endif
633         glEnable(GL_BLEND);
634         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
635         draw_rectangle_do(gr, p, w, h);
636 #ifdef USE_OPENGLES2
637         glUniform1i(gr->use_texture_location, 0);
638         glDisableVertexAttribArray(gr->texture_position_location);
639 #else
640         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
641         glDisable(GL_TEXTURE_2D);
642 #endif
643         glDisable(GL_BLEND);
644 }
645
646
647 #endif
648
649 static void
650 get_overlay_pos(struct graphics_priv *gr, struct point *point_out)
651 {
652         if (gr->parent == NULL) {
653                 point_out->x = 0;
654                 point_out->y = 0;
655                 return;
656         }
657         point_out->x = gr->p.x;
658         if (point_out->x < 0) {
659                 point_out->x += gr->parent->width;
660         }
661
662         point_out->y = gr->p.y;
663         if (point_out->y < 0) {
664                 point_out->y += gr->parent->height;
665         }
666 }
667
668 static void
669 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc,
670            struct point *p, int count)
671 {
672         if ((gr->parent && !gr->parent->overlay_enabled)
673             || (gr->parent && gr->parent->overlay_enabled
674                 && !gr->overlay_enabled)) {
675                 return;
676         }
677 #if !defined(USE_OPENGLES) || defined(USE_OPENGLES2)
678         glLineWidth(gc->linewidth);
679 #endif
680         set_color(gr, gc);
681         graphics_priv_root->dirty = 1;
682
683 #ifndef USE_OPENGLES
684         if (!gr->parent && 0 < gc->dash_count) {
685                 glLineStipple(1, gc->dash_mask);
686                 glEnable(GL_LINE_STIPPLE);
687         }
688 #endif
689         draw_array(gr, p, count, GL_LINE_STRIP);
690 #ifndef USE_OPENGLES
691         if (!gr->parent && 0 < gc->dash_count) {
692                 glDisable(GL_LINE_STIPPLE);
693         }
694 #endif
695 }
696
697 #if !defined(USE_OPENGLES) || defined(USE_GLUT_FOR_OPENGLES)
698 static int tess_count;
699 static struct point tess_array[512];
700 static GLenum tess_type;
701
702 const char *
703 getPrimitiveType(GLenum type)
704 {
705         char *ret = "";
706
707         switch (type) {
708         case 0x0000:
709                 ret = "GL_POINTS";
710                 break;
711         case 0x0001:
712                 ret = "GL_LINES";
713                 break;
714         case 0x0002:
715                 ret = "GL_LINE_LOOP";
716                 break;
717         case 0x0003:
718                 ret = "GL_LINE_STRIP";
719                 break;
720         case 0x0004:
721                 ret = "GL_TRIANGLES";
722                 break;
723         case 0x0005:
724                 ret = "GL_TRIANGLE_STRIP";
725                 break;
726         case 0x0006:
727                 ret = "GL_TRIANGLE_FAN";
728                 break;
729         case 0x0007:
730                 ret = "GL_QUADS";
731                 break;
732         case 0x0008:
733                 ret = "GL_QUAD_STRIP";
734                 break;
735         case 0x0009:
736                 ret = "GL_POLYGON";
737                 break;
738         }
739         return ret;
740 }
741
742 void APIENTRY
743 tessBeginCB(GLenum which)
744 {
745         dbg(1, "glBegin( %s );\n", getPrimitiveType(which));
746         tess_type=which;
747         tess_count=0;
748 }
749
750
751
752 void APIENTRY
753 tessEndCB()
754 {
755         dbg(1, "glEnd();\n");
756         draw_array(graphics_priv_root, tess_array, tess_count, tess_type);
757 }
758
759
760
761 void APIENTRY
762 tessVertexCB(const GLvoid * data)
763 {
764         // cast back to double type
765         const GLdouble *ptr = (const GLdouble *) data;
766         dbg(1, "  glVertex3d();\n");
767
768         tess_array[tess_count].x=ptr[0];
769         tess_array[tess_count].y=ptr[1];
770         if (tess_count < 511)
771                 tess_count++;
772         else
773                 dbg(0,"overflow\n");
774 }
775
776 void APIENTRY
777 tessCombineCB(GLdouble c[3], void *d[4], GLfloat w[4], void **out)
778 {
779         GLdouble *nv = (GLdouble *) malloc(sizeof(GLdouble) * 3);
780         nv[0] = c[0];
781         nv[1] = c[1];
782         nv[2] = c[2];
783         *out = nv;
784 }
785
786 #endif
787
788
789 static void
790 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
791              struct point *p, int count)
792 {
793         if ((gr->parent && !gr->parent->overlay_enabled)
794             || (gr->parent && gr->parent->overlay_enabled
795                 && !gr->overlay_enabled)) {
796                 return;
797         }
798         set_color(gr, gc);
799         graphics_priv_root->dirty = 1;
800 #if defined(USE_OPENGLES) && !defined(USE_GLUT_FOR_OPENGLES)
801         draw_array(gr, p, count, GL_LINE_STRIP);
802 #else
803
804         GLUtesselator *tess = gluNewTess();     // create a tessellator
805         if (!tess)
806                 return;         // failed to create tessellation object, return 0
807
808         GLdouble quad1[count][3];
809         int i;
810         for (i = 0; i < count; i++) {
811                 quad1[i][0] = (GLdouble) (p[i].x);
812                 quad1[i][1] = (GLdouble) (p[i].y);
813                 quad1[i][2] = 0;
814         }
815
816
817         // register callback functions
818         gluTessCallback(tess, GLU_TESS_BEGIN,   (void (APIENTRY *)(void)) tessBeginCB);
819         gluTessCallback(tess, GLU_TESS_END,             (void (APIENTRY *)(void)) tessEndCB);
820         //     gluTessCallback(tess, GLU_TESS_ERROR, (void (*)(void))tessErrorCB);
821         gluTessCallback(tess, GLU_TESS_VERTEX,  (void (APIENTRY *)(void)) tessVertexCB);
822         gluTessCallback(tess, GLU_TESS_COMBINE, (void (APIENTRY *)(void)) tessCombineCB);
823
824         // tessellate and compile a concave quad into display list
825         // gluTessVertex() takes 3 params: tess object, pointer to vertex coords,
826         // and pointer to vertex data to be passed to vertex callback.
827         // The second param is used only to perform tessellation, and the third
828         // param is the actual vertex data to draw. It is usually same as the second
829         // param, but It can be more than vertex coord, for example, color, normal
830         // and UV coords which are needed for actual drawing.
831         // Here, we are looking at only vertex coods, so the 2nd and 3rd params are
832         // pointing same address.
833         gluTessBeginPolygon(tess, 0);   // with NULL data
834         gluTessBeginContour(tess);
835         for (i = 0; i < count; i++) {
836                 gluTessVertex(tess, quad1[i], quad1[i]);
837         }
838         gluTessEndContour(tess);
839         gluTessEndPolygon(tess);
840
841         gluDeleteTess(tess);    // delete after tessellation
842 #endif
843 }
844
845 static void
846 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc,
847                struct point *p, int w, int h)
848 {
849         if ((gr->parent && !gr->parent->overlay_enabled)
850             || (gr->parent && gr->parent->overlay_enabled
851                 && !gr->overlay_enabled)) {
852                 return;
853         }
854         set_color(gr, gc);
855         draw_rectangle_do(gr, p, w, h);
856         graphics_priv_root->dirty = 1;
857 }
858
859 static void
860 display_text_draw(struct font_freetype_text *text,
861                   struct graphics_priv *gr, struct graphics_gc_priv *fg,
862                   struct graphics_gc_priv *bg, int color, struct point *p)
863 {
864         int i, x, y, stride;
865         struct font_freetype_glyph *g, **gp;
866         unsigned char *shadow, *glyph;
867         struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
868         struct color black =
869             { fg->fr * 65535, fg->fg * 65535, fg->fb * 65535,
870    fg->fa * 65535 };
871         struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
872
873         if (bg) {
874                 if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
875                         black.r = 65535;
876                         black.g = 65535;
877                         black.b = 65535;
878                         black.a = 65535;
879
880                         white.r = 0;
881                         white.g = 0;
882                         white.b = 0;
883                         white.a = 65535;
884                 } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
885                         white.r = 65535;
886                         white.g = 65535;
887                         white.b = 65535;
888                         white.a = 65535;
889
890                         black.r = 0;
891                         black.g = 0;
892                         black.b = 0;
893                         black.a = 65535;
894                 } else {
895                         white.r = bg->fr;
896                         white.g = bg->fg;
897                         white.b = bg->fb;
898                         white.a = bg->fa;
899                 }
900         } else {
901                 white.r = 0;
902                 white.g = 0;
903                 white.b = 0;
904                 white.a = 0;
905         }
906
907         gp = text->glyph;
908         i = text->glyph_count;
909         x = p->x << 6;
910         y = p->y << 6;
911         while (i-- > 0) {
912                 g = *gp++;
913                 if (g->w && g->h && bg) {
914                         stride = (g->w + 2) * 4;
915                         if (color) {
916                                 shadow = g_malloc(stride * (g->h + 2));
917                                 gr->freetype_methods.get_shadow(g, shadow,
918                                                                 32, stride,
919                                                                 &white,
920                                                                 &transparent);
921 #ifdef USE_OPENGLES
922                                 struct point p;
923                                 p.x=((x + g->x) >> 6)-1;
924                                 p.y=((y + g->y) >> 6)-1;
925                                 draw_image_es(gr, &p, g->w+2, g->h+2, shadow);
926 #else
927 #ifdef MIRRORED_VIEW
928                                 glPixelZoom(-1.0, -1.0);        //mirrored mode
929 #else
930                                 glPixelZoom(1.0, -1.0);
931 #endif
932                                 glRasterPos2d((x + g->x) >> 6,
933                                               (y + g->y) >> 6);
934                                 glDrawPixels(g->w + 2, g->h + 2, PIXEL_FORMAT,
935                                              GL_UNSIGNED_BYTE, shadow);
936 #endif
937                                 g_free(shadow);
938                         }
939                 }
940                 x += g->dx;
941                 y += g->dy;
942         }
943
944         x = p->x << 6;
945         y = p->y << 6;
946         gp = text->glyph;
947         i = text->glyph_count;
948         while (i-- > 0) {
949                 g = *gp++;
950                 if (g->w && g->h) {
951                         if (color) {
952                                 stride = g->w;
953                                 if (bg) {
954                                         glyph =
955                                             g_malloc(stride * g->h * 4);
956                                         gr->freetype_methods.get_glyph(g,
957                                                                        glyph,
958                                                                        32,
959                                                                        stride
960                                                                        * 4,
961                                                                        &black,
962                                                                        &white,
963                                                                        &transparent);
964 #ifdef USE_OPENGLES
965                                         struct point p;
966                                         p.x=(x + g->x) >> 6;
967                                         p.y=(y + g->y) >> 6;
968                                         draw_image_es(gr, &p, g->w, g->h, glyph);
969 #else
970 #ifdef MIRRORED_VIEW
971                                         glPixelZoom(-1.0, -1.0);        //mirrored mode
972 #else
973                                         glPixelZoom(1.0, -1.0);
974 #endif
975                                         glRasterPos2d((x + g->x) >> 6,
976                                                       (y + g->y) >> 6);
977                                         glDrawPixels(g->w, g->h, PIXEL_FORMAT,
978                                                      GL_UNSIGNED_BYTE,
979                                                      glyph);
980 #endif
981                                         g_free(glyph);
982                                 }
983                                 stride *= 4;
984                                 glyph = g_malloc(stride * g->h);
985                                 gr->freetype_methods.get_glyph(g, glyph,
986                                                                32, stride,
987                                                                &black,
988                                                                &white,
989                                                                &transparent);
990 #ifdef USE_OPENGLES
991                                 struct point p;
992                                 p.x=(x + g->x) >> 6;
993                                 p.y=(y + g->y) >> 6;
994                                 draw_image_es(gr, &p, g->w, g->h, glyph);
995 #else
996 #ifdef MIRRORED_VIEW
997                                 glPixelZoom(-1.0, -1.0);        //mirrored mode
998 #else
999                                 glPixelZoom(1.0, -1.0);
1000 #endif
1001                                 glRasterPos2d((x + g->x) >> 6,
1002                                               (y + g->y) >> 6);
1003                                 glDrawPixels(g->w, g->h, PIXEL_FORMAT,
1004                                              GL_UNSIGNED_BYTE, glyph);
1005 #endif
1006                                 g_free(glyph);
1007                         }
1008                 }
1009                 x += g->dx;
1010                 y += g->dy;
1011         }
1012 }
1013
1014 static void
1015 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1016           struct graphics_gc_priv *bg, struct graphics_font_priv *font,
1017           char *text, struct point *p, int dx, int dy)
1018 {
1019         if ((gr->parent && !gr->parent->overlay_enabled)
1020             || (gr->parent && gr->parent->overlay_enabled
1021                 && !gr->overlay_enabled)) {
1022                 return;
1023         }
1024
1025         struct font_freetype_text *t;
1026         int color = 1;
1027
1028         if (!font) {
1029                 dbg(0, "no font, returning\n");
1030                 return;
1031         }
1032
1033         graphics_priv_root->dirty = 1;
1034
1035         t = gr->freetype_methods.text_new(text,
1036                                           (struct font_freetype_font *)
1037                                           font, dx, dy);
1038
1039         struct point p_eff;
1040         p_eff.x = p->x;
1041         p_eff.y = p->y;
1042
1043         display_text_draw(t, gr, fg, bg, color, &p_eff);
1044         gr->freetype_methods.text_destroy(t);
1045 }
1046
1047
1048 static void
1049 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1050            struct point *p, struct graphics_image_priv *img)
1051 {
1052 #ifdef USE_OPENGLES
1053         draw_image_es(gr, p, img->w, img->h, img->data);
1054 #else
1055         if ((gr->parent && !gr->parent->overlay_enabled)
1056             || (gr->parent && gr->parent->overlay_enabled
1057                 && !gr->overlay_enabled)) {
1058                 return;
1059         }
1060
1061         if (!img || !img->data) {
1062                 return;
1063         }
1064
1065         graphics_priv_root->dirty = 1;
1066
1067         struct point p_eff;
1068         p_eff.x = p->x + img->hot_x;
1069         p_eff.y = p->y + img->hot_y;
1070
1071         glEnable(GL_BLEND);
1072         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1073
1074         glRasterPos2d(p_eff.x - img->hot_x, p_eff.y - img->hot_y);
1075         glDrawPixels(img->w, img->h, GL_RGBA, GL_UNSIGNED_BYTE, img->data);
1076 #endif
1077
1078 }
1079
1080 static void
1081 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1082                 struct point *p, int count, char *data)
1083 {
1084 }
1085
1086 static void
1087 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1088 {
1089 }
1090
1091 static void
1092 draw_drag(struct graphics_priv *gr, struct point *p)
1093 {
1094
1095         if (p) {
1096                 gr->p.x = p->x;
1097                 gr->p.y = p->y;
1098         }
1099 }
1100
1101 static void
1102 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1103 {
1104         gr->background_gc = gc;
1105 }
1106
1107 static void
1108 handle_mouse_queue()
1109 {
1110 #ifdef USE_OPENGLES
1111 #else
1112         static locked = 0;
1113         if (!locked) {
1114                 locked = 1;
1115         } else {
1116                 return;
1117         }
1118
1119         if (mouse_event_queue_begin_idx < mouse_event_queue_end_idx) {
1120                 if (mouse_queue[mouse_event_queue_begin_idx].button ==
1121                     GLUT_LEFT_BUTTON
1122                     && mouse_queue[mouse_event_queue_begin_idx].state ==
1123                     GLUT_UP) {
1124                         struct point p;
1125                         p.x =
1126                             mouse_queue[mouse_event_queue_begin_idx %
1127                                         mouse_event_queue_size].x;
1128                         p.y =
1129                             mouse_queue[mouse_event_queue_begin_idx %
1130                                         mouse_event_queue_size].y;
1131                         graphics_priv_root->force_redraw = 1;
1132                         callback_list_call_attr_3(graphics_priv_root->cbl,
1133                                                   attr_button, (void *) 0,
1134                                                   1, (void *) &p);
1135                 } else if (mouse_queue[mouse_event_queue_begin_idx].
1136                            button == GLUT_LEFT_BUTTON
1137                            && mouse_queue[mouse_event_queue_begin_idx].
1138                            state == GLUT_DOWN) {
1139                         struct point p;
1140                         p.x =
1141                             mouse_queue[mouse_event_queue_begin_idx %
1142                                         mouse_event_queue_size].x;
1143                         p.y =
1144                             mouse_queue[mouse_event_queue_begin_idx %
1145                                         mouse_event_queue_size].y;
1146                         graphics_priv_root->force_redraw = 1;
1147                         callback_list_call_attr_3(graphics_priv_root->cbl,
1148                                                   attr_button, (void *) 1,
1149                                                   1, (void *) &p);
1150                 }
1151                 ++mouse_event_queue_begin_idx;
1152         }
1153         locked = 0;
1154 #endif
1155 }
1156
1157
1158 /*draws root graphics and its overlays*/
1159 static int
1160 redraw_screen(struct graphics_priv *gr)
1161 {
1162 #ifdef USE_OPENGLES
1163 #else
1164         time_t curr_time = time(0);
1165         graphics_priv_root->dirty = 0;
1166
1167         glCallList(gr->DLid);
1168         //display overlays display list
1169         struct graphics_priv *overlay;
1170         overlay = gr->overlays;
1171         while (gr->overlay_enabled && overlay) {
1172                 if (overlay->overlay_enabled) {
1173                         glPushMatrix();
1174                         struct point p_eff;
1175                         get_overlay_pos(overlay, &p_eff);
1176                         glTranslatef(p_eff.x, p_eff.y, 1);
1177                         glCallList(overlay->DLid);
1178                         glPopMatrix();
1179                 }
1180                 overlay = overlay->next;
1181         }
1182         glutSwapBuffers();
1183 #endif
1184
1185         return TRUE;
1186 }
1187
1188
1189 #ifndef USE_OPENGLES
1190 /*filters call to redraw in overlay enabled(map) mode*/
1191 static void
1192 redraw_filter(struct graphics_priv *gr)
1193 {
1194         if (gr->overlay_enabled && gr->dirty) {
1195                 redraw_screen(gr);
1196         }
1197 }
1198 #endif
1199
1200
1201
1202 static void
1203 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1204 {
1205         if (gr->parent) {       //overlay
1206 #ifdef USE_OPENGLES
1207 #else
1208                 if (mode == draw_mode_begin) {
1209                         glNewList(gr->DLid, GL_COMPILE);
1210                 }
1211
1212                 if (mode == draw_mode_end || mode == draw_mode_end_lazy) {
1213                         glEndList();
1214                 }
1215 #endif
1216         } else {                //root graphics
1217                 if (mode == draw_mode_begin) {
1218 #ifdef USE_OPENGLES
1219 #else
1220                         glNewList(gr->DLid, GL_COMPILE);
1221 #endif
1222                 }
1223
1224                 if (mode == draw_mode_end) {
1225 #ifdef USE_OPENGLES
1226                         gr->platform_methods->swap_buffers(gr->platform);
1227 #else
1228                         glEndList();
1229                         gr->force_redraw = 1;
1230                         if (!gr->overlay_enabled || gr->force_redraw) {
1231                                 redraw_screen(gr);
1232                         }
1233 #endif
1234                 }
1235         }
1236         gr->mode = mode;
1237 }
1238
1239 static struct graphics_priv *overlay_new(struct graphics_priv *gr,
1240                                          struct graphics_methods *meth,
1241                                          struct point *p, int w, int h,
1242                                          int alpha, int wraparound);
1243
1244 static int
1245 graphics_opengl_fullscreen(struct window *w, int on)
1246 {
1247         return 1;
1248 }
1249
1250 static void
1251 graphics_opengl_disable_suspend(struct window *w)
1252 {
1253 }
1254
1255 #ifdef USE_OPENGLES2
1256 static GLuint
1257 load_shader(const char *shader_source, GLenum type)
1258 {
1259         GLuint shader = glCreateShader(type);
1260
1261         glShaderSource(shader, 1, &shader_source, NULL);
1262         glCompileShader(shader);
1263
1264         return shader;
1265 }
1266 #endif
1267
1268 static void *
1269 get_data(struct graphics_priv *this, char *type)
1270 {
1271         /*TODO initialize gtkglext context when type=="gtk_widget" */
1272         if (!strcmp(type, "gtk_widget")) {
1273                 fprintf(stderr,
1274                         "Currently GTK gui is not yet supported with opengl graphics driver\n");
1275                 return NULL;
1276         }
1277         if (strcmp(type, "window") == 0) {
1278                 struct window *win;
1279 #ifdef USE_OPENGLES
1280                 GLuint vertexShader;
1281                 GLuint fragmentShader;
1282                 GLuint textures;
1283                 GLfloat matrix[16];
1284                 int i;
1285
1286                 this->window_system=graphics_opengl_x11_new(NULL, this->width, this->height, 32, &this->window_system_methods);
1287                 this->platform=graphics_opengl_egl_new(this->window_system_methods->get_display(this->window_system),
1288                                                        this->window_system_methods->get_window(this->window_system),
1289                                                        &this->platform_methods);
1290                 this->window_system_methods->set_callbacks(this->window_system, this, resize_callback_do, click_notify_do, motion_notify_do, NULL);
1291                 resize_callback(this->width,this->height);
1292 #if 0
1293                 glClearColor ( 0.4 , 0.4 , 0.4 , 1);
1294 #endif
1295                 glClear ( GL_COLOR_BUFFER_BIT );
1296 #ifdef USE_OPENGLES2
1297                 this->program=glCreateProgram();
1298                 vertexShader = load_shader(vertex_src, GL_VERTEX_SHADER);
1299                 fragmentShader = load_shader(fragment_src, GL_FRAGMENT_SHADER);
1300                 glAttachShader(this->program, vertexShader);
1301                 glAttachShader(this->program, fragmentShader);
1302                 glLinkProgram(this->program);
1303                 glUseProgram(this->program);
1304                 this->mvp_location=glGetUniformLocation(this->program, "mvp");
1305                 this->position_location=glGetAttribLocation(this->program, "position");
1306                 glEnableVertexAttribArray(this->position_location);
1307                 this->texture_position_location=glGetAttribLocation(this->program, "texture_position");
1308                 this->color_location=glGetUniformLocation(this->program, "avcolor");
1309                 this->texture_location=glGetUniformLocation(this->program, "texture");
1310                 this->use_texture_location=glGetUniformLocation(this->program, "use_texture");
1311                 glUniform1i(this->use_texture_location, 0);
1312                 glUniform1i(this->texture_location, 0);
1313
1314                 for (i = 0 ; i < 16 ; i++)
1315                         matrix[i]=0.0;
1316                 matrix[0]=2.0/this->width;
1317                 matrix[5]=-2.0/this->height;
1318                 matrix[10]=1;
1319                 matrix[12]=-1;
1320                 matrix[13]=1;
1321                 matrix[15]=1;
1322                 glUniformMatrix4fv(this->mvp_location, 1, GL_FALSE, matrix);
1323 #else
1324                 glEnableClientState(GL_VERTEX_ARRAY);
1325 #endif
1326                 glGenTextures(1, &textures);
1327                 glActiveTexture(GL_TEXTURE0);
1328                 glBindTexture(GL_TEXTURE_2D, textures);
1329                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1330                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1331                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1332                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1333 #ifndef USE_OPENGLES2
1334                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1335 #endif
1336 #endif
1337                 win = g_new0(struct window, 1);
1338                 win->priv = this;
1339                 win->fullscreen = graphics_opengl_fullscreen;
1340                 win->disable_suspend = graphics_opengl_disable_suspend;
1341                 return win;
1342         } else {
1343 #ifdef USE_OPENGLES
1344                 return NULL;
1345 #else
1346                 return &this->DLid;
1347 #endif
1348         }
1349
1350
1351 }
1352
1353 static void
1354 image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
1355 {
1356 //TODO free image data in hashtable when graphics is destroyed
1357 //currently graphics destroy is not called !!!
1358 /*
1359   g_free(priv->data);
1360   priv->data = NULL;
1361   g_free(priv); 
1362   priv = NULL;
1363 */
1364 }
1365
1366 static void
1367 overlay_disable(struct graphics_priv *gr, int disable)
1368 {
1369         gr->overlay_enabled = !disable;
1370         gr->force_redraw = 1;
1371         draw_mode(gr, draw_mode_end);
1372 }
1373
1374 static void
1375 overlay_resize(struct graphics_priv *gr, struct point *p, int w, int h,
1376                int alpha, int wraparound)
1377 {
1378         int changed = 0;
1379         int w2, h2;
1380
1381         if (w == 0) {
1382                 w2 = 1;
1383         } else {
1384                 w2 = w;
1385         }
1386
1387         if (h == 0) {
1388                 h2 = 1;
1389         } else {
1390                 h2 = h;
1391         }
1392
1393         gr->p = *p;
1394         if (gr->width != w2) {
1395                 gr->width = w2;
1396                 changed = 1;
1397         }
1398
1399         if (gr->height != h2) {
1400                 gr->height = h2;
1401                 changed = 1;
1402         }
1403
1404         gr->wraparound = wraparound;
1405
1406         if (changed) {
1407                 if ((w == 0) || (h == 0)) {
1408                         gr->overlay_autodisabled = 1;
1409                 } else {
1410                         gr->overlay_autodisabled = 0;
1411                 }
1412
1413                 callback_list_call_attr_2(gr->cbl, attr_resize,
1414                                           GINT_TO_POINTER(gr->width),
1415                                           GINT_TO_POINTER(gr->height));
1416         }
1417 }
1418
1419 static struct graphics_methods graphics_methods = {
1420         graphics_destroy,
1421         draw_mode,
1422         draw_lines,
1423         draw_polygon,
1424         draw_rectangle,
1425         NULL,
1426         draw_text,
1427         draw_image,
1428         draw_image_warp,
1429         draw_restore,
1430         draw_drag,
1431         NULL,
1432         gc_new,
1433         background_gc,
1434         overlay_new,
1435         image_new,
1436         get_data,
1437         image_free,
1438         NULL,
1439         overlay_disable,
1440         overlay_resize,
1441 };
1442
1443 static struct graphics_priv *
1444 graphics_opengl_new_helper(struct graphics_methods *meth)
1445 {
1446         struct font_priv *(*font_freetype_new) (void *meth);
1447         font_freetype_new = plugin_get_font_type("freetype");
1448
1449         if (!font_freetype_new) {
1450                 return NULL;
1451         }
1452
1453         struct graphics_priv *this = g_new0(struct graphics_priv, 1);
1454
1455         font_freetype_new(&this->freetype_methods);
1456         *meth = graphics_methods;
1457
1458         meth->font_new =
1459             (struct graphics_font_priv *
1460              (*)(struct graphics_priv *, struct graphics_font_methods *,
1461                  char *, int, int)) this->freetype_methods.font_new;
1462         meth->get_text_bbox = this->freetype_methods.get_text_bbox;
1463
1464         return this;
1465 }
1466
1467 static struct graphics_priv *
1468 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth,
1469             struct point *p, int w, int h, int alpha, int wraparound)
1470 {
1471         int w2, h2;
1472         struct graphics_priv *this = graphics_opengl_new_helper(meth);
1473         this->p = *p;
1474         this->width = w;
1475         this->height = h;
1476         this->parent = gr;
1477
1478         /* If either height or width is 0, we set it to 1 to avoid warnings, and
1479          * disable the overlay. */
1480         if (h == 0) {
1481                 h2 = 1;
1482         } else {
1483                 h2 = h;
1484         }
1485
1486         if (w == 0) {
1487                 w2 = 1;
1488         } else {
1489                 w2 = w;
1490         }
1491
1492         if ((w == 0) || (h == 0)) {
1493                 this->overlay_autodisabled = 1;
1494         } else {
1495                 this->overlay_autodisabled = 0;
1496         }
1497         this->overlay_enabled = 1;
1498         this->overlay_autodisabled = 0;
1499
1500         this->next = gr->overlays;
1501         gr->overlays = this;
1502 #ifdef USE_OPENGLES
1503 #else
1504         this->DLid = glGenLists(1);
1505 #endif
1506         return this;
1507 }
1508
1509
1510 static void
1511 click_notify_do(struct graphics_priv *priv, int button, int state, int x, int y)
1512 {
1513         struct point p={x,y};
1514         dbg(0,"enter state %d button %d\n",state,button);
1515         callback_list_call_attr_3(priv->cbl, attr_button, (void *) state, (void *)button, (void *) &p);
1516 }
1517
1518 static void
1519 click_notify(int button, int state, int x, int y)
1520 {
1521         mouse_queue[mouse_event_queue_end_idx %
1522                     mouse_event_queue_size].button = button;
1523         mouse_queue[mouse_event_queue_end_idx %
1524                     mouse_event_queue_size].state = state;
1525 #ifdef MIRRORED_VIEW
1526         mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].x =
1527             graphics_priv_root->width - x;
1528 #else
1529         mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].x =
1530             x;
1531 #endif
1532         mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].y =
1533             y;
1534         ++mouse_event_queue_end_idx;
1535 }
1536
1537 static void
1538 motion_notify_do(struct graphics_priv *priv, int x, int y)
1539 {
1540         struct point p;
1541 #ifdef MIRRORED_VIEW
1542         p.x = priv->width - x;
1543 #else
1544         p.x = x;
1545 #endif
1546         p.y = y;
1547         callback_list_call_attr_1(priv->cbl, attr_motion,
1548                                   (void *) &p);
1549         return;
1550 }
1551
1552 static void
1553 motion_notify(int x, int y)
1554 {
1555         motion_notify_do(graphics_priv_root, x, y);
1556 }
1557
1558 #ifndef USE_OPENGLES
1559 static gboolean
1560 graphics_opengl_idle(void *data)
1561 {
1562         static int opengl_init_ok = 0;
1563         if (!opengl_init_ok) {
1564                 callback_list_call_attr_2(graphics_priv_root->cbl,
1565                                           attr_resize,
1566                                           GINT_TO_POINTER
1567                                           (graphics_priv_root->width),
1568                                           GINT_TO_POINTER
1569                                           (graphics_priv_root->height));
1570                 opengl_init_ok = 1;
1571         } else {
1572                 
1573 #ifdef FREEGLUT
1574                 glutMainLoopEvent();
1575 #endif
1576                 handle_mouse_queue();
1577         }
1578         return TRUE;
1579 }
1580 #endif
1581
1582 static void
1583 ProcessNormalKeys(unsigned char key_in, int x, int y)
1584 {
1585         int key = 0;
1586         char keybuf[2];
1587
1588         switch (key_in) {
1589         case 13:
1590                 key = NAVIT_KEY_RETURN;
1591                 break;
1592         default:
1593                 key = key_in;
1594                 break;
1595         }
1596         keybuf[0] = key;
1597         keybuf[1] = '\0';
1598         graphics_priv_root->force_redraw = 1;
1599         callback_list_call_attr_1(graphics_priv_root->cbl, attr_keypress,
1600                                   (void *) keybuf);
1601 }
1602
1603 static void
1604 ProcessSpecialKeys(int key_in, int x, int y)
1605 {
1606         int key = 0;
1607         char keybuf[2];
1608
1609         switch (key_in) {
1610         case 102:
1611                 key = NAVIT_KEY_RIGHT;
1612                 break;
1613         case 100:
1614                 key = NAVIT_KEY_LEFT;
1615                 break;
1616         case 103:
1617                 key = NAVIT_KEY_DOWN;
1618                 break;
1619         case 101:
1620                 key = NAVIT_KEY_UP;
1621                 break;
1622         case 104:
1623                 key = NAVIT_KEY_ZOOM_OUT;
1624                 break;
1625         case 105:
1626                 key = NAVIT_KEY_ZOOM_IN;
1627                 break;
1628         default:
1629                 break;
1630         }                       //switch
1631
1632         graphics_priv_root->force_redraw = 1;
1633         keybuf[0] = key;
1634         keybuf[1] = '\0';
1635         callback_list_call_attr_1(graphics_priv_root->cbl, attr_keypress,
1636                                   (void *) keybuf);
1637 }
1638
1639 static void
1640 resize_callback_do(struct graphics_priv *priv, int w, int h)
1641 {
1642         glViewport(0, 0, w, h);
1643 #ifndef USE_OPENGLES2
1644         glMatrixMode(GL_PROJECTION);
1645         glLoadIdentity();
1646 #ifdef MIRRORED_VIEW
1647         glOrthof(glF(w), glF(0), glF(h), glF(0), glF(1), glF(-1));
1648 #else
1649         glOrthof(glF(0), glF(w), glF(h), glF(0), glF(1), glF(-1));
1650 #endif
1651 #endif
1652         priv->width = w;
1653         priv->height = h;
1654
1655         callback_list_call_attr_2(priv->cbl, attr_resize,
1656                                   GINT_TO_POINTER(w), GINT_TO_POINTER(h));
1657 }
1658
1659 static void
1660 resize_callback(int w, int h)
1661 {
1662         resize_callback_do(graphics_priv_root, w, h);
1663 }
1664
1665 static void
1666 display(void)
1667 {
1668         graphics_priv_root->force_redraw = 1;
1669         redraw_screen(graphics_priv_root);
1670         resize_callback(graphics_priv_root->width,
1671                         graphics_priv_root->height);
1672 }
1673
1674 static void
1675 glut_close(void)
1676 {
1677         callback_list_call_attr_0(graphics_priv_root->cbl,
1678                                   attr_window_closed);
1679 }
1680
1681
1682 static struct graphics_priv *
1683 graphics_opengl_new(struct navit *nav, struct graphics_methods *meth,
1684                     struct attr **attrs, struct callback_list *cbl)
1685 {
1686         struct attr *attr;
1687
1688         if (!event_request_system("glib", "graphics_opengl_new"))
1689                 return NULL;
1690
1691         struct graphics_priv *this = graphics_opengl_new_helper(meth);
1692         graphics_priv_root = this;
1693
1694         this->nav = nav;
1695         this->parent = NULL;
1696         this->overlay_enabled = 1;
1697
1698         this->width = SCREEN_WIDTH;
1699         if ((attr = attr_search(attrs, NULL, attr_w)))
1700                 this->width = attr->u.num;
1701         this->height = SCREEN_HEIGHT;
1702         if ((attr = attr_search(attrs, NULL, attr_h)))
1703                 this->height = attr->u.num;
1704         this->timeout = 100;
1705         if ((attr = attr_search(attrs, NULL, attr_timeout)))
1706                 this->timeout = attr->u.num;
1707         this->delay = 0;
1708         if ((attr = attr_search(attrs, NULL, attr_delay)))
1709                 this->delay = attr->u.num;
1710         this->cbl = cbl;
1711
1712         char *cmdline = "";
1713         int argc = 0;
1714 #ifndef USE_OPENGLES
1715         glutInit(&argc, &cmdline);
1716         glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
1717
1718         glutInitWindowSize(this->width, this->height);
1719         glutInitWindowPosition(0, 0);
1720         glutCreateWindow("Navit opengl window");
1721
1722         glutDisplayFunc(display);
1723         glutReshapeFunc(resize_callback);
1724         resize_callback(this->width, this->height);
1725 #endif
1726
1727         graphics_priv_root->cbl = cbl;
1728         graphics_priv_root->width = this->width;
1729         graphics_priv_root->height = this->height;
1730
1731 #ifndef USE_OPENGLES
1732         glutMotionFunc(motion_notify);
1733         glutPassiveMotionFunc(motion_notify);
1734         glutMouseFunc(click_notify);
1735         glutKeyboardFunc(ProcessNormalKeys);
1736         glutSpecialFunc(ProcessSpecialKeys);
1737 #ifdef FREEGLUT
1738         glutCloseFunc(glut_close);
1739 #endif
1740         this->DLid = glGenLists(1);
1741
1742         g_timeout_add(G_PRIORITY_DEFAULT + 10, graphics_opengl_idle, NULL);
1743
1744         /*this will only refresh screen in map(overlay enabled) mode */
1745         g_timeout_add(G_PRIORITY_DEFAULT + 1000, redraw_filter, this);
1746 #endif
1747
1748         //create hash table for uncompressed image data
1749         hImageData = g_hash_table_new(g_str_hash, g_str_equal);
1750         return this;
1751 }
1752
1753
1754 static void
1755 event_opengl_main_loop_run(void)
1756 {
1757         dbg(0, "enter\n");
1758 }
1759
1760 static void
1761 event_opengl_main_loop_quit(void)
1762 {
1763         dbg(0, "enter\n");
1764 }
1765
1766 static struct event_watch *
1767 event_opengl_add_watch(void *h, enum event_watch_cond cond,
1768                        struct callback *cb)
1769 {
1770         dbg(0, "enter\n");
1771         return NULL;
1772 }
1773
1774 static void
1775 event_opengl_remove_watch(struct event_watch *ev)
1776 {
1777         dbg(0, "enter\n");
1778 }
1779
1780
1781 static struct event_timeout *
1782 event_opengl_add_timeout(int timeout, int multi, struct callback *cb)
1783 {
1784         dbg(0, "enter\n");
1785         return NULL;
1786 }
1787
1788 static void
1789 event_opengl_remove_timeout(struct event_timeout *to)
1790 {
1791         dbg(0, "enter\n");
1792 }
1793
1794
1795 static struct event_idle *
1796 event_opengl_add_idle(int priority, struct callback *cb)
1797 {
1798         dbg(0, "enter\n");
1799         return NULL;
1800 }
1801
1802 static void
1803 event_opengl_remove_idle(struct event_idle *ev)
1804 {
1805         dbg(0, "enter\n");
1806 }
1807
1808 static void
1809 event_opengl_call_callback(struct callback_list *cb)
1810 {
1811         dbg(0, "enter\n");
1812 }
1813
1814 static struct event_methods event_opengl_methods = {
1815         event_opengl_main_loop_run,
1816         event_opengl_main_loop_quit,
1817         event_opengl_add_watch,
1818         event_opengl_remove_watch,
1819         event_opengl_add_timeout,
1820         event_opengl_remove_timeout,
1821         event_opengl_add_idle,
1822         event_opengl_remove_idle,
1823         event_opengl_call_callback,
1824 };
1825
1826 static struct event_priv *
1827 event_opengl_new(struct event_methods *meth)
1828 {
1829         *meth = event_opengl_methods;
1830         return NULL;
1831 }
1832
1833 void
1834 plugin_init(void)
1835 {
1836         plugin_register_graphics_type("opengl", graphics_opengl_new);
1837         plugin_register_event_type("opengl", event_opengl_new);
1838 }