2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2010 Navit Team
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.
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.
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.
21 #define REQUIRES_POWER_OF_2 0
42 #include "navit/font/freetype/font_freetype.h"
44 #if defined(WINDOWS) || defined(WIN32)
45 #define PIXEL_FORMAT GL_RGBA
47 # define sleep(i) Sleep(i * 1000)
49 #define PIXEL_FORMAT GL_BGRA
53 #include <FreeImage.h>
58 #include <GLES2/gl2.h>
66 extern EGLSurface eglwindow;
67 extern EGLDisplay egldisplay;
69 #define glOrthof glOrtho
73 #include <GLUT/glut.h>
75 #include <GL/glut.h> /* glut.h includes gl.h and glu.h */
85 #define glF(x) ((GLfixed)((x)*(1<<16)))
90 #define glClearColor glClearColorx
91 #define glTranslatef glTranslatex
92 #define glRotatef glRotatex
93 #define glMaterialfv glMaterialxv
94 #define glMaterialf glMaterialx
95 #define glOrthof glOrthox
96 #define glScalef glScalex
97 #define glColor4f glColor4x
99 #define glTexParameteri glTexParameterx
101 #define SCREEN_WIDTH 700
102 #define SCREEN_HEIGHT 700
104 //#define MIRRORED_VIEW 1
106 struct graphics_gc_priv {
107 struct graphics_priv *gr;
108 float fr, fg, fb, fa;
109 float br, bg, bb, ba;
111 unsigned char *dash_list;
116 struct graphics_priv {
124 int overlay_autodisabled;
126 struct graphics_priv *parent;
127 struct graphics_priv *overlays;
128 struct graphics_priv *next;
129 struct graphics_gc_priv *background_gc;
130 enum draw_mode_num mode;
131 void (*resize_callback) (void *data, int w, int h);
132 void *resize_callback_data;
133 void (*motion_callback) (void *data, struct point * p);
134 void *motion_callback_data;
135 void (*button_callback) (void *data, int press, int button,
137 void *button_callback_data;
140 GLint mvp_location, position_location, color_location, texture_position_location, use_texture_location, texture_location;
144 struct callback_list *cbl;
145 struct font_freetype_methods freetype_methods;
149 struct window window;
150 int dirty; //display needs to be redrawn (draw on root graphics or overlay is done)
151 int force_redraw; //display needs to be redrawn (draw on root graphics or overlay is done)
152 time_t last_refresh_time; //last display refresh time
155 static struct graphics_priv *graphics_priv_root;
156 struct graphics_image_priv {
163 } graphics_image_priv;
165 struct mouse_event_queue_element {
172 static const int mouse_event_queue_size = 100;
173 static int mouse_event_queue_begin_idx = 0;
174 static int mouse_event_queue_end_idx = 0;
175 static struct mouse_event_queue_element mouse_queue[100];
177 //hastable for uncompressed image data
178 static GHashTable *hImageData;
183 void APIENTRY tessBeginCB(GLenum which);
184 void APIENTRY tessEndCB();
185 void APIENTRY tessErrorCB(GLenum errorCode);
186 void APIENTRY tessVertexCB(const GLvoid * data);
187 void APIENTRY tessVertexCB2(const GLvoid * data);
188 void APIENTRY tessCombineCB(GLdouble c[3], void *d[4], GLfloat w[4], void **out);
189 const char *getPrimitiveType(GLenum type);
192 static struct graphics_priv *graphics_opengl_new_helper(struct
195 static void display(void);
196 static void resize_callback(int w, int h);
197 static void glut_close();
200 const char vertex_src [] =
202 attribute vec2 position; \
203 attribute vec2 texture_position; \
205 varying vec2 v_texture_position; \
209 v_texture_position=texture_position; \
210 gl_Position = mvp*vec4(position, 0.0, 1.0); \
214 const char fragment_src [] =
216 uniform lowp vec4 avcolor; \
217 uniform sampler2D texture; \
218 uniform bool use_texture; \
219 varying vec2 v_texture_position; \
223 gl_FragColor = texture2D(texture, v_texture_position); \
225 gl_FragColor = avcolor; \
232 graphics_destroy(struct graphics_priv *gr)
234 /*FIXME graphics_destroy is never called */
235 /*TODO add destroy code for image cache(delete entries in hImageData) */
241 gc_destroy(struct graphics_gc_priv *gc)
248 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
254 gc_set_dashes(struct graphics_gc_priv *gc, int width, int offset,
255 unsigned char *dash_list, int n)
258 const int cOpenglMaskBits = 16;
262 for (i = 0; i < cOpenglMaskBits; ++i) {
264 gc->dash_mask |= (i / n) % 2;
267 unsigned char *curr = dash_list;
268 int cnt = 0; //dot counter
269 int dcnt = 0; //dash element counter
273 for (i = 0; i < n; ++i) {
274 sum_dash += dash_list[i];
277 //scale dashlist elements to max size
278 if (sum_dash > cOpenglMaskBits) {
279 int num_error[2] = { 0, 0 }; //count elements rounded to 0 for odd(drawn) and even(masked) for compensation
280 double factor = (1.0 * cOpenglMaskBits) / sum_dash;
281 for (i = 0; i < n; ++i) { //calculate dashlist max and largest common denomiator for scaling
282 dash_list[i] *= factor;
283 if (dash_list[i] == 0) {
286 } else if (0 < num_error[i % 2]
287 && 2 < dash_list[i]) {
294 for (i = 0; i < cOpenglMaskBits; ++i) {
296 gc->dash_mask |= 1 - dcnt % 2;
312 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
314 gc->fr = c->r / 65535.0;
315 gc->fg = c->g / 65535.0;
316 gc->fb = c->b / 65535.0;
317 gc->fa = c->a / 65535.0;
321 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
323 gc->br = c->r / 65535.0;
324 gc->bg = c->g / 65535.0;
325 gc->bb = c->b / 65535.0;
326 gc->ba = c->a / 65535.0;
329 static struct graphics_gc_methods gc_methods = {
337 static struct graphics_gc_priv *
338 gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
340 struct graphics_gc_priv *gc = g_new0(struct graphics_gc_priv, 1);
348 static struct graphics_image_priv image_error;
350 static struct graphics_image_priv *
351 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth,
352 char *path, int *w, int *h, struct point *hot, int rotation)
358 int width, height, i, j;
359 struct graphics_image_priv *gi;
360 //check if image already exists in hashmap
361 struct graphics_image_priv *curr_elem =
362 g_hash_table_lookup(hImageData, path);
363 if (curr_elem == &image_error) {
364 //found but couldn't be loaded
366 } else if (curr_elem) {
367 //found and OK -> use hastable entry
370 hot->x = curr_elem->w / 2 - 1;
371 hot->y = curr_elem->h / 2 - 1;
374 if (strlen(path) < 4) {
375 g_hash_table_insert(hImageData, g_strdup(path),
379 char *ext_str = path + strlen(path) - 3;
380 if (strstr(ext_str, "png") || strstr(path, "PNG")) {
382 FreeImage_Load(FIF_PNG, path, 0)) == NULL) {
383 g_hash_table_insert(hImageData,
388 } else if (strstr(ext_str, "xpm") || strstr(path, "XPM")) {
390 FreeImage_Load(FIF_XPM, path, 0)) == NULL) {
391 g_hash_table_insert(hImageData,
396 } else if (strstr(ext_str, "svg") || strstr(path, "SVG")) {
398 snprintf(path_new, strlen(path) - 3, "%s", path);
399 strcat(path_new, "_48_48.png");
402 FreeImage_Load(FIF_PNG, path_new,
404 g_hash_table_insert(hImageData,
410 g_hash_table_insert(hImageData, g_strdup(path),
415 if (FreeImage_GetBPP(image) == 64) {
417 image2 = FreeImage_ConvertTo32Bits(image);
418 FreeImage_Unload(image);
421 #if FREEIMAGE_MAJOR_VERSION*100+FREEIMAGE_MINOR_VERSION >= 313
424 image2 = FreeImage_Rotate(image, rotation, NULL);
429 gi = g_new0(struct graphics_image_priv, 1);
431 width = FreeImage_GetWidth(image);
432 height = FreeImage_GetHeight(image);
434 if ((*w != width || *h != height) && 0 < *w && 0 < *h) {
436 image2 = FreeImage_Rescale(image, *w, *h, NULL);
437 FreeImage_Unload(image);
443 data = (unsigned char *) malloc(width * height * 4);
445 RGBQUAD *palette = NULL;
446 if (FreeImage_GetBPP(image) == 8) {
447 palette = FreeImage_GetPalette(image);
450 for (i = 0; i < height; i++) {
451 for (j = 0; j < width; j++) {
453 if (FreeImage_GetBPP(image) == 8) {
454 FreeImage_GetPixelIndex(image, j,
458 data[4 * width * i + 4 * j + 0] =
460 data[4 * width * i + 4 * j + 1] =
461 palette[idx].rgbGreen;
462 data[4 * width * i + 4 * j + 2] =
463 palette[idx].rgbBlue;
464 data[4 * width * i + 4 * j + 3] =
466 } else if (FreeImage_GetBPP(image) == 16
467 || FreeImage_GetBPP(image) == 24
468 || FreeImage_GetBPP(image) ==
470 FreeImage_GetPixelColor(image, j,
476 && aPixel.rgbBlue == 0
477 && aPixel.rgbGreen == 0);
478 data[4 * width * i + 4 * j + 0] =
479 transparent ? 0 : (aPixel.
481 data[4 * width * i + 4 * j + 1] =
483 data[4 * width * i + 4 * j + 2] =
484 transparent ? 0 : (aPixel.
486 data[4 * width * i + 4 * j + 3] =
487 transparent ? 0 : 255;
493 FreeImage_Unload(image);
499 gi->hot_x = width / 2 - 1;
500 gi->hot_y = height / 2 - 1;
501 hot->x = width / 2 - 1;
502 hot->y = height / 2 - 1;
506 g_hash_table_insert(hImageData, g_strdup(path), gi);
517 set_color(struct graphics_priv *gr, struct graphics_gc_priv *gc)
525 glUniform4fv(gr->color_location, 1, col);
527 glColor4f(glF(gc->fr), glF(gc->fg), glF(gc->fb), glF(gc->fa));
532 draw_array(struct graphics_priv *gr, struct point *p, int count, GLenum mode)
537 for (i = 0 ; i < count ; i++) {
539 x[i*2+1]=glF(p[i].y);
542 glVertexAttribPointer (gr->position_location, 2, GL_FLOAT, 0, 0, x );
544 glVertexPointer(2, GL_F, 0, x);
546 glDrawArrays(mode, 0, count);
550 draw_rectangle_es(struct graphics_priv *gr, struct point *p, int w, int h)
553 pa[0]=pa[1]=pa[2]=pa[3]=*p;
558 draw_array(gr, pa, 4, GL_TRIANGLE_STRIP);
561 static int next_power2(int x)
570 draw_image_es(struct graphics_priv *gr, struct point *p, int w, int h, unsigned char *data)
574 memset(x, 0, sizeof(x));
575 #if REQUIRES_POWER_OF_2
576 int w2=next_power2(w);
577 int h2=next_power2(h);
579 if (w2 != w || h2 != h) {
580 char *newpix=g_malloc0(w2*h2*4);
581 for (y=0 ; y < h ; y++)
582 memcpy(newpix+y*w2*4, data+y*w*4, w*4);
583 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w2, h2, 0, GL_RGBA, GL_UNSIGNED_BYTE, newpix);
588 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
590 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
597 glUniform1i(gr->use_texture_location, 1);
598 glEnableVertexAttribArray(gr->texture_position_location);
599 glVertexAttribPointer (gr->texture_position_location, 2, GL_FLOAT, 0, 0, x );
601 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
602 glEnable(GL_TEXTURE_2D);
603 glTexCoordPointer(2, GL_F, 0, x);
606 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
607 draw_rectangle_es(gr, p, w, h);
609 glUniform1i(gr->use_texture_location, 0);
610 glDisableVertexAttribArray(gr->texture_position_location);
612 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
613 glDisable(GL_TEXTURE_2D);
621 getPrimitiveType(GLenum type)
633 ret = "GL_LINE_LOOP";
636 ret = "GL_LINE_STRIP";
639 ret = "GL_TRIANGLES";
642 ret = "GL_TRIANGLE_STRIP";
645 ret = "GL_TRIANGLE_FAN";
651 ret = "GL_QUAD_STRIP";
661 tessBeginCB(GLenum which)
665 dbg(1, "glBegin( %s );\n", getPrimitiveType(which));
675 dbg(1, "glEnd();\n");
681 tessVertexCB(const GLvoid * data)
683 // cast back to double type
684 const GLdouble *ptr = (const GLdouble *) data;
688 dbg(1, " glVertex3d();\n");
693 get_overlay_pos(struct graphics_priv *gr, struct point *point_out)
695 if (gr->parent == NULL) {
700 point_out->x = gr->p.x;
701 if (point_out->x < 0) {
702 point_out->x += gr->parent->width;
705 point_out->y = gr->p.y;
706 if (point_out->y < 0) {
707 point_out->y += gr->parent->height;
712 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc,
713 struct point *p, int count)
715 if ((gr->parent && !gr->parent->overlay_enabled)
716 || (gr->parent && gr->parent->overlay_enabled
717 && !gr->overlay_enabled)) {
720 #if !defined(USE_OPENGLES) || defined(USE_OPENGLES2)
721 glLineWidth(gc->linewidth);
725 draw_array(gr, p, count, GL_LINE_STRIP);
728 graphics_priv_root->dirty = 1;
730 glColor4f(gc->fr, gc->fg, gc->fb, gc->fa);
731 if (!gr->parent && 0 < gc->dash_count) {
732 glLineStipple(1, gc->dash_mask);
733 glEnable(GL_LINE_STIPPLE);
735 glBegin(GL_LINE_STRIP);
737 for (i = 0; i < count; i++) {
741 glVertex2f(p_eff.x, p_eff.y);
744 if (!gr->parent && 0 < gc->dash_count) {
745 glDisable(GL_LINE_STIPPLE);
753 tessCombineCB(GLdouble c[3], void *d[4], GLfloat w[4], void **out)
755 GLdouble *nv = (GLdouble *) malloc(sizeof(GLdouble) * 3);
765 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
766 struct point *p, int count)
768 if ((gr->parent && !gr->parent->overlay_enabled)
769 || (gr->parent && gr->parent->overlay_enabled
770 && !gr->overlay_enabled)) {
775 draw_array(gr, p, count, GL_LINE_STRIP);
777 graphics_priv_root->dirty = 1;
779 GLUtesselator *tess = gluNewTess(); // create a tessellator
781 return; // failed to create tessellation object, return 0
783 GLdouble quad1[count][3];
785 for (i = 0; i < count; i++) {
786 quad1[i][0] = (GLdouble) (p[i].x);
787 quad1[i][1] = (GLdouble) (p[i].y);
792 // register callback functions
793 gluTessCallback(tess, GLU_TESS_BEGIN, (void (APIENTRY *)(void)) tessBeginCB);
794 gluTessCallback(tess, GLU_TESS_END, (void (APIENTRY *)(void)) tessEndCB);
795 // gluTessCallback(tess, GLU_TESS_ERROR, (void (*)(void))tessErrorCB);
796 gluTessCallback(tess, GLU_TESS_VERTEX, (void (APIENTRY *)(void)) tessVertexCB);
797 gluTessCallback(tess, GLU_TESS_COMBINE, (void (APIENTRY *)(void)) tessCombineCB);
799 // tessellate and compile a concave quad into display list
800 // gluTessVertex() takes 3 params: tess object, pointer to vertex coords,
801 // and pointer to vertex data to be passed to vertex callback.
802 // The second param is used only to perform tessellation, and the third
803 // param is the actual vertex data to draw. It is usually same as the second
804 // param, but It can be more than vertex coord, for example, color, normal
805 // and UV coords which are needed for actual drawing.
806 // Here, we are looking at only vertex coods, so the 2nd and 3rd params are
807 // pointing same address.
808 glColor4f(gc->fr, gc->fg, gc->fb, gc->fa);
809 gluTessBeginPolygon(tess, 0); // with NULL data
810 gluTessBeginContour(tess);
811 for (i = 0; i < count; i++) {
812 gluTessVertex(tess, quad1[i], quad1[i]);
814 gluTessEndContour(tess);
815 gluTessEndPolygon(tess);
817 gluDeleteTess(tess); // delete after tessellation
822 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc,
823 struct point *p, int w, int h)
825 if ((gr->parent && !gr->parent->overlay_enabled)
826 || (gr->parent && gr->parent->overlay_enabled
827 && !gr->overlay_enabled)) {
832 draw_rectangle_es(gr, p, w, h);
835 graphics_priv_root->dirty = 1;
841 glColor4f(gc->fr, gc->fg, gc->fb, gc->fa);
843 glVertex2f(p_eff.x, p_eff.y);
844 glVertex2f(p_eff.x + w, p_eff.y);
845 glVertex2f(p_eff.x + w, p_eff.y + h);
846 glVertex2f(p_eff.x, p_eff.y + h);
852 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc,
853 struct point *p, int r)
857 if ((gr->parent && !gr->parent->overlay_enabled)
858 || (gr->parent && gr->parent->overlay_enabled
859 && !gr->overlay_enabled)) {
863 graphics_priv_root->dirty = 1;
865 /* FIXME: does not quite match gtk */
866 /* hack for osd compass.. why is this needed!? */
875 GLUquadricObj *quadratic;
876 quadratic = gluNewQuadric();
878 glTranslatef(p_eff.x, p_eff.y, 0);
879 glColor4f(gc->fr, gc->fg, gc->fb, gc->fa);
880 gluDisk(quadratic, r - (gc->linewidth / 2) - 2,
881 r + (gc->linewidth / 2), 10 + r / 5, 10 + r / 5);
883 gluDeleteQuadric(quadratic);
888 display_text_draw(struct font_freetype_text *text,
889 struct graphics_priv *gr, struct graphics_gc_priv *fg,
890 struct graphics_gc_priv *bg, int color, struct point *p)
893 struct font_freetype_glyph *g, **gp;
894 unsigned char *shadow, *glyph;
895 struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
897 { fg->fr * 65535, fg->fg * 65535, fg->fb * 65535,
899 struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
902 if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
912 } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
936 i = text->glyph_count;
941 if (g->w && g->h && bg) {
942 stride = (g->w + 2) * 4;
944 shadow = g_malloc(stride * (g->h + 2));
945 gr->freetype_methods.get_shadow(g, shadow,
951 p.x=((x + g->x) >> 6)-1;
952 p.y=((y + g->y) >> 6)-1;
953 draw_image_es(gr, &p, g->w+2, g->h+2, shadow);
956 glPixelZoom(-1.0, -1.0); //mirrored mode
958 glPixelZoom(1.0, -1.0);
960 glRasterPos2d((x + g->x) >> 6,
962 glDrawPixels(g->w + 2, g->h + 2, PIXEL_FORMAT,
963 GL_UNSIGNED_BYTE, shadow);
975 i = text->glyph_count;
983 g_malloc(stride * g->h * 4);
984 gr->freetype_methods.get_glyph(g,
996 draw_image_es(gr, &p, g->w, g->h, glyph);
999 glPixelZoom(-1.0, -1.0); //mirrored mode
1001 glPixelZoom(1.0, -1.0);
1003 glRasterPos2d((x + g->x) >> 6,
1005 glDrawPixels(g->w, g->h, PIXEL_FORMAT,
1012 glyph = g_malloc(stride * g->h);
1013 gr->freetype_methods.get_glyph(g, glyph,
1020 p.x=(x + g->x) >> 6;
1021 p.y=(y + g->y) >> 6;
1022 draw_image_es(gr, &p, g->w, g->h, glyph);
1024 #ifdef MIRRORED_VIEW
1025 glPixelZoom(-1.0, -1.0); //mirrored mode
1027 glPixelZoom(1.0, -1.0);
1029 glRasterPos2d((x + g->x) >> 6,
1031 glDrawPixels(g->w, g->h, PIXEL_FORMAT,
1032 GL_UNSIGNED_BYTE, glyph);
1043 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1044 struct graphics_gc_priv *bg, struct graphics_font_priv *font,
1045 char *text, struct point *p, int dx, int dy)
1047 if ((gr->parent && !gr->parent->overlay_enabled)
1048 || (gr->parent && gr->parent->overlay_enabled
1049 && !gr->overlay_enabled)) {
1053 struct font_freetype_text *t;
1057 dbg(0, "no font, returning\n");
1061 graphics_priv_root->dirty = 1;
1063 t = gr->freetype_methods.text_new(text,
1064 (struct font_freetype_font *)
1071 display_text_draw(t, gr, fg, bg, color, &p_eff);
1072 gr->freetype_methods.text_destroy(t);
1077 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1078 struct point *p, struct graphics_image_priv *img)
1081 draw_image_es(gr, p, img->w, img->h, img->data);
1083 if ((gr->parent && !gr->parent->overlay_enabled)
1084 || (gr->parent && gr->parent->overlay_enabled
1085 && !gr->overlay_enabled)) {
1089 if (!img || !img->data) {
1093 graphics_priv_root->dirty = 1;
1096 p_eff.x = p->x + img->hot_x;
1097 p_eff.y = p->y + img->hot_y;
1100 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1102 glRasterPos2d(p_eff.x - img->hot_x, p_eff.y - img->hot_y);
1103 glDrawPixels(img->w, img->h, GL_RGBA, GL_UNSIGNED_BYTE, img->data);
1109 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1110 struct point *p, int count, char *data)
1115 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1120 draw_drag(struct graphics_priv *gr, struct point *p)
1130 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1132 gr->background_gc = gc;
1136 handle_mouse_queue()
1147 if (mouse_event_queue_begin_idx < mouse_event_queue_end_idx) {
1148 if (mouse_queue[mouse_event_queue_begin_idx].button ==
1150 && mouse_queue[mouse_event_queue_begin_idx].state ==
1154 mouse_queue[mouse_event_queue_begin_idx %
1155 mouse_event_queue_size].x;
1157 mouse_queue[mouse_event_queue_begin_idx %
1158 mouse_event_queue_size].y;
1159 graphics_priv_root->force_redraw = 1;
1160 callback_list_call_attr_3(graphics_priv_root->cbl,
1161 attr_button, (void *) 0,
1163 } else if (mouse_queue[mouse_event_queue_begin_idx].
1164 button == GLUT_LEFT_BUTTON
1165 && mouse_queue[mouse_event_queue_begin_idx].
1166 state == GLUT_DOWN) {
1169 mouse_queue[mouse_event_queue_begin_idx %
1170 mouse_event_queue_size].x;
1172 mouse_queue[mouse_event_queue_begin_idx %
1173 mouse_event_queue_size].y;
1174 graphics_priv_root->force_redraw = 1;
1175 callback_list_call_attr_3(graphics_priv_root->cbl,
1176 attr_button, (void *) 1,
1179 ++mouse_event_queue_begin_idx;
1186 /*draws root graphics and its overlays*/
1188 redraw_screen(struct graphics_priv *gr)
1192 time_t curr_time = time(0);
1193 graphics_priv_root->dirty = 0;
1195 glCallList(gr->DLid);
1196 //display overlays display list
1197 struct graphics_priv *overlay;
1198 overlay = gr->overlays;
1199 while (gr->overlay_enabled && overlay) {
1200 if (overlay->overlay_enabled) {
1203 get_overlay_pos(overlay, &p_eff);
1204 glTranslatef(p_eff.x, p_eff.y, 1);
1205 glCallList(overlay->DLid);
1208 overlay = overlay->next;
1217 #ifndef USE_OPENGLES
1218 /*filters call to redraw in overlay enabled(map) mode*/
1220 redraw_filter(struct graphics_priv *gr)
1222 if (gr->overlay_enabled && gr->dirty) {
1231 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1233 if (gr->parent) { //overlay
1236 if (mode == draw_mode_begin) {
1237 glNewList(gr->DLid, GL_COMPILE);
1240 if (mode == draw_mode_end || mode == draw_mode_end_lazy) {
1244 } else { //root graphics
1245 if (mode == draw_mode_begin) {
1248 glNewList(gr->DLid, GL_COMPILE);
1252 if (mode == draw_mode_end) {
1254 eglSwapBuffers(egldisplay, eglwindow);
1257 gr->force_redraw = 1;
1258 if (!gr->overlay_enabled || gr->force_redraw) {
1267 static struct graphics_priv *overlay_new(struct graphics_priv *gr,
1268 struct graphics_methods *meth,
1269 struct point *p, int w, int h,
1270 int alpha, int wraparound);
1273 graphics_opengl_fullscreen(struct window *w, int on)
1279 graphics_opengl_disable_suspend(struct window *w)
1283 #ifdef USE_OPENGLES2
1285 load_shader(const char *shader_source, GLenum type)
1287 GLuint shader = glCreateShader(type);
1289 glShaderSource(shader, 1, &shader_source, NULL);
1290 glCompileShader(shader);
1297 get_data(struct graphics_priv *this, char *type)
1299 /*TODO initialize gtkglext context when type=="gtk_widget" */
1300 if (!strcmp(type, "gtk_widget")) {
1302 "Currently GTK gui is not yet supported with opengl graphics driver\n");
1305 if (strcmp(type, "window") == 0) {
1308 GLuint vertexShader;
1309 GLuint fragmentShader;
1314 createEGLWindow(this->width,this->height,"Navit");
1315 resize_callback(this->width,this->height);
1317 glClearColor ( 0.4 , 0.4 , 0.4 , 1);
1319 glClear ( GL_COLOR_BUFFER_BIT );
1320 #ifdef USE_OPENGLES2
1321 this->program=glCreateProgram();
1322 vertexShader = load_shader(vertex_src, GL_VERTEX_SHADER);
1323 fragmentShader = load_shader(fragment_src, GL_FRAGMENT_SHADER);
1324 glAttachShader(this->program, vertexShader);
1325 glAttachShader(this->program, fragmentShader);
1326 glLinkProgram(this->program);
1327 glUseProgram(this->program);
1328 this->mvp_location=glGetUniformLocation(this->program, "mvp");
1329 this->position_location=glGetAttribLocation(this->program, "position");
1330 glEnableVertexAttribArray(this->position_location);
1331 this->texture_position_location=glGetAttribLocation(this->program, "texture_position");
1332 this->color_location=glGetUniformLocation(this->program, "avcolor");
1333 this->texture_location=glGetUniformLocation(this->program, "texture");
1334 this->use_texture_location=glGetUniformLocation(this->program, "use_texture");
1335 glUniform1i(this->use_texture_location, 0);
1336 glUniform1i(this->texture_location, 0);
1338 for (i = 0 ; i < 16 ; i++)
1340 matrix[0]=2.0/this->width;
1341 matrix[5]=-2.0/this->height;
1346 glUniformMatrix4fv(this->mvp_location, 1, GL_FALSE, matrix);
1348 glEnableClientState(GL_VERTEX_ARRAY);
1350 glGenTextures(1, &textures);
1351 glActiveTexture(GL_TEXTURE0);
1352 glBindTexture(GL_TEXTURE_2D, textures);
1353 #ifndef USE_OPENGLES2
1354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1359 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1362 win = g_new0(struct window, 1);
1364 win->fullscreen = graphics_opengl_fullscreen;
1365 win->disable_suspend = graphics_opengl_disable_suspend;
1379 image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
1381 //TODO free image data in hashtable when graphics is destroyed
1382 //currently graphics destroy is not called !!!
1392 overlay_disable(struct graphics_priv *gr, int disable)
1394 gr->overlay_enabled = !disable;
1395 gr->force_redraw = 1;
1396 draw_mode(gr, draw_mode_end);
1400 overlay_resize(struct graphics_priv *gr, struct point *p, int w, int h,
1401 int alpha, int wraparound)
1419 if (gr->width != w2) {
1424 if (gr->height != h2) {
1429 gr->wraparound = wraparound;
1432 if ((w == 0) || (h == 0)) {
1433 gr->overlay_autodisabled = 1;
1435 gr->overlay_autodisabled = 0;
1438 callback_list_call_attr_2(gr->cbl, attr_resize,
1439 GINT_TO_POINTER(gr->width),
1440 GINT_TO_POINTER(gr->height));
1444 static struct graphics_methods graphics_methods = {
1472 static struct graphics_priv *
1473 graphics_opengl_new_helper(struct graphics_methods *meth)
1475 struct font_priv *(*font_freetype_new) (void *meth);
1476 font_freetype_new = plugin_get_font_type("freetype");
1478 if (!font_freetype_new) {
1482 struct graphics_priv *this = g_new0(struct graphics_priv, 1);
1484 font_freetype_new(&this->freetype_methods);
1485 *meth = graphics_methods;
1488 (struct graphics_font_priv *
1489 (*)(struct graphics_priv *, struct graphics_font_methods *,
1490 char *, int, int)) this->freetype_methods.font_new;
1491 meth->get_text_bbox = this->freetype_methods.get_text_bbox;
1496 static struct graphics_priv *
1497 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth,
1498 struct point *p, int w, int h, int alpha, int wraparound)
1501 struct graphics_priv *this = graphics_opengl_new_helper(meth);
1507 /* If either height or width is 0, we set it to 1 to avoid warnings, and
1508 * disable the overlay. */
1521 if ((w == 0) || (h == 0)) {
1522 this->overlay_autodisabled = 1;
1524 this->overlay_autodisabled = 0;
1526 this->overlay_enabled = 1;
1527 this->overlay_autodisabled = 0;
1529 this->next = gr->overlays;
1530 gr->overlays = this;
1533 this->DLid = glGenLists(1);
1540 click_notify(int button, int state, int x, int y)
1542 mouse_queue[mouse_event_queue_end_idx %
1543 mouse_event_queue_size].button = button;
1544 mouse_queue[mouse_event_queue_end_idx %
1545 mouse_event_queue_size].state = state;
1546 #ifdef MIRRORED_VIEW
1547 mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].x =
1548 graphics_priv_root->width - x;
1550 mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].x =
1553 mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].y =
1555 ++mouse_event_queue_end_idx;
1559 motion_notify(int x, int y)
1562 #ifdef MIRRORED_VIEW
1563 p.x = graphics_priv_root->width - x;
1568 callback_list_call_attr_1(graphics_priv_root->cbl, attr_motion,
1573 #ifndef USE_OPENGLES
1575 graphics_opengl_idle(void *data)
1577 static int opengl_init_ok = 0;
1578 if (!opengl_init_ok) {
1579 callback_list_call_attr_2(graphics_priv_root->cbl,
1582 (graphics_priv_root->width),
1584 (graphics_priv_root->height));
1589 glutMainLoopEvent();
1591 handle_mouse_queue();
1598 ProcessNormalKeys(unsigned char key_in, int x, int y)
1605 key = NAVIT_KEY_RETURN;
1613 graphics_priv_root->force_redraw = 1;
1614 callback_list_call_attr_1(graphics_priv_root->cbl, attr_keypress,
1619 ProcessSpecialKeys(int key_in, int x, int y)
1626 key = NAVIT_KEY_RIGHT;
1629 key = NAVIT_KEY_LEFT;
1632 key = NAVIT_KEY_DOWN;
1638 key = NAVIT_KEY_ZOOM_OUT;
1641 key = NAVIT_KEY_ZOOM_IN;
1647 graphics_priv_root->force_redraw = 1;
1650 callback_list_call_attr_1(graphics_priv_root->cbl, attr_keypress,
1655 resize_callback(int w, int h)
1657 glViewport(0, 0, w, h);
1658 #ifndef USE_OPENGLES2
1659 glMatrixMode(GL_PROJECTION);
1661 #ifdef MIRRORED_VIEW
1662 glOrthof(glF(w), glF(0), glF(h), glF(0), glF(1), glF(-1));
1664 glOrthof(glF(0), glF(w), glF(h), glF(0), glF(1), glF(-1));
1667 graphics_priv_root->width = w;
1668 graphics_priv_root->height = h;
1670 callback_list_call_attr_2(graphics_priv_root->cbl, attr_resize,
1671 GINT_TO_POINTER(w), GINT_TO_POINTER(h));
1677 graphics_priv_root->force_redraw = 1;
1678 redraw_screen(graphics_priv_root);
1679 resize_callback(graphics_priv_root->width,
1680 graphics_priv_root->height);
1686 callback_list_call_attr_0(graphics_priv_root->cbl,
1687 attr_window_closed);
1691 static struct graphics_priv *
1692 graphics_opengl_new(struct navit *nav, struct graphics_methods *meth,
1693 struct attr **attrs, struct callback_list *cbl)
1697 if (!event_request_system("glib", "graphics_opengl_new"))
1700 struct graphics_priv *this = graphics_opengl_new_helper(meth);
1701 graphics_priv_root = this;
1704 this->parent = NULL;
1705 this->overlay_enabled = 1;
1707 this->width = SCREEN_WIDTH;
1708 if ((attr = attr_search(attrs, NULL, attr_w)))
1709 this->width = attr->u.num;
1710 this->height = SCREEN_HEIGHT;
1711 if ((attr = attr_search(attrs, NULL, attr_h)))
1712 this->height = attr->u.num;
1713 this->timeout = 100;
1714 if ((attr = attr_search(attrs, NULL, attr_timeout)))
1715 this->timeout = attr->u.num;
1717 if ((attr = attr_search(attrs, NULL, attr_delay)))
1718 this->delay = attr->u.num;
1723 #ifndef USE_OPENGLES
1724 glutInit(&argc, &cmdline);
1725 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
1727 glutInitWindowSize(this->width, this->height);
1728 glutInitWindowPosition(0, 0);
1729 glutCreateWindow("Navit opengl window");
1731 glutDisplayFunc(display);
1732 glutReshapeFunc(resize_callback);
1733 resize_callback(this->width, this->height);
1736 graphics_priv_root->cbl = cbl;
1737 graphics_priv_root->width = this->width;
1738 graphics_priv_root->height = this->height;
1740 #ifndef USE_OPENGLES
1741 glutMotionFunc(motion_notify);
1742 glutPassiveMotionFunc(motion_notify);
1743 glutMouseFunc(click_notify);
1744 glutKeyboardFunc(ProcessNormalKeys);
1745 glutSpecialFunc(ProcessSpecialKeys);
1747 glutCloseFunc(glut_close);
1749 this->DLid = glGenLists(1);
1751 g_timeout_add(G_PRIORITY_DEFAULT + 10, graphics_opengl_idle, NULL);
1753 /*this will only refresh screen in map(overlay enabled) mode */
1754 g_timeout_add(G_PRIORITY_DEFAULT + 1000, redraw_filter, this);
1757 //create hash table for uncompressed image data
1758 hImageData = g_hash_table_new(g_str_hash, g_str_equal);
1764 event_opengl_main_loop_run(void)
1770 event_opengl_main_loop_quit(void)
1775 static struct event_watch *
1776 event_opengl_add_watch(void *h, enum event_watch_cond cond,
1777 struct callback *cb)
1784 event_opengl_remove_watch(struct event_watch *ev)
1790 static struct event_timeout *
1791 event_opengl_add_timeout(int timeout, int multi, struct callback *cb)
1798 event_opengl_remove_timeout(struct event_timeout *to)
1804 static struct event_idle *
1805 event_opengl_add_idle(int priority, struct callback *cb)
1812 event_opengl_remove_idle(struct event_idle *ev)
1818 event_opengl_call_callback(struct callback_list *cb)
1823 static struct event_methods event_opengl_methods = {
1824 event_opengl_main_loop_run,
1825 event_opengl_main_loop_quit,
1826 event_opengl_add_watch,
1827 event_opengl_remove_watch,
1828 event_opengl_add_timeout,
1829 event_opengl_remove_timeout,
1830 event_opengl_add_idle,
1831 event_opengl_remove_idle,
1832 event_opengl_call_callback,
1835 static struct event_priv *
1836 event_opengl_new(struct event_methods *meth)
1838 *meth = event_opengl_methods;
1845 plugin_register_graphics_type("opengl", graphics_opengl_new);
1846 plugin_register_event_type("opengl", event_opengl_new);