1 /* graphics_sdl.c -- barebones sdl graphics layer
3 copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org>
9 - proper image transparency (libsdl-image xpm does not work)
14 2008-06-15 SDL_DOUBLEBUF+SDL_Flip for linux fb. fix FT leaks.
15 2008-06-18 defer initial resize_callback
16 2008-06-21 linux touchscreen
17 2008-07-04 custom rastering
33 #include "navit/font/freetype/font_freetype.h"
45 #undef LINUX_TOUCHSCREEN
54 #define OVERLAY_MAX 16
65 #include <SDL/SDL_gfxPrimitives.h>
69 #include <SDL/SDL_ttf.h>
71 #include <fontconfig/fontconfig.h>
73 #include FT_FREETYPE_H
74 #include <freetype/ftglyph.h>
79 #include <SDL/SDL_image.h>
82 #ifdef LINUX_TOUCHSCREEN
83 /* we use Linux evdev directly for the touchscreen. */
84 #include <sys/types.h>
87 #include <linux/input.h>
98 /* TODO: union overlay + non-overlay to reduce size */
100 struct graphics_priv {
104 uint32_t video_flags;
111 struct graphics_priv *overlay_parent;
116 struct graphics_priv *overlay_array[OVERLAY_MAX];
118 enum draw_mode_num draw_mode;
120 int resize_callback_initial;
123 struct callback_list *cbl;
125 #ifdef LINUX_TOUCHSCREEN
137 struct timeval draw_begin_tv;
138 unsigned long draw_time_peak;
140 struct font_freetype_methods freetype_methods;
147 struct graphics_font_priv {
155 struct graphics_gc_priv {
156 struct graphics_priv *gr;
168 struct graphics_image_priv {
173 #ifdef LINUX_TOUCHSCREEN
174 static int input_ts_exit(struct graphics_priv *gr);
178 graphics_destroy(struct graphics_priv *gr)
180 dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode);
184 SDL_FreeSurface(gr->screen);
185 gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL;
192 FT_Done_FreeType(gr->library);
195 #ifdef LINUX_TOUCHSCREEN
205 static char *fontfamilies[]={
215 static void font_destroy(struct graphics_font_priv *gf)
219 FT_Done_Face(gf->face);
224 static struct graphics_font_methods font_methods = {
231 gc_destroy(struct graphics_gc_priv *gc)
237 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
240 printf("gc_set_linewidth %p %d\n", gc, w);
246 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
252 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
255 printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
257 gc->fore_r = c->r/256;
258 gc->fore_g = c->g/256;
259 gc->fore_b = c->b/256;
260 gc->fore_a = c->a/256;
264 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
267 printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
269 gc->back_r = c->r/256;
270 gc->back_g = c->g/256;
271 gc->back_b = c->b/256;
272 gc->back_a = c->a/256;
275 static struct graphics_gc_methods gc_methods = {
283 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
285 struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1);
288 gc->linewidth=1; /* upper layer should override anyway? */
293 #if 0 /* unused by core? */
294 static void image_destroy(struct graphics_image_priv *gi)
297 SDL_FreeSurface(gi->img);
302 static struct graphics_image_methods gi_methods =
308 static struct graphics_image_priv *
309 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
310 struct point *hot, int rotation)
313 struct graphics_image_priv *gi;
315 /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
317 gi = g_new0(struct graphics_image_priv, 1);
318 gi->img = IMG_Load(name);
321 /* TBD: improves blit performance? */
322 #if !SDL_VERSION_ATLEAST(1,3,0)
323 SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey);
332 /* TODO: debug "colour parse errors" on xpm */
333 printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError());
345 image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
348 SDL_FreeSurface(gi->img);
354 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate)
359 FT_GlyphSlot slot = font->face->glyph; // a small shortcut
371 bbox.xMin = bbox.yMin = 32000;
372 bbox.xMax = bbox.yMax = -32000;
373 FT_Set_Transform( font->face, &matrix, &pen );
374 len=g_utf8_strlen(text, -1);
375 for ( n = 0; n < len; n++ ) {
377 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
378 p=g_utf8_next_char(p);
379 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT );
380 FT_Get_Glyph(font->face->glyph, &glyph);
381 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox );
382 FT_Done_Glyph(glyph);
383 glyph_bbox.xMin += x >> 6;
384 glyph_bbox.xMax += x >> 6;
385 glyph_bbox.yMin += y >> 6;
386 glyph_bbox.yMax += y >> 6;
387 x += slot->advance.x;
388 y -= slot->advance.y;
389 if ( glyph_bbox.xMin < bbox.xMin )
390 bbox.xMin = glyph_bbox.xMin;
391 if ( glyph_bbox.yMin < bbox.yMin )
392 bbox.yMin = glyph_bbox.yMin;
393 if ( glyph_bbox.xMax > bbox.xMax )
394 bbox.xMax = glyph_bbox.xMax;
395 if ( glyph_bbox.yMax > bbox.yMax )
396 bbox.yMax = glyph_bbox.yMax;
398 if ( bbox.xMin > bbox.xMax ) {
415 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
417 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
426 vx = alloca(count * sizeof(Sint16));
427 vy = alloca(count * sizeof(Sint16));
429 for(i = 0; i < count; i++)
449 printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y);
456 raster_aapolygon(gr->screen, count, vx, vy,
457 SDL_MapRGBA(gr->screen->format,
465 raster_polygon(gr->screen, count, vx, vy,
466 SDL_MapRGBA(gr->screen->format,
475 sge_FilledPolygonAlpha(gr->screen, count, vx, vy,
476 SDL_MapRGB(gr->screen->format,
483 sge_AAFilledPolygon(gr->screen, count, vx, vy,
484 SDL_MapRGB(gr->screen->format,
489 sge_FilledPolygon(gr->screen, count, vx, vy,
490 SDL_MapRGB(gr->screen->format,
497 filledPolygonRGBA(gr->screen, vx, vy, count,
498 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
506 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
508 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
514 printf("draw_rectangle: %d %d %d %d r=%d g=%d b=%d a=%d\n", p->x, p->y, w, h,
515 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
517 if(w > gr->screen->w)
521 if(h > gr->screen->h)
527 raster_rect(gr->screen, p->x, p->y, w, h,
528 SDL_MapRGBA(gr->screen->format,
536 sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h,
537 SDL_MapRGB(gr->screen->format,
543 /* no AA -- should use poly instead for that */
544 sge_FilledRect(gr->screen, p->x, p->y, p->x + w, p->y + h,
545 SDL_MapRGB(gr->screen->format,
551 boxRGBA(gr->screen, p->x, p->y, p->x + w, p->y + h,
552 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
559 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
561 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
567 if(gc->fore_a != 0xff)
569 dbg(0, "%d %d %d %u %u:%u:%u:%u\n", p->x, p->y, r, gc->linewidth,
570 gc->fore_a, gc->fore_r, gc->fore_g, gc->fore_b);
574 /* FIXME: does not quite match gtk */
576 /* hack for osd compass.. why is this needed!? */
585 raster_aacircle(gr->screen, p->x, p->y, r,
586 SDL_MapRGBA(gr->screen->format,
594 raster_circle(gr->screen, p->x, p->y, r,
595 SDL_MapRGBA(gr->screen->format,
604 sge_FilledCircleAlpha(gr->screen, p->x, p->y, r,
605 SDL_MapRGB(gr->screen->format,
606 gc->fore_r, gc->fore_g, gc->fore_b),
610 sge_AAFilledCircle(gr->screen, p->x, p->y, r,
611 SDL_MapRGB(gr->screen->format,
612 gc->fore_r, gc->fore_g, gc->fore_b));
614 sge_FilledCircle(gr->screen, p->x, p->y, r,
615 SDL_MapRGB(gr->screen->format,
616 gc->fore_r, gc->fore_g, gc->fore_b));
621 aacircleRGBA(gr->screen, p->x, p->y, r,
622 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
624 filledCircleRGBA(gr->screen, p->x, p->y, r,
625 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
633 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
635 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
640 /* you might expect lines to be simpler than the other shapes.
641 but, that would be wrong. 1 line can generate 1 polygon + 2 circles
642 and even worse, we have to calculate their parameters!
643 go dust off your trigonometry hat.
646 int i, l, x_inc, y_inc, lw;
650 for(i = 0; i < count-1; i++)
653 printf("draw_lines: %p %d %d,%d->%d,%d %d\n", gc, i, p[i].x, p[i].y, p[i+1].x, p[i+1].y, gc->linewidth);
655 for(l = 0; l < lw; l++)
659 if(p[i].x != p[i+1].x)
668 if(p[i].y != p[i+1].y)
682 aalineRGBA(gr->screen, p[i].x + x_inc, p[i].y + y_inc, p[i+1].x + x_inc, p[i+1].y + y_inc,
683 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
685 lineRGBA(gr->screen, p[i].x + x_inc, p[i].y + y_inc, p[i+1].x + x_inc, p[i+1].y + y_inc,
686 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
691 /* sort of based on graphics_opengl.c::draw_lines */
692 /* FIXME: should honor ./configure flag for no fp.
693 this could be 100% integer code pretty easily,
694 except that i am lazy
696 struct point vert[4];
697 int lw = gc->linewidth;
701 for(i = 0; i < count-1; i++)
703 float dx=p[i+1].x-p[i].x;
704 float dy=p[i+1].y-p[i].y;
707 float cx=(p[i+1].x+p[i].x)/2;
708 float cy=(p[i+1].y+p[i].y)/2;
713 int x_lw_adj, y_lw_adj;
720 raster_aaline(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
721 SDL_MapRGBA(gr->screen->format,
729 raster_line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
730 SDL_MapRGBA(gr->screen->format,
739 sge_LineAlpha(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
740 SDL_MapRGB(gr->screen->format,
741 gc->fore_r, gc->fore_g, gc->fore_b),
745 sge_AALine(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
746 SDL_MapRGB(gr->screen->format,
747 gc->fore_r, gc->fore_g, gc->fore_b));
749 sge_Line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
750 SDL_MapRGB(gr->screen->format,
751 gc->fore_r, gc->fore_g, gc->fore_b));
756 aalineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
757 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
759 lineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
760 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
767 /* there is probably a much simpler way but this works ok */
769 /* FIXME: float + double mixture */
770 /* FIXME: lrint(round())? */
775 y_lw_adj = round((float)lw/2.0);
780 x_lw_adj = round((float)lw/2.0);
785 angle = (M_PI/2.0) - atan(abs(dx)/abs(dy));
786 x_lw_adj = round(sin(angle)*(float)lw/2.0);
787 y_lw_adj = round(cos(angle)*(float)lw/2.0);
788 if((x_lw_adj < 0) || (y_lw_adj < 0))
791 printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
792 printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
793 printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
797 if(p[i+1].x > p[i].x)
799 x_lw_adj = -x_lw_adj;
801 if(p[i+1].y > p[i].y)
803 y_lw_adj = -y_lw_adj;
807 if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2))
810 printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
811 printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
812 printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
816 /* FIXME: draw a circle/square if p[i]==p[i+1]? */
817 /* FIXME: clipping, check for neg values. hoping sdl-gfx does this */
818 vert[0].x = p[i].x + x_lw_adj;
819 vert[0].y = p[i].y - y_lw_adj;
820 vert[1].x = p[i].x - x_lw_adj;
821 vert[1].y = p[i].y + y_lw_adj;
822 vert[2].x = p[i+1].x - x_lw_adj;
823 vert[2].y = p[i+1].y + y_lw_adj;
824 vert[3].x = p[i+1].x + x_lw_adj;
825 vert[3].y = p[i+1].y - y_lw_adj;
827 draw_polygon(gr, gc, vert, 4);
829 /* draw small circles at the ends. this looks better than nothing, and slightly
830 * better than the triangle used by graphics_opengl, but is more expensive.
831 * should have an ifdef/xml attr?
834 /* FIXME: should just draw a half circle */
836 /* now some circular endcaps, if the width is over 2 */
841 draw_circle(gr, gc, &p[i], lw/2);
843 /* we truncate on the divide on purpose, so we don't go outside the line */
844 draw_circle(gr, gc, &p[i+1], lw/2);
851 display_text_draw(struct font_freetype_text *text,
852 struct graphics_priv *gr, struct graphics_gc_priv *fg,
853 struct graphics_gc_priv *bg, int color, struct point *p)
856 struct font_freetype_glyph *g, **gp;
857 unsigned char *shadow, *glyph;
858 struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
860 { fg->fore_r * 255, fg->fore_g * 255, fg->fore_b * 255, fg->fore_a * 255
862 struct color white = { 0xffff, 0xffff, 0xffff, 0xffff };
865 if (COLOR_IS_WHITE(black) && COLOR_IS_BLACK(white)) {
875 } else if (COLOR_IS_BLACK(black) && COLOR_IS_WHITE(white)) {
886 white.r = bg->fore_r * 255;
887 white.g = bg->fore_g * 255;
888 white.b = bg->fore_b * 255;
889 white.a = bg->fore_a * 255;
900 i = text->glyph_count;
905 if (g->w && g->h && bg) {
906 stride = (g->w + 2) * 4;
908 shadow = g_malloc(stride * (g->h + 2));
909 gr->freetype_methods.get_shadow(g, shadow, 32, stride, &white, &transparent);
911 SDL_Surface *glyph_surface =
912 SDL_CreateRGBSurfaceFrom(shadow, g->w + 2, g->h + 2,
915 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
918 r.x = (x + g->x) >> 6;
919 r.y = (y + g->y) >> 6;
923 SDL_BlitSurface(glyph_surface, NULL, gr->screen, &r);
924 SDL_FreeSurface(glyph_surface);
936 i = text->glyph_count;
943 glyph = g_malloc(stride * g->h * 4);
944 gr->freetype_methods.get_glyph(g, glyph, 32,
946 &white, &transparent);
947 SDL_Surface *glyph_surface =
948 SDL_CreateRGBSurfaceFrom(glyph, g->w, g->h, 32,
950 0x000000ff,0x0000ff00, 0x00ff0000,0xff000000);
953 r.x = (x + g->x) >> 6;
954 r.y = (y + g->y) >> 6;
958 SDL_BlitSurface(glyph_surface, NULL, gr->screen,&r);
959 SDL_FreeSurface(glyph_surface);
964 glyph = g_malloc(stride * g->h);
965 gr->freetype_methods.get_glyph(g, glyph, 32, stride,
968 //convert ABGR to RGBA
970 unsigned char *pGlyph = glyph;
971 for (j = 0; j < g->w * g->h; ++j) {
974 *(pGlyph + 0) = *(pGlyph + 2);
978 SDL_Surface *glyph_surface =
979 SDL_CreateRGBSurfaceFrom(glyph, g->w, g->h, 32,
981 0x000000ff,0x0000ff00,0x00ff0000,0xff000000);
984 r.x = (x + g->x) >> 6;
985 r.y = (y + g->y) >> 6;
989 SDL_BlitSurface(glyph_surface, NULL, gr->screen, &r);
990 SDL_FreeSurface(glyph_surface);
994 for (jj = 0; jj < g->h; ++jj) {
995 for (ii = 0; ii < g->w; ++ii) {
996 int sx = (x + g->x) >> 6;
997 int sy = (y + g->y) >> 6;
998 sx = sx < 0 ? 0 : sx;
999 sy = sy < 0 ? 0 : sy;
1001 gr->screen->w * ((jj) + sy) + ((ii) + sx);
1002 poff *= gr->screen->format->BytesPerPixel;
1014 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg,
1015 struct graphics_gc_priv *bg, struct graphics_font_priv *font,
1016 char *text, struct point *p, int dx, int dy)
1018 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable)
1019 || (gr->overlay_parent && gr->overlay_parent->overlay_enable
1020 && !gr->overlay_enable)) {
1024 struct font_freetype_text *t;
1028 dbg(0, "no font, returning\n");
1031 t = gr->freetype_methods.text_new(text,
1032 (struct font_freetype_font *) font,
1039 display_text_draw(t, gr, fg, bg, color, &p_eff);
1040 gr->freetype_methods.text_destroy(t);
1044 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
1046 if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent && gr->overlay_parent->overlay_enable && !gr->overlay_enable) )
1059 SDL_BlitSurface(img->img, NULL, gr->screen, &r);
1064 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
1070 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1073 printf("draw_restore\n");
1078 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1081 printf("background_gc\n");
1087 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1091 unsigned long elapsed;
1093 struct graphics_priv *ov;
1097 if(gr->overlay_mode)
1099 /* will be drawn below */
1104 printf("draw_mode: %d\n", mode);
1108 if(mode == draw_mode_begin)
1110 gettimeofday(&gr->draw_begin_tv, NULL);
1114 if(mode == draw_mode_end)
1116 if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable)
1118 for(i = 0; i < OVERLAY_MAX; i++)
1120 ov = gr->overlay_array[i];
1121 if(ov && ov->overlay_enable)
1123 rect.x = ov->overlay_x;
1124 if(rect.x<0) rect.x += gr->screen->w;
1125 rect.y = ov->overlay_y;
1126 if(rect.y<0) rect.y += gr->screen->h;
1127 rect.w = ov->screen->w;
1128 rect.h = ov->screen->h;
1129 SDL_BlitSurface(ov->screen, NULL,
1135 SDL_Flip(gr->screen);
1138 gettimeofday(&now, NULL);
1139 elapsed = 1000000 * (now.tv_sec - gr->draw_begin_tv.tv_sec);
1140 elapsed += (now.tv_usec - gr->draw_begin_tv.tv_usec);
1141 if(elapsed >= gr->draw_time_peak)
1143 dbg(0, "draw elapsed %u usec\n", elapsed);
1144 gr->draw_time_peak = elapsed;
1149 gr->draw_mode = mode;
1153 static void overlay_disable(struct graphics_priv *gr, int disable)
1155 gr->overlay_enable = !disable;
1156 struct graphics_priv *curr_gr = gr;
1157 if(gr->overlay_parent) {
1158 curr_gr = gr->overlay_parent;
1160 draw_mode(curr_gr,draw_mode_end);
1163 static struct graphics_priv *
1164 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha, int wraparound);
1166 static int window_fullscreen(struct window *win, int on)
1168 struct graphics_priv *gr=(struct graphics_priv *)win->priv;
1170 /* Update video flags */
1172 gr->video_flags |= SDL_FULLSCREEN;
1174 gr->video_flags &= ~SDL_FULLSCREEN;
1177 /* Update video mode */
1178 gr->screen = SDL_SetVideoMode(gr->screen->w, gr->screen->h, gr->video_bpp, gr->video_flags);
1179 if(gr->screen == NULL) {
1180 navit_destroy(gr->nav);
1183 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1189 get_data(struct graphics_priv *this, char *type)
1191 if(strcmp(type, "window") == 0) {
1193 win=g_new(struct window, 1);
1195 win->fullscreen=window_fullscreen;
1196 win->disable_suspend=NULL;
1203 static void draw_drag(struct graphics_priv *gr, struct point *p)
1206 gr->overlay_x = p->x;
1207 gr->overlay_y = p->y;
1211 static struct graphics_methods graphics_methods = {
1229 // register_resize_callback,
1230 // register_button_callback,
1231 // register_motion_callback,
1235 // register_keypress_callback
1238 static struct graphics_priv *
1239 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h,int alpha, int wraparound)
1241 struct graphics_priv *ov;
1242 Uint32 rmask, gmask, bmask, amask;
1245 for(i = 0; i < OVERLAY_MAX; i++)
1247 if(gr->overlay_array[i] == NULL)
1252 if(i == OVERLAY_MAX)
1254 dbg(0, "too many overlays! increase OVERLAY_MAX\n");
1258 dbg(1, "overlay_new %d %d %d %u %u (%x, %x, %x ,%x, %d)\n", i,
1263 gr->screen->format->Rmask,
1264 gr->screen->format->Gmask,
1265 gr->screen->format->Bmask,
1266 gr->screen->format->Amask,
1267 gr->screen->format->BitsPerPixel
1270 ov = g_new0(struct graphics_priv, 1);
1272 switch(gr->screen->format->BitsPerPixel) {
1292 rmask = gr->screen->format->Rmask;
1293 gmask = gr->screen->format->Gmask;
1294 bmask = gr->screen->format->Bmask;
1295 amask = gr->screen->format->Amask;
1298 ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
1300 gr->screen->format->BitsPerPixel,
1301 rmask, gmask, bmask, amask);
1303 ov->overlay_mode = 1;
1304 ov->overlay_enable = 1;
1305 ov->overlay_x = p->x;
1306 ov->overlay_y = p->y;
1307 ov->overlay_parent = gr;
1308 ov->overlay_idx = i;
1309 gr->overlay_array[i] = ov;
1312 struct font_priv *(*font_freetype_new) (void *meth);
1313 font_freetype_new = plugin_get_font_type ("freetype");
1315 if (!font_freetype_new)
1321 font_freetype_new (&ov->freetype_methods);
1323 *meth=graphics_methods;
1326 (struct graphics_font_priv *
1327 (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1328 int)) ov->freetype_methods.font_new;
1329 meth->get_text_bbox = ov->freetype_methods.get_text_bbox;
1338 #ifdef LINUX_TOUCHSCREEN
1340 #define EVFN "/dev/input/eventX"
1342 static int input_ts_init(struct graphics_priv *gr)
1360 fn[sizeof(EVFN)-2] = '0' + n;
1362 fd = open(fn, O_RDONLY);
1366 ret = ioctl(fd, EVIOCGNAME(64), (void *)name);
1369 printf("input_ts: %s\n", name);
1373 ret = ioctl(fd, EVIOCGID, (void *)&ii);
1377 printf("bustype %04x vendor %04x product %04x version %04x\n",
1384 if((ii.bustype == BUS_USB) &&
1385 (ii.vendor == 0x0eef) &&
1386 (ii.product == 0x0001))
1388 ret = fcntl(fd, F_SETFL, O_NONBLOCK);
1407 /* FIXME: should check all 32 minors */
1420 /* returns 0-based display coordinate for the given ts coord */
1421 static void input_ts_map(int *disp_x, int *disp_y,
1422 uint32_t ts_x, uint32_t ts_y)
1424 /* Dynamix 7" (eGalax TS)
1427 bot left = 1986,1897
1430 calibrate your TS using input_event_dump
1431 and touching all four corners. use the most extreme values.
1434 #define INPUT_TS_LEFT 1978
1435 #define INPUT_TS_RIGHT 48
1436 #define INPUT_TS_TOP 115
1437 #define INPUT_TS_BOT 1870
1440 if(ts_x > INPUT_TS_LEFT)
1442 ts_x = INPUT_TS_LEFT;
1444 if(ts_x < INPUT_TS_RIGHT)
1446 ts_x = INPUT_TS_RIGHT;
1449 ts_x = ts_x - INPUT_TS_RIGHT;
1451 *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT);
1452 *disp_x = (DISPLAY_W-1) - *disp_x;
1455 if(ts_y > INPUT_TS_BOT)
1457 ts_y = INPUT_TS_BOT;
1459 if(ts_y < INPUT_TS_TOP)
1461 ts_y = INPUT_TS_TOP;
1464 ts_y = ts_y - INPUT_TS_TOP;
1466 *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP);
1467 /* *disp_y = (DISPLAY_H-1) - *disp_y; */
1471 static void input_event_dump(struct input_event *ie)
1473 printf("input_event:\n"
1479 (unsigned int)ie->time.tv_sec,
1487 static int input_ts_exit(struct graphics_priv *gr)
1497 static gboolean graphics_sdl_idle(void *data)
1499 struct graphics_priv *gr = (struct graphics_priv *)data;
1502 #ifdef LINUX_TOUCHSCREEN
1503 struct input_event ie;
1509 /* generate the initial resize callback, so the gui knows W/H
1511 its unsafe to do this directly inside register_resize_callback;
1512 graphics_gtk does it during Configure, but SDL does not have
1513 an equivalent event, so we use our own flag
1515 if(gr->resize_callback_initial != 0)
1517 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1518 gr->resize_callback_initial = 0;
1521 #ifdef LINUX_TOUCHSCREEN
1524 ss = read(gr->ts_fd, (void *)&ie, sizeof(ie));
1525 if(ss == sizeof(ie))
1527 /* we (usually) get three events on a touchscreen hit:
1529 code =330 [BTN_TOUCH]
1542 once hit, if the contact point changes, we'll get more
1543 EV_ABS (for 1 or both axes), followed by an EV_SYN.
1548 code =330 [BTN_TOUCH]
1557 if(ie.code == BTN_TOUCH)
1559 gr->ts_hit = ie.value;
1569 gr->ts_x = ie.value;
1571 else if(ie.code == 1)
1573 gr->ts_y = ie.value;
1581 input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y);
1583 /* always send MOUSE_MOTION (first) */
1584 callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
1587 callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)SDL_BUTTON_LEFT, (void *)&p);
1589 else if(gr->ts_hit == 0)
1591 callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)SDL_BUTTON_LEFT, (void *)&p);
1611 ret = SDL_PollEvent(&ev);
1619 case SDL_MOUSEMOTION:
1623 callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p);
1629 switch(ev.key.keysym.sym)
1633 key = NAVIT_KEY_LEFT;
1638 key = NAVIT_KEY_RIGHT;
1641 case SDLK_BACKSPACE:
1643 key = NAVIT_KEY_BACKSPACE;
1648 key = NAVIT_KEY_RETURN;
1653 key = NAVIT_KEY_DOWN;
1658 key = NAVIT_KEY_ZOOM_OUT;
1668 key = NAVIT_KEY_ZOOM_IN;
1673 /* return unicode chars when they can be converted to ascii */
1674 key = ev.key.keysym.unicode<=127 ? ev.key.keysym.unicode : 0;
1681 callback_list_call_attr_1(gr->cbl, attr_keypress, (void *)keybuf);
1691 case SDL_MOUSEBUTTONDOWN:
1694 printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n",
1704 callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)(int)ev.button.button, (void *)&p);
1708 case SDL_MOUSEBUTTONUP:
1711 printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n",
1721 callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)(int)ev.button.button, (void *)&p);
1727 navit_destroy(gr->nav);
1731 case SDL_VIDEORESIZE:
1734 gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, gr->video_bpp, gr->video_flags);
1735 if(gr->screen == NULL)
1737 navit_destroy(gr->nav);
1741 callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h);
1750 printf("SDL_Event %d\n", ev.type);
1761 static struct graphics_priv *
1762 graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
1764 struct graphics_priv *this=g_new0(struct graphics_priv, 1);
1767 int w=DISPLAY_W,h=DISPLAY_H;
1769 struct font_priv *(*font_freetype_new) (void *meth);
1770 font_freetype_new = plugin_get_font_type ("freetype");
1772 if (!font_freetype_new)
1777 font_freetype_new (&this->freetype_methods);
1782 ret = SDL_Init(SDL_INIT_VIDEO);
1789 if (! event_request_system("glib","graphics_sdl_new"))
1792 this->video_bpp = 16;
1793 this->video_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE;
1795 if ((attr=attr_search(attrs, NULL, attr_w)))
1797 if ((attr=attr_search(attrs, NULL, attr_h)))
1799 if ((attr=attr_search(attrs, NULL, attr_bpp)))
1800 this->video_bpp=attr->u.num;
1801 if ((attr=attr_search(attrs, NULL, attr_flags))) {
1802 if (attr->u.num & 1)
1803 this->video_flags = SDL_SWSURFACE;
1805 if ((attr=attr_search(attrs, NULL, attr_frame))) {
1807 this->video_flags |= SDL_NOFRAME;
1810 this->screen = SDL_SetVideoMode(w, h, this->video_bpp, this->video_flags);
1812 /* Use screen size instead of requested */
1813 w = this->screen->w;
1814 h = this->screen->h;
1816 if(this->screen == NULL)
1823 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
1825 SDL_EnableUNICODE(1);
1826 SDL_WM_SetCaption("navit", NULL);
1828 #ifdef LINUX_TOUCHSCREEN
1829 input_ts_init(this);
1830 if(this->ts_fd >= 0)
1832 /* mouse cursor does not always display correctly in Linux FB.
1833 anyway, it is unnecessary w/ a touch screen
1844 *meth=graphics_methods;
1848 (struct graphics_font_priv *
1849 (*)(struct graphics_priv *, struct graphics_font_methods *, char *, int,
1850 int)) this->freetype_methods.font_new;
1851 meth->get_text_bbox = this->freetype_methods.get_text_bbox;
1855 g_timeout_add(G_PRIORITY_DEFAULT+10, graphics_sdl_idle, this);
1857 this->overlay_enable = 1;
1860 if((attr=attr_search(attrs, NULL, attr_antialias)))
1861 this->aa = attr->u.num;
1863 this->resize_callback_initial=1;
1870 plugin_register_graphics_type("sdl", graphics_sdl_new);