Fix:graphics_sdl:Match keypress_callback in core. Fix col_lev warning
[profile/ivi/navit.git] / navit / navit / graphics / sdl / graphics_sdl.c
1 /* graphics_sdl.c -- barebones sdl graphics layer
2
3    copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org>
4    license: GPLv2
5
6    TODO:
7    - dashed lines
8    - ifdef DEBUG -> dbg()
9    - proper image transparency (libsdl-image xpm does not work)
10    - valgrind
11
12    revision history:
13    2008-06-01 initial
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
18 */
19
20 #include <glib.h>
21 #include "config.h"
22 #include "debug.h"
23 #include "point.h"
24 #include "graphics.h"
25 #include "color.h"
26 #include "plugin.h"
27 #include "window.h"
28 #include "navit.h"
29 #include "keys.h"
30 #include "item.h"
31 #include "attr.h"
32
33 #include <SDL/SDL.h>
34 #include <math.h>
35
36 #define RASTER
37 #undef SDL_SGE
38 #undef SDL_GFX
39 #undef ALPHA
40
41 #undef SDL_TTF
42 #define SDL_IMAGE
43 #undef LINUX_TOUCHSCREEN
44
45 #define DISPLAY_W 800
46 #define DISPLAY_H 600
47
48
49 #undef DEBUG
50 #undef PROFILE
51
52 #define OVERLAY_MAX 8
53
54 #ifdef RASTER
55 #include "raster.h"
56 #endif
57
58 #ifdef SDL_SGE
59 #include <SDL/sge.h>
60 #endif
61
62 #ifdef SDL_GFX
63 #include <SDL/SDL_gfxPrimitives.h>
64 #endif
65
66 #ifdef SDL_TTF
67 #include <SDL/SDL_ttf.h>
68 #else
69 #include <fontconfig/fontconfig.h>
70 #include <ft2build.h>
71 #include FT_FREETYPE_H
72 #include <freetype/ftglyph.h>
73 #endif
74
75 #ifdef SDL_IMAGE
76 #include <SDL/SDL_image.h>
77 #endif
78
79 #ifdef LINUX_TOUCHSCREEN
80 /* we use Linux evdev directly for the touchscreen.  */
81 #include <sys/types.h>
82 #include <sys/stat.h>
83 #include <fcntl.h>
84 #include <linux/input.h>
85 #endif
86
87 #include <alloca.h>
88
89 #ifdef PROFILE
90 #include <sys/time.h>
91 #include <time.h>
92 #endif
93
94
95 /* TODO: union overlay + non-overlay to reduce size */
96 struct graphics_priv;
97 struct graphics_priv {
98     SDL_Surface *screen;
99     int aa;
100
101     /* <overlay> */
102     int overlay_mode;
103     int overlay_x;
104     int overlay_y;
105     struct graphics_priv *overlay_parent;
106     int overlay_idx;
107     /* </overlay> */
108
109     /* <main> */
110     struct graphics_priv *overlay_array[OVERLAY_MAX];
111     int overlay_enable;
112     enum draw_mode_num draw_mode;
113
114         void (*resize_callback)(void *data, int w, int h);
115         void *resize_callback_data;
116         int resize_callback_initial;
117
118         void (*motion_callback)(void *data, struct point *p);
119         void *motion_callback_data;
120
121         void (*button_callback)(void *data, int press, int button, struct point *p);
122         void *button_callback_data;
123
124         void (*keypress_callback)(void *data, char *key);
125         void *keypress_callback_data;
126
127     struct navit *nav;
128
129 #ifdef LINUX_TOUCHSCREEN
130     int ts_fd;
131     int32_t ts_hit;
132     uint32_t ts_x;
133     uint32_t ts_y;
134 #endif
135
136 #ifndef SDL_TTF
137     FT_Library library;
138 #endif
139
140 #ifdef PROFILE
141     struct timeval draw_begin_tv;
142     unsigned long draw_time_peak;
143 #endif
144     /* </main> */
145 };
146
147 static int dummy;
148
149
150 struct graphics_font_priv {
151 #ifdef SDL_TTF
152     TTF_Font *font;
153 #else
154     FT_Face face;
155 #endif
156 };
157
158 struct graphics_gc_priv {
159     struct graphics_priv *gr;
160     Uint8 fore_r;
161     Uint8 fore_g;
162     Uint8 fore_b;
163     Uint8 fore_a;
164     Uint8 back_r;
165     Uint8 back_g;
166     Uint8 back_b;
167     Uint8 back_a;
168     int linewidth;
169 };
170
171 struct graphics_image_priv {
172     SDL_Surface *img;
173 };
174
175
176 #ifdef LINUX_TOUCHSCREEN
177 static int input_ts_exit(struct graphics_priv *gr);
178 #endif
179
180 static void
181 graphics_destroy(struct graphics_priv *gr)
182 {
183     dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode);
184
185     if(gr->overlay_mode)
186     {
187         SDL_FreeSurface(gr->screen);
188         gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL;
189     }
190     else
191     {
192 #ifdef SDL_TTF
193         TTF_Quit();
194 #else
195         FT_Done_FreeType(gr->library);
196         FcFini();
197 #endif
198 #ifdef LINUX_TOUCHSCREEN
199         input_ts_exit(gr);
200 #endif
201         SDL_Quit();
202     }
203
204     g_free(gr);
205 }
206
207 /* graphics_font */
208 static char *fontfamilies[]={
209         "Liberation Mono",
210         "Arial",
211         "DejaVu Sans",
212         "NcrBI4nh",
213         "luximbi",
214         "FreeSans",
215         NULL,
216 };
217
218 static void font_destroy(struct graphics_font_priv *gf)
219 {
220 #ifdef SDL_TTF
221 #else
222     FT_Done_Face(gf->face);
223 #endif
224     g_free(gf);
225 }
226
227 static struct graphics_font_methods font_methods = {
228         font_destroy
229 };
230
231 static struct graphics_font_priv *font_new(struct graphics_priv *gr, struct graphics_font_methods *meth, int size, int flags)
232 {
233     struct graphics_font_priv *gf=g_new(struct graphics_font_priv, 1);
234
235 #ifdef SDL_TTF
236     /* 'size' is in pixels, TTF_OpenFont wants pts. */
237     size = size / 15;
238
239 //    gf->font = TTF_OpenFont("/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf", size);
240     if(flags)
241     {
242         gf->font = TTF_OpenFont("/usr/share/fonts/truetype/LiberationMono-Bold.ttf", size);
243     }
244     else
245     {
246         gf->font = TTF_OpenFont("/usr/share/fonts/truetype/LiberationMono-Regular.ttf", size);
247     }
248
249     if(gf->font == NULL)
250     {
251         g_free(gf);
252         return NULL;
253     }
254
255     if(flags)
256     {
257         /* apparently just means bold right now */
258         TTF_SetFontStyle(gf->font, TTF_STYLE_BOLD);
259     }
260     else
261     {
262         TTF_SetFontStyle(gf->font, TTF_STYLE_NORMAL);
263     }
264 #else
265     /* copy-pasted from graphics_gtk_drawing_area.c
266
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?
269     */
270
271         int exact, found;
272         char **family;
273
274     if(gr->overlay_mode)
275     {
276         gr = gr->overlay_parent;
277     }
278
279         found=0;
280         for (exact=1;!found && exact>=0;exact--) {
281                 family=fontfamilies;
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);
285                         if (flags)
286                                 FcPatternAddInteger(required,FC_WEIGHT,FC_WEIGHT_BOLD);
287                         FcConfigSubstitute(FcConfigGetCurrent(), required, FcMatchFont);
288                         FcDefaultSubstitute(required);
289                         FcResult result;
290                         FcPattern *matched = FcFontMatch(FcConfigGetCurrent(), required, &result);
291                         if (matched) {
292                                 FcValue v1, v2;
293                                 FcChar8 *fontfile;
294                                 int fontindex;
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 );
302                                         found=1;
303                                 }
304                                 FcPatternDestroy(matched);
305                         }
306                         FcPatternDestroy(required);
307                         family++;
308                 }
309         }
310         if (!found) {
311                 g_warning("Failed to load font, no labelling");
312                 g_free(gf);
313                 return NULL;
314         }
315         FT_Set_Char_Size(gf->face, 0, size, 300, 300);
316         FT_Select_Charmap(gf->face, FT_ENCODING_UNICODE);
317 #endif
318
319         *meth=font_methods;
320
321     return gf;
322 }
323
324
325 /* graphics_gc */
326
327 static void
328 gc_destroy(struct graphics_gc_priv *gc)
329 {
330     g_free(gc);
331 }
332
333 static void
334 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
335 {
336 #ifdef DEBUG
337     printf("gc_set_linewidth %p %d\n", gc, w);
338 #endif
339     gc->linewidth = w;
340 }
341
342 static void
343 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
344 {
345     /* TODO */
346 }
347
348 static void
349 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
350 {
351 #ifdef DEBUG
352     printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
353 #endif
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;
358 }
359
360 static void
361 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
362 {
363 #ifdef DEBUG
364     printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b);
365 #endif
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;
370 }
371
372 static struct graphics_gc_methods gc_methods = {
373         gc_destroy,
374         gc_set_linewidth,
375         gc_set_dashes,  
376         gc_set_foreground,      
377         gc_set_background       
378 };
379
380 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
381 {
382     struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1);
383         *meth=gc_methods;
384     gc->gr=gr;
385     gc->linewidth=1; /* upper layer should override anyway? */
386         return gc;
387 }
388
389
390 #if 0 /* unused by core? */
391 static void image_destroy(struct graphics_image_priv *gi)
392 {
393 #ifdef SDL_IMAGE
394     SDL_FreeSurface(gi->img);
395     g_free(gi);
396 #endif
397 }
398
399 static struct graphics_image_methods gi_methods =
400 {
401     image_destroy
402 };
403 #endif
404
405 static struct graphics_image_priv *
406 image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h,
407           struct point *hot)
408 {
409 #ifdef SDL_IMAGE
410     struct graphics_image_priv *gi;
411
412     /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */
413
414     gi = g_new0(struct graphics_image_priv, 1);
415     gi->img = IMG_Load(name);
416     if(gi->img)
417     {
418         /* TBD: improves blit performance? */
419         SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey);
420         *w=gi->img->w;
421         *h=gi->img->h;
422         hot->x=*w/2;
423         hot->y=*h/2;
424     }
425     else
426     {
427         /* TODO: debug "colour parse errors" on xpm */
428         printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError());
429         g_free(gi);
430         gi = NULL;
431     }
432
433     return gi;
434 #else
435     return NULL;
436 #endif
437 }
438
439 static void
440 image_free(struct graphics_priv *gr, struct graphics_image_priv * gi)
441 {
442 #ifdef SDL_IMAGE
443     SDL_FreeSurface(gi->img);
444     g_free(gi);
445 #endif
446 }
447
448 static void
449 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret)
450 {
451         char *p=text;
452         FT_BBox bbox;
453         FT_UInt  glyph_index;
454         FT_GlyphSlot  slot = font->face->glyph;  // a small shortcut
455         FT_Glyph glyph;
456         FT_Matrix matrix;
457         FT_Vector pen;
458         pen.x = 0 * 64;
459         pen.y = 0 * 64;
460         matrix.xx = dx;
461         matrix.xy = dy;
462         matrix.yx = -dy;
463         matrix.yy = dx;
464         int n,len,x=0,y=0;
465
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++ ) {
471                 FT_BBox glyph_bbox;
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;
492         } 
493         if ( bbox.xMin > bbox.xMax ) {
494                 bbox.xMin = 0;
495                 bbox.yMin = 0;
496                 bbox.xMax = 0;
497                 bbox.yMax = 0;
498         }
499         ret[0].x=bbox.xMin;
500         ret[0].y=-bbox.yMin;
501         ret[1].x=bbox.xMin;
502         ret[1].y=-bbox.yMax;
503         ret[2].x=bbox.xMax;
504         ret[2].y=-bbox.yMax;
505         ret[3].x=bbox.xMax;
506         ret[3].y=-bbox.yMin;
507 }
508
509 static void
510 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
511 {
512     Sint16 *vx, *vy;
513     Sint16 x, y;
514     int i;
515
516     vx = alloca(count * sizeof(Sint16));
517     vy = alloca(count * sizeof(Sint16));
518
519     for(i = 0; i < count; i++)
520     {
521         x = (Sint16)p[i].x;
522         y = (Sint16)p[i].y;
523
524 #if 0
525         if(x < 0)
526         {
527             x = 0;
528         }
529         if(y < 0)
530         {
531             y = 0;
532         }
533 #endif
534
535         vx[i] = x;
536         vy[i] = y;
537
538 #ifdef DEBUG
539         printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y);
540 #endif
541     }
542
543 #ifdef RASTER
544     if(gr->aa)
545     {
546         raster_aapolygon(gr->screen, count, vx, vy,
547                        SDL_MapRGB(gr->screen->format,
548                                   gc->fore_r,
549                                   gc->fore_g,
550                                   gc->fore_b));
551     }
552     else
553     {
554         raster_polygon(gr->screen, count, vx, vy,
555                        SDL_MapRGB(gr->screen->format,
556                                   gc->fore_r,
557                                   gc->fore_g,
558                                   gc->fore_b));
559     }
560 #else
561 #ifdef SDL_SGE
562 #ifdef ALPHA
563     sge_FilledPolygonAlpha(gr->screen, count, vx, vy,
564                            SDL_MapRGB(gr->screen->format,
565                                       gc->fore_r,
566                                       gc->fore_g,
567                                       gc->fore_b),
568                            gc->fore_a);
569 #else
570 #ifdef ANTI_ALIAS
571     sge_AAFilledPolygon(gr->screen, count, vx, vy,
572                            SDL_MapRGB(gr->screen->format,
573                                       gc->fore_r,
574                                       gc->fore_g,
575                                       gc->fore_b));
576 #else
577     sge_FilledPolygon(gr->screen, count, vx, vy,
578                            SDL_MapRGB(gr->screen->format,
579                                       gc->fore_r,
580                                       gc->fore_g,
581                                       gc->fore_b));
582 #endif
583 #endif
584 #else
585     filledPolygonRGBA(gr->screen, vx, vy, count,
586                       gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
587 #endif
588 #endif
589 }
590
591
592
593 static void
594 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
595 {
596 #ifdef DEBUG
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);
599 #endif
600     if(w > gr->screen->w)
601     {
602         w = gr->screen->w;
603     }
604     if(h > gr->screen->h)
605     {
606         h = gr->screen->h;
607     }
608
609 #ifdef RASTER
610     raster_rect(gr->screen, p->x, p->y, w, h,
611                 SDL_MapRGB(gr->screen->format,
612                            gc->fore_r,
613                            gc->fore_g,
614                            gc->fore_b));
615 #else
616 #ifdef SDL_SGE
617 #ifdef ALPHA
618     sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h,
619                         SDL_MapRGB(gr->screen->format,
620                                    gc->fore_r,
621                                    gc->fore_g,
622                                    gc->fore_b),
623                         gc->fore_a);
624 #else
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,
628                                    gc->fore_r,
629                                    gc->fore_g,
630                                    gc->fore_b));
631 #endif
632 #else
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);
635 #endif
636 #endif
637
638 }
639
640 static void
641 draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
642 {
643 #if 0
644         if(gc->fore_a != 0xff)
645         {
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);
648         }
649 #endif
650
651     /* FIXME: does not quite match gtk */
652
653     /* hack for osd compass.. why is this needed!? */
654     if(gr->overlay_mode)
655     {
656         r = r / 2;
657     }
658
659 #ifdef RASTER
660         if(gr->aa)
661         {
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));
665         }
666         else
667         {
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));
671         }
672 #else
673 #ifdef SDL_SGE
674 #ifdef ALPHA
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),
678                          gc->fore_a);
679 #else
680 #ifdef ANTI_ALIAS
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));
684 #else
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));
688 #endif
689 #endif
690 #else
691 #ifdef ANTI_ALIAS
692         aacircleRGBA(gr->screen, p->x, p->y, r,
693                    gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
694 #else
695         filledCircleRGBA(gr->screen, p->x, p->y, r,
696                          gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a);
697 #endif
698 #endif
699 #endif
700 }
701
702
703 static void
704 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
705 {
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.
710     */
711 #if 0
712     int i, l, x_inc, y_inc, lw;
713
714     lw = gc->linewidth;
715
716     for(i = 0; i < count-1; i++)
717     {
718 #ifdef DEBUG
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);
720 #endif
721         for(l = 0; l < lw; l++)
722         {
723             /* FIXME: center? */
724 #if 1
725             if(p[i].x != p[i+1].x)
726             {
727                 x_inc = l - (lw/2);
728             }
729             else
730             {
731                 x_inc = 0;
732             }
733
734             if(p[i].y != p[i+1].y)
735             {
736                 y_inc = l - (lw/2);
737             }
738             else
739             {
740                 y_inc = 0;
741             }
742 #else
743             x_inc = 0;
744             y_inc = 0;
745 #endif
746
747 #ifdef ANTI_ALIAS
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);
750 #else
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);
753 #endif
754         }
755     }
756 #else
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
761     */
762     struct point vert[4];
763     int lw = gc->linewidth;
764     //int lw = 1;
765     int i;
766
767     for(i = 0; i < count-1; i++)
768     {
769                 float dx=p[i+1].x-p[i].x;
770                 float dy=p[i+1].y-p[i].y;
771
772 #if 0
773                 float cx=(p[i+1].x+p[i].x)/2;
774                 float cy=(p[i+1].y+p[i].y)/2;
775 #endif
776
777         float angle;
778
779         int x_lw_adj, y_lw_adj;
780
781         if(lw == 1)
782         {
783 #ifdef RASTER
784             if(gr->aa)
785             {
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));
789             }
790             else
791             {
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));
795             }
796 #else
797 #ifdef SDL_SGE
798 #ifdef ALPHA
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),
802                      gc->fore_a);
803 #else
804 #ifdef ANTI_ALIAS
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));
808 #else
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));
812 #endif
813 #endif
814 #else
815 #ifdef ANTI_ALIAS
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);
818 #else
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);
821 #endif
822 #endif
823 #endif
824         }
825         else
826         {
827             /* there is probably a much simpler way but this works ok */
828
829             /* FIXME: float + double mixture */
830             /* FIXME: lrint(round())? */
831             if(dy == 0.0)
832             {
833                 angle = 0.0;
834                 x_lw_adj = 0;
835                 y_lw_adj = round((float)lw/2.0);
836             }
837             else if(dx == 0.0)
838             {
839                 angle = 0.0;
840                 x_lw_adj = round((float)lw/2.0);
841                 y_lw_adj = 0;
842             }
843             else
844             {
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))
849                 {
850                     printf("i=%d\n", i);
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);
854                 }
855             }
856
857             if(p[i+1].x > p[i].x)
858             {
859                 x_lw_adj = -x_lw_adj;
860             }
861             if(p[i+1].y > p[i].y)
862             {
863                 y_lw_adj = -y_lw_adj;
864             }
865
866 #if 0
867             if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2))
868             {
869                 printf("i=%d\n", i);
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);
873             }
874 #endif
875
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;
886
887             draw_polygon(gr, gc, vert, 4);
888
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?
892             */
893
894             /* FIXME: should just draw a half circle */
895
896             /* now some circular endcaps, if the width is over 2 */ 
897             if(lw > 2)
898             {
899                 if(i == 0)
900                 {
901                     draw_circle(gr, gc, &p[i], lw/2);
902                 }
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);
905             }
906         }
907     }
908 #endif
909 }
910
911
912 #ifdef SDL_TTF
913 static void
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)
915 {
916     SDL_Surface *ss;
917     SDL_Color f, b;
918     SDL_Rect r;
919
920 #if 0
921     /* correct? */
922     f.r = bg->back_r;
923     f.g = bg->back_g;
924     f.b = bg->back_b;
925     b.r = bg->back_r;
926     b.g = bg->back_g;
927     b.b = bg->back_b;
928 #else
929     f.r = 0xff;
930     f.g = 0xff;
931     f.b = 0xff;
932     b.r = 0x00;
933     b.g = 0x00;
934     b.b = 0x00;
935 #endif
936
937     /* TODO: dx + dy? */
938
939     ss = TTF_RenderUTF8_Solid(gf->font, text, b);
940     if(ss)
941     {
942         r.x = p->x;
943         r.y = p->y;
944         r.w = ss->w;
945         r.h = ss->h;
946         //SDL_SetAlpha(ss, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
947         SDL_BlitSurface(ss, NULL, gr->screen, &r);
948     }
949 }
950 #else
951
952 struct text_glyph {
953         int x,y,w,h;
954     unsigned char *shadow;
955         unsigned char pixmap[0];
956 };
957
958 struct text_render {
959         int x1,y1;
960         int x2,y2;
961         int x3,y3;
962         int x4,y4;
963         int glyph_count;
964         struct text_glyph *glyph[0];
965 };
966
967 static unsigned char *
968 display_text_render_shadow(struct text_glyph *g)
969 {
970         int mask0, mask1, mask2, x, y, w=g->w, h=g->h;
971         int str=(g->w+9)/8;
972         unsigned char *shadow;
973         unsigned char *p, *pm=g->pixmap;
974
975         shadow=malloc(str*(g->h+2));
976         memset(shadow, 0, str*(g->h+2));
977         for (y = 0 ; y < h ; y++) {
978                 p=shadow+str*y;
979                 mask0=0x4000;
980                 mask1=0xe000;
981                 mask2=0x4000;
982                 for (x = 0 ; x < w ; x++) {
983                         if (pm[x+y*w]) {
984                                 p[0]|=(mask0 >> 8);
985                                 if (mask0 & 0xff)
986                                         p[1]|=mask0;
987
988                                 p[str]|=(mask1 >> 8);
989                                 if (mask1 & 0xff)
990                                         p[str+1]|=mask1;
991                                 p[str*2]|=(mask2 >> 8);
992                                 if (mask2 & 0xff)
993                                         p[str*2+1]|=mask2;
994                         }
995                         mask0 >>= 1;
996                         mask1 >>= 1;
997                         mask2 >>= 1;
998                         if (!((mask0 >> 8) | (mask1 >> 8) | (mask2 >> 8))) {
999                                 mask0<<=8;
1000                                 mask1<<=8;
1001                                 mask2<<=8;
1002                                 p++;
1003                         }
1004                 }
1005         }
1006         return shadow;
1007 }
1008
1009
1010 static struct text_render *
1011 display_text_render(char *text, struct graphics_font_priv *font, int dx, int dy, int x, int y)
1012 {
1013         FT_GlyphSlot  slot = font->face->glyph;  // a small shortcut
1014         FT_Matrix matrix;
1015         FT_Vector pen;
1016         FT_UInt  glyph_index;
1017         int n,len;
1018         struct text_render *ret;
1019         struct text_glyph *curr;
1020         char *p=text;
1021
1022         len=g_utf8_strlen(text, -1);
1023         ret=g_malloc(sizeof(*ret)+len*sizeof(struct text_glyph *));
1024         ret->glyph_count=len;
1025
1026         matrix.xx = dx;
1027         matrix.xy = dy;
1028         matrix.yx = -dy;
1029         matrix.yy = dx;
1030
1031         pen.x = 0 * 64;
1032         pen.y = 0 * 64;
1033         x <<= 6;
1034         y <<= 6;
1035         FT_Set_Transform( font->face, &matrix, &pen );
1036
1037         for ( n = 0; n < len; n++ )
1038         {
1039
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 );
1043
1044                 curr=g_malloc(sizeof(*curr)+slot->bitmap.rows*slot->bitmap.pitch);
1045                 ret->glyph[n]=curr;
1046
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);
1054                 }
1055                 else
1056                         curr->shadow=NULL;
1057 #if 0
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);
1061 #endif
1062 #if 0
1063         printf("slot->advance x %d y %d\n",
1064                slot->advance.x,
1065                slot->advance.y);
1066 #endif
1067
1068                 x += slot->advance.x;
1069                 y -= slot->advance.y;
1070                 p=g_utf8_next_char(p);
1071         }
1072         return ret;
1073 }
1074
1075 #if 0
1076 static void hexdump(unsigned char *buf, unsigned int w, unsigned int h)
1077 {
1078     int x, y;
1079     printf("hexdump %u %u\n", w, h);
1080     for(y = 0; y < h; y++)
1081     {
1082         for(x = 0; x < w; x++)
1083         {
1084             printf("%02x ", buf[y*w+x]);
1085         }
1086         printf("\n");
1087     }
1088 }
1089
1090 static void bitdump(unsigned char *buf, unsigned int w, unsigned int h)
1091 {
1092     int x, pos;
1093     printf("bitdump %u %u\n", w, h);
1094     pos = 0;
1095     for(x = 0; x < h * w; x++)
1096     {
1097         if(buf[pos] & (1 << (x&0x7)))
1098         {
1099             printf("00 ");
1100         }
1101         else
1102         {
1103             printf("ff ");
1104         }
1105
1106         if((x & 0x7) == 0x7)
1107         {
1108             pos++;
1109         }
1110
1111         if((x % w) == (w-1))
1112         {
1113             printf("\n");
1114         }
1115     }
1116     printf("\n");
1117 }
1118 #endif
1119
1120 #if 0
1121 static void sdl_inv_grayscale_pal_set(SDL_Surface *ss)
1122 {
1123     SDL_Color c;
1124     int i;
1125
1126     for(i = 0; i < 256; i++)
1127     {
1128         c.r = 255-i;
1129         c.g = 255-i;
1130         c.b = 255-i;
1131         SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1); 
1132     }
1133 }
1134
1135 static void sdl_scale_pal_set(SDL_Surface *ss, Uint8 r, Uint8 g, Uint8 b)
1136 {
1137     SDL_Color c;
1138     int i;
1139
1140     for(i = 0; i < 256; i++)
1141     {
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); 
1146     }
1147 }
1148 #endif
1149
1150 #if 0
1151 static void sdl_fixed_pal_set(SDL_Surface *ss, Uint8 r, Uint8 g, Uint8 b)
1152 {
1153     SDL_Color c;
1154     int i;
1155
1156     c.r = r;
1157     c.g = g;
1158     c.b = b;
1159     for(i = 0; i < 256; i++)
1160     {
1161         SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1); 
1162     }
1163 }
1164 #endif
1165
1166 static void
1167 display_text_draw(struct text_render *text, struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg)
1168 {
1169     int i, x, y, poff, soff, col_lev;
1170     struct text_glyph *gly, **gp;
1171     Uint32 pix;
1172     Uint8 r, g, b;
1173
1174 #if 0
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);
1178
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);
1182 #endif
1183     
1184     if(bg)
1185     {
1186         col_lev = bg->fore_r + bg->fore_g + bg->fore_b;
1187     }
1188     else
1189     {
1190         col_lev = 0;
1191     }
1192
1193     /* TODO: lock/unlock in draw_mode() to reduce overhead */
1194     SDL_LockSurface(gr->screen);
1195         gp=text->glyph;
1196         i=text->glyph_count;
1197         while (i-- > 0)
1198         {
1199                 gly=*gp++;
1200                 if (gly->w && gly->h)
1201         {
1202 #if 0
1203             if(gly->shadow && bg)
1204             {
1205                 hexdump(gly->pixmap, gly->w, gly->h);
1206                 bitdump(gly->shadow, gly->w+2, gly->h+2);    
1207             }
1208 #endif
1209
1210             for(y = 0; y < gly->h + 2; y++)
1211             {
1212                 if(gly->y - 1 + y < 0)
1213                 {
1214                     continue;
1215                 }
1216
1217                 if(((gly->y-1) + y) >= gr->screen->h)
1218                 {
1219                     break;
1220                 }
1221
1222                 for(x = 0; x < gly->w + 2; x++)
1223                 {
1224                     if(gly->x - 1 + x < 0)
1225                     {
1226                         continue;
1227                     }
1228
1229                     if(((gly->x-1) + x) >= gr->screen->w)
1230                     {
1231                         break;
1232                     }
1233
1234                     poff = gr->screen->w * ((gly->y-1) + y) + ((gly->x-1) + x);
1235                     poff = poff * gr->screen->format->BytesPerPixel;
1236
1237                     switch(gr->screen->format->BytesPerPixel)
1238                     {
1239                         case 2:
1240                         {
1241                             pix = *(Uint16 *)((Uint8*)gr->screen->pixels + poff);
1242                             break;
1243                         }
1244                         case 4:
1245                         {
1246                             pix = *(Uint32 *)((Uint8*)gr->screen->pixels + poff);
1247                             break;
1248                         }
1249                         default:
1250                         {
1251                             pix = 0;
1252                             break;
1253                         }
1254                     }
1255
1256                     SDL_GetRGB(pix,
1257                                gr->screen->format,
1258                                &r,
1259                                &g,
1260                                &b);
1261
1262 #ifdef DEBUG
1263                     printf("%u %u -> %u off\n",
1264                            gly->x,
1265                            gly->y,
1266                            off);
1267
1268                     printf("%u,%u: %u %u %u in\n",
1269                            x, y,
1270                            r, g, b, off);
1271 #endif
1272
1273
1274
1275                     if(gly->shadow && bg)
1276                     {
1277                         soff = (8 * ((gly->w+9)/8) * y) + x;
1278                         pix = gly->shadow[soff/8];
1279
1280                         if(pix & (1 << (7-(soff&0x7))))
1281                         {
1282                             if(col_lev >= 3*0x80)
1283                             {
1284                                 r |= bg->fore_r;
1285                                 g |= bg->fore_g;
1286                                 b |= bg->fore_b;
1287                             }
1288                             else
1289                             {
1290                                 r &= ~bg->fore_r;
1291                                 g &= ~bg->fore_g;
1292                                 b &= ~bg->fore_b;
1293                             }
1294                         }
1295                     }
1296
1297                     /* glyph */
1298                     if((x > 0) && (x <= gly->w) &&
1299                        (y > 0) && (y <= gly->h))
1300                     {
1301                         if(bg && (col_lev >= 3*0x80))
1302                         {
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)];
1306                         }
1307                         else
1308                         {
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)];
1312                         }
1313                     }
1314
1315 #ifdef DEBUG
1316                     printf("%u,%u: %u %u %u out\n",
1317                            x, y,
1318                            r, g, b);
1319 #endif
1320
1321                     pix = SDL_MapRGB(gr->screen->format,
1322                                      r,
1323                                      g,
1324                                      b);
1325
1326                     switch(gr->screen->format->BytesPerPixel)
1327                     {
1328                         case 2:
1329                         {
1330                             *(Uint16 *)((Uint8*)gr->screen->pixels + poff) = pix;
1331                             break;
1332                         }
1333                         case 4:
1334                         {
1335                             *(Uint32 *)((Uint8*)gr->screen->pixels + poff) = pix;
1336                             break;
1337                         }
1338                         default:
1339                         {
1340                             break;
1341                         }
1342                     }
1343                 }
1344             }
1345
1346             //dbg(0, "glyph %d %d %d %d\n", g->x, g->y, g->w, g->h);
1347         }
1348         }
1349     SDL_UnlockSurface(gr->screen);
1350 }
1351
1352 static void
1353 display_text_free(struct text_render *text)
1354 {
1355         int i;
1356         struct text_glyph **gp;
1357
1358         gp=text->glyph;
1359         i=text->glyph_count;
1360         while (i-- > 0) {
1361                 if ((*gp)->shadow) {
1362            free((*gp)->shadow);
1363             }   
1364                 g_free(*gp++);
1365         }
1366         g_free(text);
1367 }
1368
1369 static void
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)
1371 {
1372         struct text_render *t;
1373
1374         if (! font)
1375                 return;
1376
1377 #if 0
1378         if (bg) {
1379                 gdk_gc_set_function(fg->gc, GDK_AND_INVERT);
1380                 gdk_gc_set_function(bg->gc, GDK_OR);
1381         }
1382 #endif
1383
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);
1387 #if 0
1388         if (bg) {
1389                 gdk_gc_set_function(fg->gc, GDK_COPY);
1390                 gdk_gc_set_function(bg->gc, GDK_COPY);
1391         }
1392 #endif
1393 }
1394 #endif
1395
1396
1397
1398 static void
1399 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
1400 {
1401 #ifdef SDL_IMAGE
1402     SDL_Rect r;
1403
1404     r.x = p->x;
1405     r.y = p->y;
1406     r.w = img->img->w;
1407     r.h = img->img->h;
1408
1409     SDL_BlitSurface(img->img, NULL, gr->screen, &r);
1410 #endif
1411 }
1412
1413 static void
1414 draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
1415 {
1416     /* TODO */
1417 }
1418
1419 static void
1420 draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
1421 {
1422 #ifdef DEBUG
1423     printf("draw_restore\n");
1424 #endif
1425 }
1426
1427 static void
1428 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
1429 {
1430 #ifdef DEBUG
1431     printf("background_gc\n");
1432 #endif
1433 }
1434
1435
1436 static void
1437 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
1438 {
1439 #ifdef PROFILE
1440     struct timeval now;
1441     unsigned long elapsed;
1442 #endif
1443     struct graphics_priv *ov;
1444     SDL_Rect rect;
1445     int i;
1446
1447     if(gr->overlay_mode)
1448     {
1449         /* will be drawn below */
1450     }
1451     else
1452     {
1453 #ifdef DEBUG
1454         printf("draw_mode: %d\n", mode);
1455 #endif
1456
1457 #ifdef PROFILE
1458         if(mode == draw_mode_begin)
1459         {
1460             gettimeofday(&gr->draw_begin_tv, NULL);
1461         }
1462 #endif
1463
1464         if(mode == draw_mode_end)
1465         {
1466             if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable)
1467             {
1468                 for(i = 0; i < OVERLAY_MAX; i++)
1469                 {
1470                     ov = gr->overlay_array[i];
1471                     if(ov)
1472                     {
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,
1478                                         gr->screen, &rect);
1479                     }
1480                 }
1481             }
1482
1483             SDL_Flip(gr->screen);
1484
1485 #ifdef PROFILE
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)
1490             {
1491                dbg(0, "draw elapsed %u usec\n", elapsed);
1492                gr->draw_time_peak = elapsed;
1493             }
1494 #endif
1495         }
1496
1497         gr->draw_mode = mode;
1498     }
1499 }
1500
1501 static struct graphics_methods graphics_methods;
1502
1503 static struct graphics_priv *
1504 overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h)
1505 {
1506     struct graphics_priv *ov;
1507     int i, x, y;
1508
1509     for(i = 0; i < OVERLAY_MAX; i++)
1510     {
1511         if(gr->overlay_array[i] == NULL)
1512         {
1513             break;
1514         }
1515     }
1516     if(i == OVERLAY_MAX)
1517     {
1518         dbg(0, "too many overlays! increase OVERLAY_MAX\n");
1519         return NULL;
1520     }
1521     dbg(0, "x %d y %d\n", p->x, p->y);
1522
1523     if(p->x < 0)
1524     {
1525         x = gr->screen->w + p->x;
1526     }
1527     else
1528     {
1529         x = p->x;
1530     }
1531     if(p->y < 0)
1532     {
1533         y = gr->screen->h + p->y;
1534     }
1535     else
1536     {
1537         y = p->y;
1538     }
1539
1540     dbg(1, "overlay_new %d %d %d %u %u\n", i,
1541         x,
1542         y,
1543         w,
1544         h);
1545
1546     ov = g_new0(struct graphics_priv, 1);
1547
1548     ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, 
1549                                       w, h,
1550 #if 1 
1551                                       gr->screen->format->BitsPerPixel,
1552                                       gr->screen->format->Rmask,
1553                                       gr->screen->format->Gmask,
1554                                       gr->screen->format->Bmask,
1555                                       0x00000000);
1556 #else
1557                                       0x00ff0000,
1558                                       0x0000ff00,
1559                                       0x000000ff,
1560                                       0xff000000);
1561 #endif
1562     SDL_SetAlpha(ov->screen, SDL_SRCALPHA, 128);
1563
1564     ov->overlay_mode = 1;
1565     ov->overlay_x = x;
1566     ov->overlay_y = y;
1567     ov->overlay_parent = gr;
1568     ov->overlay_idx = i;
1569
1570     gr->overlay_array[i] = ov;
1571
1572         *meth=graphics_methods;
1573
1574     return ov;
1575 }
1576
1577 static void overlay_disable(struct graphics_priv *gr, int disable)
1578 {
1579     gr->overlay_enable = !disable;
1580 }
1581
1582
1583 static int window_fullscreen(struct window *win, int on)
1584 {
1585     /* TODO */
1586     return 0;
1587 }
1588
1589 static struct window sdl_win =
1590 {
1591     NULL,
1592     window_fullscreen
1593
1594 };
1595
1596 static void *
1597 get_data(struct graphics_priv *this, char *type)
1598 {
1599     printf("get_data: %s\n", type);
1600
1601     if(strcmp(type, "window") == 0)
1602     {
1603         return &sdl_win;
1604     }
1605     else
1606     {
1607         return &dummy;
1608     }
1609 }
1610
1611
1612
1613 static void
1614 register_resize_callback(struct graphics_priv *this, void (*callback)(void *data, int w, int h), void *data)
1615 {
1616         this->resize_callback=callback;
1617         this->resize_callback_data=data;
1618     this->resize_callback_initial=1;
1619 }
1620
1621 static void
1622 register_motion_callback(struct graphics_priv *this, void (*callback)(void *data, struct point *p), void *data)
1623 {
1624         this->motion_callback=callback;
1625         this->motion_callback_data=data;
1626 }
1627
1628 static void
1629 register_button_callback(struct graphics_priv *this, void (*callback)(void *data, int press, int button, struct point *p), void *data)
1630 {
1631         this->button_callback=callback;
1632         this->button_callback_data=data;
1633 }
1634
1635 static void
1636 register_keypress_callback(struct graphics_priv *this,
1637                             void (*callback)(void *data, char *key),
1638                             void *data)
1639 {
1640     this->keypress_callback=callback;
1641     this->keypress_callback_data=data;
1642 }
1643
1644 static struct graphics_methods graphics_methods = {
1645         graphics_destroy,
1646         draw_mode,
1647         draw_lines,
1648         draw_polygon,
1649         draw_rectangle,
1650         draw_circle,
1651         draw_text,
1652         draw_image,
1653         draw_image_warp,
1654         draw_restore,
1655         font_new,
1656         gc_new,
1657         background_gc,
1658         overlay_new,
1659         image_new,
1660         get_data,
1661         register_resize_callback,
1662         register_button_callback,
1663         register_motion_callback,
1664         image_free,
1665         get_text_bbox,
1666         overlay_disable,
1667         register_keypress_callback
1668 };
1669
1670
1671 #ifdef LINUX_TOUCHSCREEN
1672
1673 #define EVFN "/dev/input/eventX"
1674
1675 static int input_ts_init(struct graphics_priv *gr)
1676 {
1677     struct input_id ii;
1678     char fn[32];
1679 #if 0
1680     char name[64];
1681 #endif
1682     int n, fd, ret;
1683
1684     gr->ts_fd = -1;
1685     gr->ts_hit = -1;
1686     gr->ts_x = 0;
1687     gr->ts_y = 0;
1688
1689     strcpy(fn, EVFN);
1690     n = 0;
1691     while(1)
1692     {
1693         fn[sizeof(EVFN)-2] = '0' + n;
1694
1695         fd = open(fn, O_RDONLY);
1696         if(fd >= 0)
1697         {
1698 #if 0
1699             ret = ioctl(fd, EVIOCGNAME(64), (void *)name);
1700             if(ret > 0)
1701             {
1702                 printf("input_ts: %s\n", name);
1703             }
1704 #endif
1705
1706             ret = ioctl(fd, EVIOCGID, (void *)&ii);
1707             if(ret == 0)
1708             {
1709 #if 1
1710                 printf("bustype %04x vendor %04x product %04x version %04x\n",
1711                        ii.bustype,
1712                        ii.vendor,
1713                        ii.product,
1714                        ii.version);
1715 #endif
1716
1717                 if((ii.bustype == BUS_USB) &&
1718                    (ii.vendor == 0x0eef) &&
1719                    (ii.product == 0x0001))
1720                 {
1721                     ret = fcntl(fd, F_SETFL, O_NONBLOCK);
1722                     if(ret == 0)
1723                     {
1724                         gr->ts_fd = fd;
1725                     }
1726                     else
1727                     {
1728                         close(fd);
1729                     }
1730
1731                     break;
1732                 }
1733             }
1734
1735             close(fd);
1736         }
1737
1738         n = n + 1;
1739
1740         /* FIXME: should check all 32 minors */
1741         if(n == 10)
1742         {
1743             /* not found */
1744             ret = -1;
1745             break;
1746         }
1747     }
1748
1749     return ret;
1750 }
1751
1752
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)
1756 {
1757     /* Dynamix 7" (eGalax TS)
1758        top left  = 1986,103
1759        top right =   61,114
1760        bot left  = 1986,1897
1761        bot right =   63,1872
1762
1763        calibrate your TS using input_event_dump
1764        and touching all four corners. use the most extreme values. 
1765     */
1766
1767 #define INPUT_TS_LEFT 1978
1768 #define INPUT_TS_RIGHT  48
1769 #define INPUT_TS_TOP   115
1770 #define INPUT_TS_BOT  1870
1771
1772     /* clamp first */
1773     if(ts_x > INPUT_TS_LEFT)
1774     {
1775         ts_x = INPUT_TS_LEFT;
1776     }
1777     if(ts_x < INPUT_TS_RIGHT)
1778     {
1779         ts_x = INPUT_TS_RIGHT;
1780     }
1781
1782     ts_x = ts_x - INPUT_TS_RIGHT;
1783
1784     *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT);
1785     *disp_x = (DISPLAY_W-1) - *disp_x;
1786
1787
1788     if(ts_y > INPUT_TS_BOT)
1789     {
1790         ts_y = INPUT_TS_BOT;
1791     }
1792     if(ts_y < INPUT_TS_TOP)
1793     {
1794         ts_y = INPUT_TS_TOP;
1795     }
1796
1797     ts_y = ts_y - INPUT_TS_TOP;
1798
1799     *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP);
1800 /*  *disp_y = (DISPLAY_H-1) - *disp_y; */
1801 }
1802
1803 #if 0
1804 static void input_event_dump(struct input_event *ie)
1805 {
1806     printf("input_event:\n"
1807            "\ttv_sec\t%u\n"
1808            "\ttv_usec\t%lu\n"
1809            "\ttype\t%u\n"
1810            "\tcode\t%u\n"
1811            "\tvalue\t%d\n",
1812            (unsigned int)ie->time.tv_sec,
1813            ie->time.tv_usec,
1814            ie->type,
1815            ie->code,
1816            ie->value);
1817 }
1818 #endif
1819
1820 static int input_ts_exit(struct graphics_priv *gr)
1821 {
1822     close(gr->ts_fd);
1823     gr->ts_fd = -1;
1824
1825     return 0;
1826 }
1827 #endif
1828
1829
1830 static gboolean graphics_sdl_idle(void *data)
1831 {
1832     struct graphics_priv *gr = (struct graphics_priv *)data;
1833     struct point p;
1834     SDL_Event ev;
1835 #ifdef LINUX_TOUCHSCREEN
1836     struct input_event ie;
1837     ssize_t ss;
1838 #endif
1839     int ret, key;
1840     char keybuf[2];
1841
1842     /* generate the initial resize callback, so the gui knows W/H
1843
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
1847     */
1848     if(gr->resize_callback_initial != 0)
1849     {
1850         if(gr->resize_callback)
1851         {
1852             gr->resize_callback(gr->resize_callback_data, gr->screen->w, gr->screen->h);
1853         }
1854
1855         gr->resize_callback_initial = 0;
1856     }
1857
1858 #ifdef LINUX_TOUCHSCREEN
1859     if(gr->ts_fd >= 0)
1860     {
1861         ss = read(gr->ts_fd, (void *)&ie, sizeof(ie));
1862         if(ss == sizeof(ie))
1863         {
1864             /* we (usually) get three events on a touchscreen hit:
1865               1: type =EV_KEY
1866                  code =330 [BTN_TOUCH]
1867                  value=1
1868
1869               2: type =EV_ABS
1870                  code =0 [X]
1871                  value=X pos
1872
1873               3: type =EV_ABS
1874                  code =1 [Y]
1875                  value=Y pos
1876
1877               4: type =EV_SYN
1878
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.
1881
1882               and, on a lift:
1883
1884               5: type =EV_KEY
1885                  code =330 [BTN_TOUCH]
1886                  value=0
1887
1888               6: type =EV_SYN
1889             */
1890             switch(ie.type)
1891             {
1892                 case EV_KEY:
1893                 {
1894                     if(ie.code == BTN_TOUCH)
1895                     {
1896                         gr->ts_hit = ie.value;
1897                     }
1898
1899                     break;
1900                 }
1901
1902                 case EV_ABS:
1903                 {
1904                     if(ie.code == 0)
1905                     {
1906                         gr->ts_x = ie.value;
1907                     }
1908                     else if(ie.code == 1)
1909                     {
1910                         gr->ts_y = ie.value;
1911                     }
1912
1913                     break;
1914                 }
1915
1916                 case EV_SYN:
1917                 {
1918                     input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y);
1919
1920                     /* always send MOUSE_MOTION (first) */
1921                     if(gr->motion_callback)
1922                     {
1923                         gr->motion_callback(gr->motion_callback_data, &p);
1924                     }
1925
1926                     if(gr->ts_hit > 0)
1927                     {
1928                         if(gr->button_callback)
1929                         {
1930                             gr->button_callback(gr->button_callback_data, 1, SDL_BUTTON_LEFT, &p);
1931                         }
1932                     }
1933                     else if(gr->ts_hit == 0)
1934                     {
1935                         if(gr->button_callback)
1936                         {
1937                             gr->button_callback(gr->button_callback_data, 0, SDL_BUTTON_LEFT, &p);
1938                         }
1939                     }
1940
1941                     /* reset ts_hit */
1942                     gr->ts_hit = -1;
1943
1944                     break;
1945                 }
1946
1947                 default:
1948                 {
1949                     break;
1950                 }
1951             }
1952         }
1953     }
1954 #endif
1955
1956     while(1)
1957     {
1958         ret = SDL_PollEvent(&ev);
1959         if(ret == 0)
1960         {
1961             break;
1962         }
1963
1964         switch(ev.type)
1965         {
1966             case SDL_MOUSEMOTION:
1967             {
1968                 p.x = ev.motion.x;
1969                 p.y = ev.motion.y;
1970                 if(gr->motion_callback)
1971                 {
1972                     gr->motion_callback(gr->motion_callback_data, &p);
1973                 }
1974                 break;
1975             }
1976
1977             case SDL_KEYDOWN:
1978             {
1979                 switch(ev.key.keysym.sym)
1980                 {
1981                     case SDLK_LEFT:
1982                     {
1983                         key = NAVIT_KEY_LEFT;
1984                         break;
1985                     }
1986                     case SDLK_RIGHT:
1987                     {
1988                         key = NAVIT_KEY_RIGHT;
1989                         break;
1990                     }
1991                     case SDLK_BACKSPACE:
1992                     {
1993                         key = NAVIT_KEY_BACKSPACE;
1994                         break;
1995                     }
1996                     case SDLK_RETURN:
1997                     {
1998                         key = NAVIT_KEY_RETURN;
1999                         break;
2000                     }
2001                     case SDLK_DOWN:
2002                     {
2003                         key = NAVIT_KEY_DOWN;
2004                         break;
2005                     }
2006                     case SDLK_PAGEUP:
2007                     {
2008                         key = NAVIT_KEY_ZOOM_OUT;
2009                         break;
2010                     }
2011                     case SDLK_UP:
2012                     {
2013                         key = NAVIT_KEY_UP;
2014                         break;
2015                     }
2016                     case SDLK_PAGEDOWN:
2017                     {
2018                         key = NAVIT_KEY_ZOOM_IN;
2019                         break;
2020                     }
2021                     default:
2022                     {
2023                         key = 0;
2024                         break;
2025                     }
2026                 }
2027
2028                 if(gr->keypress_callback)
2029                 {
2030                     keybuf[0] = key;
2031                     keybuf[1] = '\0';
2032                     gr->keypress_callback(gr->keypress_callback_data, keybuf);
2033                 }
2034
2035                 break;
2036             }
2037
2038             case SDL_KEYUP:
2039             {
2040                 break;
2041             }
2042
2043             case SDL_MOUSEBUTTONDOWN:
2044             {
2045 #ifdef DEBUG
2046                 printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n",
2047                        ev.button.which,
2048                        ev.button.button,
2049                        ev.button.state,
2050                        ev.button.x,
2051                        ev.button.y);
2052 #endif
2053
2054                 p.x = ev.button.x;
2055                 p.y = ev.button.y;
2056                 if(gr->button_callback)
2057                 {
2058                     gr->button_callback(gr->button_callback_data, 1, ev.button.button, &p);
2059                 }
2060                 break;
2061             }
2062
2063             case SDL_MOUSEBUTTONUP:
2064             {
2065 #ifdef DEBUG
2066                 printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n",
2067                        ev.button.which,
2068                        ev.button.button,
2069                        ev.button.state,
2070                        ev.button.x,
2071                        ev.button.y);
2072 #endif
2073
2074                 p.x = ev.button.x;
2075                 p.y = ev.button.y;
2076                 if(gr->button_callback)
2077                 {
2078                     gr->button_callback(gr->button_callback_data, 0, ev.button.button, &p);
2079                 }
2080                 break;
2081             }
2082
2083             case SDL_QUIT:
2084             {
2085                 navit_destroy(gr->nav);
2086                 break;
2087             }
2088
2089             case SDL_VIDEORESIZE:
2090             {
2091
2092                 gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE);
2093                 if(gr->screen == NULL)
2094                 {
2095                     navit_destroy(gr->nav);
2096                 }
2097                 else
2098                 {
2099                     if(gr->resize_callback)
2100                     {
2101                         gr->resize_callback(gr->resize_callback_data, gr->screen->w, gr->screen->h);
2102                     }
2103                 }
2104
2105                 break;
2106             }
2107
2108             default:
2109             {
2110 #ifdef DEBUG
2111                 printf("SDL_Event %d\n", ev.type);
2112 #endif
2113                 break;
2114             }
2115         }
2116     }
2117
2118     return TRUE;
2119 }
2120
2121
2122 static struct graphics_priv *
2123 graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs)
2124 {
2125     struct graphics_priv *this=g_new0(struct graphics_priv, 1);
2126     struct attr *attr;
2127     int ret;
2128
2129     this->nav = nav;
2130
2131     ret = SDL_Init(SDL_INIT_VIDEO);
2132     if(ret < 0)
2133     {
2134         g_free(this);
2135         return NULL;
2136     }
2137
2138 #ifdef SDL_TTF
2139     ret = TTF_Init();
2140     if(ret < 0)
2141     {
2142         g_free(this);
2143         SDL_Quit();
2144         return NULL;
2145     }
2146 #else
2147     FT_Init_FreeType( &this->library );
2148 #endif
2149
2150     /* TODO: xml params for W/H/BPP */
2151
2152     this->screen = SDL_SetVideoMode(DISPLAY_W, DISPLAY_H, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE);
2153     if(this->screen == NULL)
2154     {
2155         g_free(this);
2156         SDL_Quit();
2157         return NULL;
2158     }
2159
2160     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
2161
2162     SDL_WM_SetCaption("navit", NULL);
2163
2164 #ifdef LINUX_TOUCHSCREEN
2165     input_ts_init(this);
2166     if(this->ts_fd >= 0)
2167     {
2168         /* mouse cursor does not always display correctly in Linux FB.
2169            anyway, it is unnecessary w/ a touch screen
2170         */
2171         SDL_ShowCursor(0);
2172     }
2173 #endif
2174
2175 #ifdef SDL_SGE
2176     sge_Update_OFF();
2177     sge_Lock_ON();
2178 #endif
2179
2180         *meth=graphics_methods;
2181
2182     g_timeout_add(10, graphics_sdl_idle, this);
2183
2184     this->overlay_enable = 1;
2185
2186     this->aa = 1;
2187     if((attr=attr_search(attrs, NULL, attr_antialias)))
2188         this->aa = attr->u.num;
2189
2190     return this;
2191 }
2192
2193 void
2194 plugin_init(void)
2195 {
2196         plugin_register_graphics_type("sdl", graphics_sdl_new);
2197 }
2198