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"
43 #include "graphics_opengl.h"
45 #if defined(WINDOWS) || defined(WIN32)
46 #define PIXEL_FORMAT GL_RGBA
48 # define sleep(i) Sleep(i * 1000)
50 #define PIXEL_FORMAT GL_BGRA
54 #include <FreeImage.h>
59 #include <GLES2/gl2.h>
67 #ifdef USE_GLUT_FOR_OPENGLES
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;
77 #define glOrthof glOrtho
81 #include <GLUT/glut.h>
83 #include <GL/glut.h> /* glut.h includes gl.h and glu.h */
93 #define glF(x) ((GLfixed)((x)*(1<<16)))
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
108 #define SCREEN_WIDTH 700
109 #define SCREEN_HEIGHT 700
111 //#define MIRRORED_VIEW 1
113 struct graphics_gc_priv {
114 struct graphics_priv *gr;
115 float fr, fg, fb, fa;
116 float br, bg, bb, ba;
118 unsigned char *dash_list;
123 struct graphics_priv {
131 int overlay_autodisabled;
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,
144 void *button_callback_data;
147 GLint mvp_location, position_location, color_location, texture_position_location, use_texture_location, texture_location;
151 struct callback_list *cbl;
152 struct font_freetype_methods freetype_methods;
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;
166 static struct graphics_priv *graphics_priv_root;
167 struct graphics_image_priv {
174 } graphics_image_priv;
176 struct mouse_event_queue_element {
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];
188 //hastable for uncompressed image data
189 static GHashTable *hImageData;
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);
203 static struct graphics_priv *graphics_opengl_new_helper(struct
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();
214 const char vertex_src [] =
216 attribute vec2 position; \
217 attribute vec2 texture_position; \
219 varying vec2 v_texture_position; \
223 v_texture_position=texture_position; \
224 gl_Position = mvp*vec4(position, 0.0, 1.0); \
228 const char fragment_src [] =
230 uniform lowp vec4 avcolor; \
231 uniform sampler2D texture; \
232 uniform bool use_texture; \
233 varying vec2 v_texture_position; \
237 gl_FragColor = texture2D(texture, v_texture_position); \
239 gl_FragColor = avcolor; \
246 graphics_destroy(struct graphics_priv *gr)
248 /*FIXME graphics_destroy is never called */
249 /*TODO add destroy code for image cache(delete entries in hImageData) */
255 gc_destroy(struct graphics_gc_priv *gc)
262 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
268 gc_set_dashes(struct graphics_gc_priv *gc, int width, int offset,
269 unsigned char *dash_list, int n)
272 const int cOpenglMaskBits = 16;
276 for (i = 0; i < cOpenglMaskBits; ++i) {
278 gc->dash_mask |= (i / n) % 2;
281 unsigned char *curr = dash_list;
282 int cnt = 0; //dot counter
283 int dcnt = 0; //dash element counter
287 for (i = 0; i < n; ++i) {
288 sum_dash += dash_list[i];
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) {
300 } else if (0 < num_error[i % 2]
301 && 2 < dash_list[i]) {
308 for (i = 0; i < cOpenglMaskBits; ++i) {
310 gc->dash_mask |= 1 - dcnt % 2;
326 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
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;
335 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
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;
343 static struct graphics_gc_methods gc_methods = {
351 static struct graphics_gc_priv *
352 gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
354 struct graphics_gc_priv *gc = g_new0(struct graphics_gc_priv, 1);
362 static struct graphics_image_priv image_error;
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)
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
380 } else if (curr_elem) {
381 //found and OK -> use hastable entry
384 hot->x = curr_elem->w / 2 - 1;
385 hot->y = curr_elem->h / 2 - 1;
388 if (strlen(path) < 4) {
389 g_hash_table_insert(hImageData, g_strdup(path),
393 char *ext_str = path + strlen(path) - 3;
394 if (strstr(ext_str, "png") || strstr(path, "PNG")) {
396 FreeImage_Load(FIF_PNG, path, 0)) == NULL) {
397 g_hash_table_insert(hImageData,
402 } else if (strstr(ext_str, "xpm") || strstr(path, "XPM")) {
404 FreeImage_Load(FIF_XPM, path, 0)) == NULL) {
405 g_hash_table_insert(hImageData,
410 } else if (strstr(ext_str, "svg") || strstr(path, "SVG")) {
412 snprintf(path_new, strlen(path) - 3, "%s", path);
413 strcat(path_new, "_48_48.png");
416 FreeImage_Load(FIF_PNG, path_new,
418 g_hash_table_insert(hImageData,
424 g_hash_table_insert(hImageData, g_strdup(path),
429 if (FreeImage_GetBPP(image) == 64) {
431 image2 = FreeImage_ConvertTo32Bits(image);
432 FreeImage_Unload(image);
435 #if FREEIMAGE_MAJOR_VERSION*100+FREEIMAGE_MINOR_VERSION >= 313
438 image2 = FreeImage_Rotate(image, rotation, NULL);
443 gi = g_new0(struct graphics_image_priv, 1);
445 width = FreeImage_GetWidth(image);
446 height = FreeImage_GetHeight(image);
448 if ((*w != width || *h != height) && 0 < *w && 0 < *h) {
450 image2 = FreeImage_Rescale(image, *w, *h, NULL);
451 FreeImage_Unload(image);
457 data = (unsigned char *) malloc(width * height * 4);
459 RGBQUAD *palette = NULL;
460 if (FreeImage_GetBPP(image) == 8) {
461 palette = FreeImage_GetPalette(image);
464 for (i = 0; i < height; i++) {
465 for (j = 0; j < width; j++) {
467 if (FreeImage_GetBPP(image) == 8) {
468 FreeImage_GetPixelIndex(image, j,
472 data[4 * width * i + 4 * j + 0] =
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] =
480 } else if (FreeImage_GetBPP(image) == 16
481 || FreeImage_GetBPP(image) == 24
482 || FreeImage_GetBPP(image) ==
484 FreeImage_GetPixelColor(image, j,
490 && aPixel.rgbBlue == 0
491 && aPixel.rgbGreen == 0);
492 data[4 * width * i + 4 * j + 0] =
493 transparent ? 0 : (aPixel.
495 data[4 * width * i + 4 * j + 1] =
497 data[4 * width * i + 4 * j + 2] =
498 transparent ? 0 : (aPixel.
500 data[4 * width * i + 4 * j + 3] =
501 transparent ? 0 : 255;
507 FreeImage_Unload(image);
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;
520 g_hash_table_insert(hImageData, g_strdup(path), gi);
524 dbg(0,"FreeImage not available - cannot load any images.\n", path);
531 set_color(struct graphics_priv *gr, struct graphics_gc_priv *gc)
539 glUniform4fv(gr->color_location, 1, col);
541 glColor4f(glF(gc->fr), glF(gc->fg), glF(gc->fb), glF(gc->fa));
546 draw_array(struct graphics_priv *gr, struct point *p, int count, GLenum mode)
555 for (i = 0 ; i < count ; i++) {
558 x[i*2+1]=glF(p[i].y);
560 glVertex2f(p[i].x, p[i].y);
565 glVertexAttribPointer (gr->position_location, 2, GL_FLOAT, 0, 0, x );
567 glVertexPointer(2, GL_F, 0, x);
569 glDrawArrays(mode, 0, count);
576 draw_rectangle_do(struct graphics_priv *gr, struct point *p, int w, int h)
579 pa[0]=pa[1]=pa[2]=pa[3]=*p;
584 draw_array(gr, pa, 4, GL_TRIANGLE_STRIP);
589 static int next_power2(int x)
598 draw_image_es(struct graphics_priv *gr, struct point *p, int w, int h, unsigned char *data)
602 memset(x, 0, sizeof(x));
603 #if REQUIRES_POWER_OF_2
604 int w2=next_power2(w);
605 int h2=next_power2(h);
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);
616 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
618 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
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 );
629 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
630 glEnable(GL_TEXTURE_2D);
631 glTexCoordPointer(2, GL_F, 0, x);
634 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
635 draw_rectangle_do(gr, p, w, h);
637 glUniform1i(gr->use_texture_location, 0);
638 glDisableVertexAttribArray(gr->texture_position_location);
640 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
641 glDisable(GL_TEXTURE_2D);
650 get_overlay_pos(struct graphics_priv *gr, struct point *point_out)
652 if (gr->parent == NULL) {
657 point_out->x = gr->p.x;
658 if (point_out->x < 0) {
659 point_out->x += gr->parent->width;
662 point_out->y = gr->p.y;
663 if (point_out->y < 0) {
664 point_out->y += gr->parent->height;
669 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc,
670 struct point *p, int count)
672 if ((gr->parent && !gr->parent->overlay_enabled)
673 || (gr->parent && gr->parent->overlay_enabled
674 && !gr->overlay_enabled)) {
677 #if !defined(USE_OPENGLES) || defined(USE_OPENGLES2)
678 glLineWidth(gc->linewidth);
681 graphics_priv_root->dirty = 1;
684 if (!gr->parent && 0 < gc->dash_count) {
685 glLineStipple(1, gc->dash_mask);
686 glEnable(GL_LINE_STIPPLE);
689 draw_array(gr, p, count, GL_LINE_STRIP);
691 if (!gr->parent && 0 < gc->dash_count) {
692 glDisable(GL_LINE_STIPPLE);
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;
703 getPrimitiveType(GLenum type)
715 ret = "GL_LINE_LOOP";
718 ret = "GL_LINE_STRIP";
721 ret = "GL_TRIANGLES";
724 ret = "GL_TRIANGLE_STRIP";
727 ret = "GL_TRIANGLE_FAN";
733 ret = "GL_QUAD_STRIP";
743 tessBeginCB(GLenum which)
745 dbg(1, "glBegin( %s );\n", getPrimitiveType(which));
755 dbg(1, "glEnd();\n");
756 draw_array(graphics_priv_root, tess_array, tess_count, tess_type);
762 tessVertexCB(const GLvoid * data)
764 // cast back to double type
765 const GLdouble *ptr = (const GLdouble *) data;
766 dbg(1, " glVertex3d();\n");
768 tess_array[tess_count].x=ptr[0];
769 tess_array[tess_count].y=ptr[1];
770 if (tess_count < 511)
777 tessCombineCB(GLdouble c[3], void *d[4], GLfloat w[4], void **out)
779 GLdouble *nv = (GLdouble *) malloc(sizeof(GLdouble) * 3);
790 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
791 struct point *p, int count)
793 if ((gr->parent && !gr->parent->overlay_enabled)
794 || (gr->parent && gr->parent->overlay_enabled
795 && !gr->overlay_enabled)) {
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);
804 GLUtesselator *tess = gluNewTess(); // create a tessellator
806 return; // failed to create tessellation object, return 0
808 GLdouble quad1[count][3];
810 for (i = 0; i < count; i++) {
811 quad1[i][0] = (GLdouble) (p[i].x);
812 quad1[i][1] = (GLdouble) (p[i].y);
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);
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]);
838 gluTessEndContour(tess);
839 gluTessEndPolygon(tess);
841 gluDeleteTess(tess); // delete after tessellation
846 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc,
847 struct point *p, int w, int h)
849 if ((gr->parent && !gr->parent->overlay_enabled)
850 || (gr->parent && gr->parent->overlay_enabled
851 && !gr->overlay_enabled)) {
855 draw_rectangle_do(gr, p, w, h);
856 graphics_priv_root->dirty = 1;
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)
865 struct font_freetype_glyph *g, **gp;
866 unsigned char *shadow, *glyph;
867 struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
869 { fg->fr * 65535, fg->fg * 65535, fg->fb * 65535,
871 struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
874 if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
884 } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
908 i = text->glyph_count;
913 if (g->w && g->h && bg) {
914 stride = (g->w + 2) * 4;
916 shadow = g_malloc(stride * (g->h + 2));
917 gr->freetype_methods.get_shadow(g, shadow,
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);
928 glPixelZoom(-1.0, -1.0); //mirrored mode
930 glPixelZoom(1.0, -1.0);
932 glRasterPos2d((x + g->x) >> 6,
934 glDrawPixels(g->w + 2, g->h + 2, PIXEL_FORMAT,
935 GL_UNSIGNED_BYTE, shadow);
947 i = text->glyph_count;
955 g_malloc(stride * g->h * 4);
956 gr->freetype_methods.get_glyph(g,
968 draw_image_es(gr, &p, g->w, g->h, glyph);
971 glPixelZoom(-1.0, -1.0); //mirrored mode
973 glPixelZoom(1.0, -1.0);
975 glRasterPos2d((x + g->x) >> 6,
977 glDrawPixels(g->w, g->h, PIXEL_FORMAT,
984 glyph = g_malloc(stride * g->h);
985 gr->freetype_methods.get_glyph(g, glyph,
994 draw_image_es(gr, &p, g->w, g->h, glyph);
997 glPixelZoom(-1.0, -1.0); //mirrored mode
999 glPixelZoom(1.0, -1.0);
1001 glRasterPos2d((x + g->x) >> 6,
1003 glDrawPixels(g->w, g->h, PIXEL_FORMAT,
1004 GL_UNSIGNED_BYTE, glyph);
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)
1019 if ((gr->parent && !gr->parent->overlay_enabled)
1020 || (gr->parent && gr->parent->overlay_enabled
1021 && !gr->overlay_enabled)) {
1025 struct font_freetype_text *t;
1029 dbg(0, "no font, returning\n");
1033 graphics_priv_root->dirty = 1;
1035 t = gr->freetype_methods.text_new(text,
1036 (struct font_freetype_font *)
1043 display_text_draw(t, gr, fg, bg, color, &p_eff);
1044 gr->freetype_methods.text_destroy(t);
1049 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1050 struct point *p, struct graphics_image_priv *img)
1053 draw_image_es(gr, p, img->w, img->h, img->data);
1055 if ((gr->parent && !gr->parent->overlay_enabled)
1056 || (gr->parent && gr->parent->overlay_enabled
1057 && !gr->overlay_enabled)) {
1061 if (!img || !img->data) {
1065 graphics_priv_root->dirty = 1;
1068 p_eff.x = p->x + img->hot_x;
1069 p_eff.y = p->y + img->hot_y;
1072 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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);
1081 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1082 struct point *p, int count, char *data)
1087 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1092 draw_drag(struct graphics_priv *gr, struct point *p)
1102 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1104 gr->background_gc = gc;
1108 handle_mouse_queue()
1119 if (mouse_event_queue_begin_idx < mouse_event_queue_end_idx) {
1120 if (mouse_queue[mouse_event_queue_begin_idx].button ==
1122 && mouse_queue[mouse_event_queue_begin_idx].state ==
1126 mouse_queue[mouse_event_queue_begin_idx %
1127 mouse_event_queue_size].x;
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,
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) {
1141 mouse_queue[mouse_event_queue_begin_idx %
1142 mouse_event_queue_size].x;
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,
1151 ++mouse_event_queue_begin_idx;
1158 /*draws root graphics and its overlays*/
1160 redraw_screen(struct graphics_priv *gr)
1164 time_t curr_time = time(0);
1165 graphics_priv_root->dirty = 0;
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) {
1175 get_overlay_pos(overlay, &p_eff);
1176 glTranslatef(p_eff.x, p_eff.y, 1);
1177 glCallList(overlay->DLid);
1180 overlay = overlay->next;
1189 #ifndef USE_OPENGLES
1190 /*filters call to redraw in overlay enabled(map) mode*/
1192 redraw_filter(struct graphics_priv *gr)
1194 if (gr->overlay_enabled && gr->dirty) {
1203 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1205 if (gr->parent) { //overlay
1208 if (mode == draw_mode_begin) {
1209 glNewList(gr->DLid, GL_COMPILE);
1212 if (mode == draw_mode_end || mode == draw_mode_end_lazy) {
1216 } else { //root graphics
1217 if (mode == draw_mode_begin) {
1220 glNewList(gr->DLid, GL_COMPILE);
1224 if (mode == draw_mode_end) {
1226 gr->platform_methods->swap_buffers(gr->platform);
1229 gr->force_redraw = 1;
1230 if (!gr->overlay_enabled || gr->force_redraw) {
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);
1245 graphics_opengl_fullscreen(struct window *w, int on)
1251 graphics_opengl_disable_suspend(struct window *w)
1255 #ifdef USE_OPENGLES2
1257 load_shader(const char *shader_source, GLenum type)
1259 GLuint shader = glCreateShader(type);
1261 glShaderSource(shader, 1, &shader_source, NULL);
1262 glCompileShader(shader);
1269 get_data(struct graphics_priv *this, char *type)
1271 /*TODO initialize gtkglext context when type=="gtk_widget" */
1272 if (!strcmp(type, "gtk_widget")) {
1274 "Currently GTK gui is not yet supported with opengl graphics driver\n");
1277 if (strcmp(type, "window") == 0) {
1280 GLuint vertexShader;
1281 GLuint fragmentShader;
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);
1293 glClearColor ( 0.4 , 0.4 , 0.4 , 1);
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);
1314 for (i = 0 ; i < 16 ; i++)
1316 matrix[0]=2.0/this->width;
1317 matrix[5]=-2.0/this->height;
1322 glUniformMatrix4fv(this->mvp_location, 1, GL_FALSE, matrix);
1324 glEnableClientState(GL_VERTEX_ARRAY);
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);
1337 win = g_new0(struct window, 1);
1339 win->fullscreen = graphics_opengl_fullscreen;
1340 win->disable_suspend = graphics_opengl_disable_suspend;
1354 image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
1356 //TODO free image data in hashtable when graphics is destroyed
1357 //currently graphics destroy is not called !!!
1367 overlay_disable(struct graphics_priv *gr, int disable)
1369 gr->overlay_enabled = !disable;
1370 gr->force_redraw = 1;
1371 draw_mode(gr, draw_mode_end);
1375 overlay_resize(struct graphics_priv *gr, struct point *p, int w, int h,
1376 int alpha, int wraparound)
1394 if (gr->width != w2) {
1399 if (gr->height != h2) {
1404 gr->wraparound = wraparound;
1407 if ((w == 0) || (h == 0)) {
1408 gr->overlay_autodisabled = 1;
1410 gr->overlay_autodisabled = 0;
1413 callback_list_call_attr_2(gr->cbl, attr_resize,
1414 GINT_TO_POINTER(gr->width),
1415 GINT_TO_POINTER(gr->height));
1419 static struct graphics_methods graphics_methods = {
1443 static struct graphics_priv *
1444 graphics_opengl_new_helper(struct graphics_methods *meth)
1446 struct font_priv *(*font_freetype_new) (void *meth);
1447 font_freetype_new = plugin_get_font_type("freetype");
1449 if (!font_freetype_new) {
1453 struct graphics_priv *this = g_new0(struct graphics_priv, 1);
1455 font_freetype_new(&this->freetype_methods);
1456 *meth = graphics_methods;
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;
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)
1472 struct graphics_priv *this = graphics_opengl_new_helper(meth);
1478 /* If either height or width is 0, we set it to 1 to avoid warnings, and
1479 * disable the overlay. */
1492 if ((w == 0) || (h == 0)) {
1493 this->overlay_autodisabled = 1;
1495 this->overlay_autodisabled = 0;
1497 this->overlay_enabled = 1;
1498 this->overlay_autodisabled = 0;
1500 this->next = gr->overlays;
1501 gr->overlays = this;
1504 this->DLid = glGenLists(1);
1511 click_notify_do(struct graphics_priv *priv, int button, int state, int x, int y)
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);
1519 click_notify(int button, int state, int x, int y)
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;
1529 mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].x =
1532 mouse_queue[mouse_event_queue_end_idx % mouse_event_queue_size].y =
1534 ++mouse_event_queue_end_idx;
1538 motion_notify_do(struct graphics_priv *priv, int x, int y)
1541 #ifdef MIRRORED_VIEW
1542 p.x = priv->width - x;
1547 callback_list_call_attr_1(priv->cbl, attr_motion,
1553 motion_notify(int x, int y)
1555 motion_notify_do(graphics_priv_root, x, y);
1558 #ifndef USE_OPENGLES
1560 graphics_opengl_idle(void *data)
1562 static int opengl_init_ok = 0;
1563 if (!opengl_init_ok) {
1564 callback_list_call_attr_2(graphics_priv_root->cbl,
1567 (graphics_priv_root->width),
1569 (graphics_priv_root->height));
1574 glutMainLoopEvent();
1576 handle_mouse_queue();
1583 ProcessNormalKeys(unsigned char key_in, int x, int y)
1590 key = NAVIT_KEY_RETURN;
1598 graphics_priv_root->force_redraw = 1;
1599 callback_list_call_attr_1(graphics_priv_root->cbl, attr_keypress,
1604 ProcessSpecialKeys(int key_in, int x, int y)
1611 key = NAVIT_KEY_RIGHT;
1614 key = NAVIT_KEY_LEFT;
1617 key = NAVIT_KEY_DOWN;
1623 key = NAVIT_KEY_ZOOM_OUT;
1626 key = NAVIT_KEY_ZOOM_IN;
1632 graphics_priv_root->force_redraw = 1;
1635 callback_list_call_attr_1(graphics_priv_root->cbl, attr_keypress,
1640 resize_callback_do(struct graphics_priv *priv, int w, int h)
1642 glViewport(0, 0, w, h);
1643 #ifndef USE_OPENGLES2
1644 glMatrixMode(GL_PROJECTION);
1646 #ifdef MIRRORED_VIEW
1647 glOrthof(glF(w), glF(0), glF(h), glF(0), glF(1), glF(-1));
1649 glOrthof(glF(0), glF(w), glF(h), glF(0), glF(1), glF(-1));
1655 callback_list_call_attr_2(priv->cbl, attr_resize,
1656 GINT_TO_POINTER(w), GINT_TO_POINTER(h));
1660 resize_callback(int w, int h)
1662 resize_callback_do(graphics_priv_root, w, h);
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);
1677 callback_list_call_attr_0(graphics_priv_root->cbl,
1678 attr_window_closed);
1682 static struct graphics_priv *
1683 graphics_opengl_new(struct navit *nav, struct graphics_methods *meth,
1684 struct attr **attrs, struct callback_list *cbl)
1688 if (!event_request_system("glib", "graphics_opengl_new"))
1691 struct graphics_priv *this = graphics_opengl_new_helper(meth);
1692 graphics_priv_root = this;
1695 this->parent = NULL;
1696 this->overlay_enabled = 1;
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;
1708 if ((attr = attr_search(attrs, NULL, attr_delay)))
1709 this->delay = attr->u.num;
1714 #ifndef USE_OPENGLES
1715 glutInit(&argc, &cmdline);
1716 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
1718 glutInitWindowSize(this->width, this->height);
1719 glutInitWindowPosition(0, 0);
1720 glutCreateWindow("Navit opengl window");
1722 glutDisplayFunc(display);
1723 glutReshapeFunc(resize_callback);
1724 resize_callback(this->width, this->height);
1727 graphics_priv_root->cbl = cbl;
1728 graphics_priv_root->width = this->width;
1729 graphics_priv_root->height = this->height;
1731 #ifndef USE_OPENGLES
1732 glutMotionFunc(motion_notify);
1733 glutPassiveMotionFunc(motion_notify);
1734 glutMouseFunc(click_notify);
1735 glutKeyboardFunc(ProcessNormalKeys);
1736 glutSpecialFunc(ProcessSpecialKeys);
1738 glutCloseFunc(glut_close);
1740 this->DLid = glGenLists(1);
1742 g_timeout_add(G_PRIORITY_DEFAULT + 10, graphics_opengl_idle, NULL);
1744 /*this will only refresh screen in map(overlay enabled) mode */
1745 g_timeout_add(G_PRIORITY_DEFAULT + 1000, redraw_filter, this);
1748 //create hash table for uncompressed image data
1749 hImageData = g_hash_table_new(g_str_hash, g_str_equal);
1755 event_opengl_main_loop_run(void)
1761 event_opengl_main_loop_quit(void)
1766 static struct event_watch *
1767 event_opengl_add_watch(void *h, enum event_watch_cond cond,
1768 struct callback *cb)
1775 event_opengl_remove_watch(struct event_watch *ev)
1781 static struct event_timeout *
1782 event_opengl_add_timeout(int timeout, int multi, struct callback *cb)
1789 event_opengl_remove_timeout(struct event_timeout *to)
1795 static struct event_idle *
1796 event_opengl_add_idle(int priority, struct callback *cb)
1803 event_opengl_remove_idle(struct event_idle *ev)
1809 event_opengl_call_callback(struct callback_list *cb)
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,
1826 static struct event_priv *
1827 event_opengl_new(struct event_methods *meth)
1829 *meth = event_opengl_methods;
1836 plugin_register_graphics_type("opengl", graphics_opengl_new);
1837 plugin_register_event_type("opengl", event_opengl_new);