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
43 #undef LINUX_TOUCHSCREEN
63 #include <SDL/SDL_gfxPrimitives.h>
67 #include <SDL/SDL_ttf.h>
69 #include <fontconfig/fontconfig.h>
71 #include FT_FREETYPE_H
72 #include <freetype/ftglyph.h>
76 #include <SDL/SDL_image.h>
79 #ifdef LINUX_TOUCHSCREEN
80 /* we use Linux evdev directly for the touchscreen. */
81 #include <sys/types.h>
84 #include <linux/input.h>
95 /* TODO: union overlay + non-overlay to reduce size */
97 struct graphics_priv {
105 struct graphics_priv *overlay_parent;
110 struct graphics_priv *overlay_array[OVERLAY_MAX];
112 enum draw_mode_num draw_mode;
114 void (*resize_callback)(void *data, int w, int h);
115 void *resize_callback_data;
116 int resize_callback_initial;
118 void (*motion_callback)(void *data, struct point *p);
119 void *motion_callback_data;
121 void (*button_callback)(void *data, int press, int button, struct point *p);
122 void *button_callback_data;
124 void (*keypress_callback)(void *data, char *key);
125 void *keypress_callback_data;
129 #ifdef LINUX_TOUCHSCREEN
141 struct timeval draw_begin_tv;
142 unsigned long draw_time_peak;
150 struct graphics_font_priv {
158 struct graphics_gc_priv {
159 struct graphics_priv *gr;
171 struct graphics_image_priv {
176 #ifdef LINUX_TOUCHSCREEN
177 static int input_ts_exit(struct graphics_priv *gr);
181 graphics_destroy(struct graphics_priv *gr)
183 dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode);
187 SDL_FreeSurface(gr->screen);
188 gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL;
195 FT_Done_FreeType(gr->library);
198 #ifdef LINUX_TOUCHSCREEN
208 static char *fontfamilies[]={
218 static void font_destroy(struct graphics_font_priv *gf)
222 FT_Done_Face(gf->face);
227 static struct graphics_font_methods font_methods = {
231 static struct graphics_font_priv *font_new(struct graphics_priv *gr, struct graphics_font_methods *meth, int size, int flags)
233 struct graphics_font_priv *gf=g_new(struct graphics_font_priv, 1);
236 /* 'size' is in pixels, TTF_OpenFont wants pts. */
239 // gf->font = TTF_OpenFont("/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf", size);
242 gf->font = TTF_OpenFont("/usr/share/fonts/truetype/LiberationMono-Bold.ttf", size);
246 gf->font = TTF_OpenFont("/usr/share/fonts/truetype/LiberationMono-Regular.ttf", size);
257 /* apparently just means bold right now */
258 TTF_SetFontStyle(gf->font, TTF_STYLE_BOLD);
262 TTF_SetFontStyle(gf->font, TTF_STYLE_NORMAL);
265 /* copy-pasted from graphics_gtk_drawing_area.c
267 FIXME: figure out some way to share this b/t gtk and sdl graphics plugin.
268 new 'font' plugin type that uses an abstracted bitmap fmt to pass to gfx plugin?
276 gr = gr->overlay_parent;
280 for (exact=1;!found && exact>=0;exact--) {
282 while (*family && !found) {
283 dbg(1, "Looking for font family %s. exact=%d\n", *family, exact);
284 FcPattern *required = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, *family, NULL);
286 FcPatternAddInteger(required,FC_WEIGHT,FC_WEIGHT_BOLD);
287 FcConfigSubstitute(FcConfigGetCurrent(), required, FcMatchFont);
288 FcDefaultSubstitute(required);
290 FcPattern *matched = FcFontMatch(FcConfigGetCurrent(), required, &result);
295 FcPatternGet(required, FC_FAMILY, 0, &v1);
296 FcPatternGet(matched, FC_FAMILY, 0, &v2);
297 FcResult r1 = FcPatternGetString(matched, FC_FILE, 0, &fontfile);
298 FcResult r2 = FcPatternGetInteger(matched, FC_INDEX, 0, &fontindex);
299 if ((r1 == FcResultMatch) && (r2 == FcResultMatch) && (FcValueEqual(v1,v2) || !exact)) {
300 dbg(2, "About to load font from file %s index %d\n", fontfile, fontindex);
301 FT_New_Face( gr->library, (char *)fontfile, fontindex, &gf->face );
304 FcPatternDestroy(matched);
306 FcPatternDestroy(required);
311 g_warning("Failed to load font, no labelling");
315 FT_Set_Char_Size(gf->face, 0, size, 300, 300);
316 FT_Select_Charmap(gf->face, FT_ENCODING_UNICODE);
328 gc_destroy(struct graphics_gc_priv *gc)
334 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
337 printf("gc_set_linewidth %p %d\n", gc, w);
343 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
349 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
352 printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
354 gc->fore_r = c->r/256;
355 gc->fore_g = c->g/256;
356 gc->fore_b = c->b/256;
357 gc->fore_a = c->a/256;
361 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
364 printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
366 gc->back_r = c->r/256;
367 gc->back_g = c->g/256;
368 gc->back_b = c->b/256;
369 gc->back_a = c->a/256;
372 static struct graphics_gc_methods gc_methods = {
380 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
382 struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1);
385 gc->linewidth=1; /* upper layer should override anyway? */
390 #if 0 /* unused by core? */
391 static void image_destroy(struct graphics_image_priv *gi)
394 SDL_FreeSurface(gi->img);
399 static struct graphics_image_methods gi_methods =
405 static struct graphics_image_priv *
406 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
410 struct graphics_image_priv *gi;
412 /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
414 gi = g_new0(struct graphics_image_priv, 1);
415 gi->img = IMG_Load(name);
418 /* TBD: improves blit performance? */
419 SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey);
427 /* TODO: debug "colour parse errors" on xpm */
428 printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError());
440 image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
443 SDL_FreeSurface(gi->img);
449 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret)
454 FT_GlyphSlot slot = font->face->glyph; // a small shortcut
466 bbox.xMin = bbox.yMin = 32000;
467 bbox.xMax = bbox.yMax = -32000;
468 FT_Set_Transform( font->face, &matrix, &pen );
469 len=g_utf8_strlen(text, -1);
470 for ( n = 0; n < len; n++ ) {
472 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
473 p=g_utf8_next_char(p);
474 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT );
475 FT_Get_Glyph(font->face->glyph, &glyph);
476 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox );
477 FT_Done_Glyph(glyph);
478 glyph_bbox.xMin += x >> 6;
479 glyph_bbox.xMax += x >> 6;
480 glyph_bbox.yMin += y >> 6;
481 glyph_bbox.yMax += y >> 6;
482 x += slot->advance.x;
483 y -= slot->advance.y;
484 if ( glyph_bbox.xMin < bbox.xMin )
485 bbox.xMin = glyph_bbox.xMin;
486 if ( glyph_bbox.yMin < bbox.yMin )
487 bbox.yMin = glyph_bbox.yMin;
488 if ( glyph_bbox.xMax > bbox.xMax )
489 bbox.xMax = glyph_bbox.xMax;
490 if ( glyph_bbox.yMax > bbox.yMax )
491 bbox.yMax = glyph_bbox.yMax;
493 if ( bbox.xMin > bbox.xMax ) {
510 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
516 vx = alloca(count * sizeof(Sint16));
517 vy = alloca(count * sizeof(Sint16));
519 for(i = 0; i < count; i++)
539 printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y);
546 raster_aapolygon(gr->screen, count, vx, vy,
547 SDL_MapRGB(gr->screen->format,
554 raster_polygon(gr->screen, count, vx, vy,
555 SDL_MapRGB(gr->screen->format,
563 sge_FilledPolygonAlpha(gr->screen, count, vx, vy,
564 SDL_MapRGB(gr->screen->format,
571 sge_AAFilledPolygon(gr->screen, count, vx, vy,
572 SDL_MapRGB(gr->screen->format,
577 sge_FilledPolygon(gr->screen, count, vx, vy,
578 SDL_MapRGB(gr->screen->format,
585 filledPolygonRGBA(gr->screen, vx, vy, count,
586 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
594 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
597 printf("draw_rectangle: %d %d %d %d r=%d g=%d b=%d a=%d\n", p->x, p->y, w, h,
598 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
600 if(w > gr->screen->w)
604 if(h > gr->screen->h)
610 raster_rect(gr->screen, p->x, p->y, w, h,
611 SDL_MapRGB(gr->screen->format,
618 sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h,
619 SDL_MapRGB(gr->screen->format,
625 /* no AA -- should use poly instead for that */
626 sge_FilledRect(gr->screen, p->x, p->y, p->x + w, p->y + h,
627 SDL_MapRGB(gr->screen->format,
633 boxRGBA(gr->screen, p->x, p->y, p->x + w, p->y + h,
634 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
641 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
644 if(gc->fore_a != 0xff)
646 dbg(0, "%d %d %d %u %u:%u:%u:%u\n", p->x, p->y, r, gc->linewidth,
647 gc->fore_a, gc->fore_r, gc->fore_g, gc->fore_b);
651 /* FIXME: does not quite match gtk */
653 /* hack for osd compass.. why is this needed!? */
662 raster_aacircle(gr->screen, p->x, p->y, r,
663 SDL_MapRGB(gr->screen->format,
664 gc->fore_r, gc->fore_g, gc->fore_b));
668 raster_circle(gr->screen, p->x, p->y, r,
669 SDL_MapRGB(gr->screen->format,
670 gc->fore_r, gc->fore_g, gc->fore_b));
675 sge_FilledCircleAlpha(gr->screen, p->x, p->y, r,
676 SDL_MapRGB(gr->screen->format,
677 gc->fore_r, gc->fore_g, gc->fore_b),
681 sge_AAFilledCircle(gr->screen, p->x, p->y, r,
682 SDL_MapRGB(gr->screen->format,
683 gc->fore_r, gc->fore_g, gc->fore_b));
685 sge_FilledCircle(gr->screen, p->x, p->y, r,
686 SDL_MapRGB(gr->screen->format,
687 gc->fore_r, gc->fore_g, gc->fore_b));
692 aacircleRGBA(gr->screen, p->x, p->y, r,
693 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
695 filledCircleRGBA(gr->screen, p->x, p->y, r,
696 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
704 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
706 /* you might expect lines to be simpler than the other shapes.
707 but, that would be wrong. 1 line can generate 1 polygon + 2 circles
708 and even worse, we have to calculate their parameters!
709 go dust off your trigonometry hat.
712 int i, l, x_inc, y_inc, lw;
716 for(i = 0; i < count-1; i++)
719 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);
721 for(l = 0; l < lw; l++)
725 if(p[i].x != p[i+1].x)
734 if(p[i].y != p[i+1].y)
748 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,
749 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
751 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,
752 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
757 /* sort of based on graphics_opengl.c::draw_lines */
758 /* FIXME: should honor ./configure flag for no fp.
759 this could be 100% integer code pretty easily,
760 except that i am lazy
762 struct point vert[4];
763 int lw = gc->linewidth;
767 for(i = 0; i < count-1; i++)
769 float dx=p[i+1].x-p[i].x;
770 float dy=p[i+1].y-p[i].y;
773 float cx=(p[i+1].x+p[i].x)/2;
774 float cy=(p[i+1].y+p[i].y)/2;
779 int x_lw_adj, y_lw_adj;
786 raster_aaline(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
787 SDL_MapRGB(gr->screen->format,
788 gc->fore_r, gc->fore_g, gc->fore_b));
792 raster_line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
793 SDL_MapRGB(gr->screen->format,
794 gc->fore_r, gc->fore_g, gc->fore_b));
799 sge_LineAlpha(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
800 SDL_MapRGB(gr->screen->format,
801 gc->fore_r, gc->fore_g, gc->fore_b),
805 sge_AALine(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
806 SDL_MapRGB(gr->screen->format,
807 gc->fore_r, gc->fore_g, gc->fore_b));
809 sge_Line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
810 SDL_MapRGB(gr->screen->format,
811 gc->fore_r, gc->fore_g, gc->fore_b));
816 aalineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
817 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
819 lineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y,
820 gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
827 /* there is probably a much simpler way but this works ok */
829 /* FIXME: float + double mixture */
830 /* FIXME: lrint(round())? */
835 y_lw_adj = round((float)lw/2.0);
840 x_lw_adj = round((float)lw/2.0);
845 angle = (M_PI/2.0) - atan(abs(dx)/abs(dy));
846 x_lw_adj = round(sin(angle)*(float)lw/2.0);
847 y_lw_adj = round(cos(angle)*(float)lw/2.0);
848 if((x_lw_adj < 0) || (y_lw_adj < 0))
851 printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
852 printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
853 printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
857 if(p[i+1].x > p[i].x)
859 x_lw_adj = -x_lw_adj;
861 if(p[i+1].y > p[i].y)
863 y_lw_adj = -y_lw_adj;
867 if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2))
870 printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y);
871 printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI);
872 printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj);
876 /* FIXME: draw a circle/square if p[i]==p[i+1]? */
877 /* FIXME: clipping, check for neg values. hoping sdl-gfx does this */
878 vert[0].x = p[i].x + x_lw_adj;
879 vert[0].y = p[i].y - y_lw_adj;
880 vert[1].x = p[i].x - x_lw_adj;
881 vert[1].y = p[i].y + y_lw_adj;
882 vert[2].x = p[i+1].x - x_lw_adj;
883 vert[2].y = p[i+1].y + y_lw_adj;
884 vert[3].x = p[i+1].x + x_lw_adj;
885 vert[3].y = p[i+1].y - y_lw_adj;
887 draw_polygon(gr, gc, vert, 4);
889 /* draw small circles at the ends. this looks better than nothing, and slightly
890 * better than the triangle used by graphics_opengl, but is more expensive.
891 * should have an ifdef/xml attr?
894 /* FIXME: should just draw a half circle */
896 /* now some circular endcaps, if the width is over 2 */
901 draw_circle(gr, gc, &p[i], lw/2);
903 /* we truncate on the divide on purpose, so we don't go outside the line */
904 draw_circle(gr, gc, &p[i+1], lw/2);
914 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct graphics_font_priv *gf, char *text, struct point *p, int dx, int dy)
939 ss = TTF_RenderUTF8_Solid(gf->font, text, b);
946 //SDL_SetAlpha(ss, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
947 SDL_BlitSurface(ss, NULL, gr->screen, &r);
954 unsigned char *shadow;
955 unsigned char pixmap[0];
964 struct text_glyph *glyph[0];
967 static unsigned char *
968 display_text_render_shadow(struct text_glyph *g)
970 int mask0, mask1, mask2, x, y, w=g->w, h=g->h;
972 unsigned char *shadow;
973 unsigned char *p, *pm=g->pixmap;
975 shadow=malloc(str*(g->h+2));
976 memset(shadow, 0, str*(g->h+2));
977 for (y = 0 ; y < h ; y++) {
982 for (x = 0 ; x < w ; x++) {
988 p[str]|=(mask1 >> 8);
991 p[str*2]|=(mask2 >> 8);
998 if (!((mask0 >> 8) | (mask1 >> 8) | (mask2 >> 8))) {
1010 static struct text_render *
1011 display_text_render(char *text, struct graphics_font_priv *font, int dx, int dy, int x, int y)
1013 FT_GlyphSlot slot = font->face->glyph; // a small shortcut
1016 FT_UInt glyph_index;
1018 struct text_render *ret;
1019 struct text_glyph *curr;
1022 len=g_utf8_strlen(text, -1);
1023 ret=g_malloc(sizeof(*ret)+len*sizeof(struct text_glyph *));
1024 ret->glyph_count=len;
1035 FT_Set_Transform( font->face, &matrix, &pen );
1037 for ( n = 0; n < len; n++ )
1040 glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p));
1041 FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT );
1042 FT_Render_Glyph(font->face->glyph, ft_render_mode_normal );
1044 curr=g_malloc(sizeof(*curr)+slot->bitmap.rows*slot->bitmap.pitch);
1047 curr->x=(x>>6)+slot->bitmap_left;
1048 curr->y=(y>>6)-slot->bitmap_top;
1049 curr->w=slot->bitmap.width;
1050 curr->h=slot->bitmap.rows;
1051 if (slot->bitmap.width && slot->bitmap.rows) {
1052 memcpy(curr->pixmap, slot->bitmap.buffer, slot->bitmap.rows*slot->bitmap.pitch);
1053 curr->shadow=display_text_render_shadow(curr);
1058 printf("height=%d\n", slot->metrics.height);
1059 printf("height2=%d\n", face->height);
1060 printf("bbox %d %d %d %d\n", face->bbox.xMin, face->bbox.yMin, face->bbox.xMax, face->bbox.yMax);
1063 printf("slot->advance x %d y %d\n",
1068 x += slot->advance.x;
1069 y -= slot->advance.y;
1070 p=g_utf8_next_char(p);
1076 static void hexdump(unsigned char *buf, unsigned int w, unsigned int h)
1079 printf("hexdump %u %u\n", w, h);
1080 for(y = 0; y < h; y++)
1082 for(x = 0; x < w; x++)
1084 printf("%02x ", buf[y*w+x]);
1090 static void bitdump(unsigned char *buf, unsigned int w, unsigned int h)
1093 printf("bitdump %u %u\n", w, h);
1095 for(x = 0; x < h * w; x++)
1097 if(buf[pos] & (1 << (x&0x7)))
1106 if((x & 0x7) == 0x7)
1111 if((x % w) == (w-1))
1121 static void sdl_inv_grayscale_pal_set(SDL_Surface *ss)
1126 for(i = 0; i < 256; i++)
1131 SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1);
1135 static void sdl_scale_pal_set(SDL_Surface *ss, Uint8 r, Uint8 g, Uint8 b)
1140 for(i = 0; i < 256; i++)
1142 c.r = (i * r) / 256;
1143 c.g = (i * g) / 256;
1144 c.b = (i * b) / 256;
1145 SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1);
1151 static void sdl_fixed_pal_set(SDL_Surface *ss, Uint8 r, Uint8 g, Uint8 b)
1159 for(i = 0; i < 256; i++)
1161 SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1);
1167 display_text_draw(struct text_render *text, struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg)
1169 int i, x, y, poff, soff, col_lev;
1170 struct text_glyph *gly, **gp;
1175 dbg(0,"%u %u %u %u, %u %u %u %u\n",
1176 fg->fore_a, fg->fore_r, fg->fore_g, fg->fore_b,
1177 fg->back_a, fg->back_r, fg->back_g, fg->back_b);
1179 dbg(0,"%u %u %u %u, %u %u %u %u\n",
1180 bg->fore_a, bg->fore_r, bg->fore_g, bg->fore_b,
1181 bg->back_a, bg->back_r, bg->back_g, bg->back_b);
1186 col_lev = bg->fore_r + bg->fore_g + bg->fore_b;
1193 /* TODO: lock/unlock in draw_mode() to reduce overhead */
1194 SDL_LockSurface(gr->screen);
1196 i=text->glyph_count;
1200 if (gly->w && gly->h)
1203 if(gly->shadow && bg)
1205 hexdump(gly->pixmap, gly->w, gly->h);
1206 bitdump(gly->shadow, gly->w+2, gly->h+2);
1210 for(y = 0; y < gly->h + 2; y++)
1212 if(gly->y - 1 + y < 0)
1217 if(((gly->y-1) + y) >= gr->screen->h)
1222 for(x = 0; x < gly->w + 2; x++)
1224 if(gly->x - 1 + x < 0)
1229 if(((gly->x-1) + x) >= gr->screen->w)
1234 poff = gr->screen->w * ((gly->y-1) + y) + ((gly->x-1) + x);
1235 poff = poff * gr->screen->format->BytesPerPixel;
1237 switch(gr->screen->format->BytesPerPixel)
1241 pix = *(Uint16 *)((Uint8*)gr->screen->pixels + poff);
1246 pix = *(Uint32 *)((Uint8*)gr->screen->pixels + poff);
1263 printf("%u %u -> %u off\n",
1268 printf("%u,%u: %u %u %u in\n",
1275 if(gly->shadow && bg)
1277 soff = (8 * ((gly->w+9)/8) * y) + x;
1278 pix = gly->shadow[soff/8];
1280 if(pix & (1 << (7-(soff&0x7))))
1282 if(col_lev >= 3*0x80)
1298 if((x > 0) && (x <= gly->w) &&
1299 (y > 0) && (y <= gly->h))
1301 if(bg && (col_lev >= 3*0x80))
1303 r &= ~gly->pixmap[gly->w * (y-1) + (x-1)];
1304 g &= ~gly->pixmap[gly->w * (y-1) + (x-1)];
1305 b &= ~gly->pixmap[gly->w * (y-1) + (x-1)];
1309 r |= gly->pixmap[gly->w * (y-1) + (x-1)];
1310 g |= gly->pixmap[gly->w * (y-1) + (x-1)];
1311 b |= gly->pixmap[gly->w * (y-1) + (x-1)];
1316 printf("%u,%u: %u %u %u out\n",
1321 pix = SDL_MapRGB(gr->screen->format,
1326 switch(gr->screen->format->BytesPerPixel)
1330 *(Uint16 *)((Uint8*)gr->screen->pixels + poff) = pix;
1335 *(Uint32 *)((Uint8*)gr->screen->pixels + poff) = pix;
1346 //dbg(0, "glyph %d %d %d %d\n", g->x, g->y, g->w, g->h);
1349 SDL_UnlockSurface(gr->screen);
1353 display_text_free(struct text_render *text)
1356 struct text_glyph **gp;
1359 i=text->glyph_count;
1361 if ((*gp)->shadow) {
1362 free((*gp)->shadow);
1370 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct graphics_font_priv *font, char *text, struct point *p, int dx, int dy)
1372 struct text_render *t;
1379 gdk_gc_set_function(fg->gc, GDK_AND_INVERT);
1380 gdk_gc_set_function(bg->gc, GDK_OR);
1384 t=display_text_render(text, font, dx, dy, p->x, p->y);
1385 display_text_draw(t, gr, fg, bg);
1386 display_text_free(t);
1389 gdk_gc_set_function(fg->gc, GDK_COPY);
1390 gdk_gc_set_function(bg->gc, GDK_COPY);
1399 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
1409 SDL_BlitSurface(img->img, NULL, gr->screen, &r);
1414 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
1420 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1423 printf("draw_restore\n");
1428 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1431 printf("background_gc\n");
1437 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1441 unsigned long elapsed;
1443 struct graphics_priv *ov;
1447 if(gr->overlay_mode)
1449 /* will be drawn below */
1454 printf("draw_mode: %d\n", mode);
1458 if(mode == draw_mode_begin)
1460 gettimeofday(&gr->draw_begin_tv, NULL);
1464 if(mode == draw_mode_end)
1466 if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable)
1468 for(i = 0; i < OVERLAY_MAX; i++)
1470 ov = gr->overlay_array[i];
1473 rect.x = ov->overlay_x;
1474 rect.y = ov->overlay_y;
1475 rect.w = ov->screen->w;
1476 rect.h = ov->screen->h;
1477 SDL_BlitSurface(ov->screen, NULL,
1483 SDL_Flip(gr->screen);
1486 gettimeofday(&now, NULL);
1487 elapsed = 1000000 * (now.tv_sec - gr->draw_begin_tv.tv_sec);
1488 elapsed += (now.tv_usec - gr->draw_begin_tv.tv_usec);
1489 if(elapsed >= gr->draw_time_peak)
1491 dbg(0, "draw elapsed %u usec\n", elapsed);
1492 gr->draw_time_peak = elapsed;
1497 gr->draw_mode = mode;
1501 static struct graphics_methods graphics_methods;
1503 static struct graphics_priv *
1504 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h)
1506 struct graphics_priv *ov;
1509 for(i = 0; i < OVERLAY_MAX; i++)
1511 if(gr->overlay_array[i] == NULL)
1516 if(i == OVERLAY_MAX)
1518 dbg(0, "too many overlays! increase OVERLAY_MAX\n");
1521 dbg(0, "x %d y %d\n", p->x, p->y);
1525 x = gr->screen->w + p->x;
1533 y = gr->screen->h + p->y;
1540 dbg(1, "overlay_new %d %d %d %u %u\n", i,
1546 ov = g_new0(struct graphics_priv, 1);
1548 ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
1551 gr->screen->format->BitsPerPixel,
1552 gr->screen->format->Rmask,
1553 gr->screen->format->Gmask,
1554 gr->screen->format->Bmask,
1562 SDL_SetAlpha(ov->screen, SDL_SRCALPHA, 128);
1564 ov->overlay_mode = 1;
1567 ov->overlay_parent = gr;
1568 ov->overlay_idx = i;
1570 gr->overlay_array[i] = ov;
1572 *meth=graphics_methods;
1577 static void overlay_disable(struct graphics_priv *gr, int disable)
1579 gr->overlay_enable = !disable;
1583 static int window_fullscreen(struct window *win, int on)
1589 static struct window sdl_win =
1597 get_data(struct graphics_priv *this, char *type)
1599 printf("get_data: %s\n", type);
1601 if(strcmp(type, "window") == 0)
1614 register_resize_callback(struct graphics_priv *this, void (*callback)(void *data, int w, int h), void *data)
1616 this->resize_callback=callback;
1617 this->resize_callback_data=data;
1618 this->resize_callback_initial=1;
1622 register_motion_callback(struct graphics_priv *this, void (*callback)(void *data, struct point *p), void *data)
1624 this->motion_callback=callback;
1625 this->motion_callback_data=data;
1629 register_button_callback(struct graphics_priv *this, void (*callback)(void *data, int press, int button, struct point *p), void *data)
1631 this->button_callback=callback;
1632 this->button_callback_data=data;
1636 register_keypress_callback(struct graphics_priv *this,
1637 void (*callback)(void *data, char *key),
1640 this->keypress_callback=callback;
1641 this->keypress_callback_data=data;
1644 static struct graphics_methods graphics_methods = {
1661 register_resize_callback,
1662 register_button_callback,
1663 register_motion_callback,
1667 register_keypress_callback
1671 #ifdef LINUX_TOUCHSCREEN
1673 #define EVFN "/dev/input/eventX"
1675 static int input_ts_init(struct graphics_priv *gr)
1693 fn[sizeof(EVFN)-2] = '0' + n;
1695 fd = open(fn, O_RDONLY);
1699 ret = ioctl(fd, EVIOCGNAME(64), (void *)name);
1702 printf("input_ts: %s\n", name);
1706 ret = ioctl(fd, EVIOCGID, (void *)&ii);
1710 printf("bustype %04x vendor %04x product %04x version %04x\n",
1717 if((ii.bustype == BUS_USB) &&
1718 (ii.vendor == 0x0eef) &&
1719 (ii.product == 0x0001))
1721 ret = fcntl(fd, F_SETFL, O_NONBLOCK);
1740 /* FIXME: should check all 32 minors */
1753 /* returns 0-based display coordinate for the given ts coord */
1754 static void input_ts_map(int *disp_x, int *disp_y,
1755 uint32_t ts_x, uint32_t ts_y)
1757 /* Dynamix 7" (eGalax TS)
1760 bot left = 1986,1897
1763 calibrate your TS using input_event_dump
1764 and touching all four corners. use the most extreme values.
1767 #define INPUT_TS_LEFT 1978
1768 #define INPUT_TS_RIGHT 48
1769 #define INPUT_TS_TOP 115
1770 #define INPUT_TS_BOT 1870
1773 if(ts_x > INPUT_TS_LEFT)
1775 ts_x = INPUT_TS_LEFT;
1777 if(ts_x < INPUT_TS_RIGHT)
1779 ts_x = INPUT_TS_RIGHT;
1782 ts_x = ts_x - INPUT_TS_RIGHT;
1784 *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT);
1785 *disp_x = (DISPLAY_W-1) - *disp_x;
1788 if(ts_y > INPUT_TS_BOT)
1790 ts_y = INPUT_TS_BOT;
1792 if(ts_y < INPUT_TS_TOP)
1794 ts_y = INPUT_TS_TOP;
1797 ts_y = ts_y - INPUT_TS_TOP;
1799 *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP);
1800 /* *disp_y = (DISPLAY_H-1) - *disp_y; */
1804 static void input_event_dump(struct input_event *ie)
1806 printf("input_event:\n"
1812 (unsigned int)ie->time.tv_sec,
1820 static int input_ts_exit(struct graphics_priv *gr)
1830 static gboolean graphics_sdl_idle(void *data)
1832 struct graphics_priv *gr = (struct graphics_priv *)data;
1835 #ifdef LINUX_TOUCHSCREEN
1836 struct input_event ie;
1842 /* generate the initial resize callback, so the gui knows W/H
1844 its unsafe to do this directly inside register_resize_callback;
1845 graphics_gtk does it during Configure, but SDL does not have
1846 an equivalent event, so we use our own flag
1848 if(gr->resize_callback_initial != 0)
1850 if(gr->resize_callback)
1852 gr->resize_callback(gr->resize_callback_data, gr->screen->w, gr->screen->h);
1855 gr->resize_callback_initial = 0;
1858 #ifdef LINUX_TOUCHSCREEN
1861 ss = read(gr->ts_fd, (void *)&ie, sizeof(ie));
1862 if(ss == sizeof(ie))
1864 /* we (usually) get three events on a touchscreen hit:
1866 code =330 [BTN_TOUCH]
1879 once hit, if the contact point changes, we'll get more
1880 EV_ABS (for 1 or both axes), followed by an EV_SYN.
1885 code =330 [BTN_TOUCH]
1894 if(ie.code == BTN_TOUCH)
1896 gr->ts_hit = ie.value;
1906 gr->ts_x = ie.value;
1908 else if(ie.code == 1)
1910 gr->ts_y = ie.value;
1918 input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y);
1920 /* always send MOUSE_MOTION (first) */
1921 if(gr->motion_callback)
1923 gr->motion_callback(gr->motion_callback_data, &p);
1928 if(gr->button_callback)
1930 gr->button_callback(gr->button_callback_data, 1, SDL_BUTTON_LEFT, &p);
1933 else if(gr->ts_hit == 0)
1935 if(gr->button_callback)
1937 gr->button_callback(gr->button_callback_data, 0, SDL_BUTTON_LEFT, &p);
1958 ret = SDL_PollEvent(&ev);
1966 case SDL_MOUSEMOTION:
1970 if(gr->motion_callback)
1972 gr->motion_callback(gr->motion_callback_data, &p);
1979 switch(ev.key.keysym.sym)
1983 key = NAVIT_KEY_LEFT;
1988 key = NAVIT_KEY_RIGHT;
1991 case SDLK_BACKSPACE:
1993 key = NAVIT_KEY_BACKSPACE;
1998 key = NAVIT_KEY_RETURN;
2003 key = NAVIT_KEY_DOWN;
2008 key = NAVIT_KEY_ZOOM_OUT;
2018 key = NAVIT_KEY_ZOOM_IN;
2028 if(gr->keypress_callback)
2032 gr->keypress_callback(gr->keypress_callback_data, keybuf);
2043 case SDL_MOUSEBUTTONDOWN:
2046 printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n",
2056 if(gr->button_callback)
2058 gr->button_callback(gr->button_callback_data, 1, ev.button.button, &p);
2063 case SDL_MOUSEBUTTONUP:
2066 printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n",
2076 if(gr->button_callback)
2078 gr->button_callback(gr->button_callback_data, 0, ev.button.button, &p);
2085 navit_destroy(gr->nav);
2089 case SDL_VIDEORESIZE:
2092 gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE);
2093 if(gr->screen == NULL)
2095 navit_destroy(gr->nav);
2099 if(gr->resize_callback)
2101 gr->resize_callback(gr->resize_callback_data, gr->screen->w, gr->screen->h);
2111 printf("SDL_Event %d\n", ev.type);
2122 static struct graphics_priv *
2123 graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs)
2125 struct graphics_priv *this=g_new0(struct graphics_priv, 1);
2131 ret = SDL_Init(SDL_INIT_VIDEO);
2147 FT_Init_FreeType( &this->library );
2150 /* TODO: xml params for W/H/BPP */
2152 this->screen = SDL_SetVideoMode(DISPLAY_W, DISPLAY_H, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE);
2153 if(this->screen == NULL)
2160 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
2162 SDL_WM_SetCaption("navit", NULL);
2164 #ifdef LINUX_TOUCHSCREEN
2165 input_ts_init(this);
2166 if(this->ts_fd >= 0)
2168 /* mouse cursor does not always display correctly in Linux FB.
2169 anyway, it is unnecessary w/ a touch screen
2180 *meth=graphics_methods;
2182 g_timeout_add(10, graphics_sdl_idle, this);
2184 this->overlay_enable = 1;
2187 if((attr=attr_search(attrs, NULL, attr_antialias)))
2188 this->aa = attr->u.num;
2196 plugin_register_graphics_type("sdl", graphics_sdl_new);