diff options
Diffstat (limited to 'graphics/sdl/graphics_sdl.c')
-rw-r--r-- | graphics/sdl/graphics_sdl.c | 2146 |
1 files changed, 2146 insertions, 0 deletions
diff --git a/graphics/sdl/graphics_sdl.c b/graphics/sdl/graphics_sdl.c new file mode 100644 index 00000000..c30bc121 --- /dev/null +++ b/graphics/sdl/graphics_sdl.c @@ -0,0 +1,2146 @@ +/* graphics_sdl.c -- barebones sdl graphics layer + + copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org> + license: GPLv2 + + TODO: + - dashed lines + - ifdef DEBUG -> dbg() + - proper image transparency (libsdl-image xpm does not work) + - valgrind + + revision history: + 2008-06-01 initial + 2008-06-15 SDL_DOUBLEBUF+SDL_Flip for linux fb. fix FT leaks. + 2008-06-18 defer initial resize_callback + 2008-06-21 linux touchscreen + 2008-07-04 custom rastering +*/ + +#include <glib.h> +#include "config.h" +#include "debug.h" +#include "point.h" +#include "graphics.h" +#include "color.h" +#include "plugin.h" +#include "window.h" +#include "navit.h" +#include "keys.h" +#include "item.h" +#include "attr.h" +#include "callback.h" + +#include <SDL/SDL.h> +#include <math.h> + +#define RASTER +#undef SDL_SGE +#undef SDL_GFX +#undef ALPHA + +#undef SDL_TTF +#define SDL_IMAGE +#undef LINUX_TOUCHSCREEN + +#define DISPLAY_W 800 +#define DISPLAY_H 600 + + +#undef DEBUG +#undef PROFILE + +#define OVERLAY_MAX 16 + +#ifdef RASTER +#include "raster.h" +#endif + +#ifdef SDL_SGE +#include <SDL/sge.h> +#endif + +#ifdef SDL_GFX +#include <SDL/SDL_gfxPrimitives.h> +#endif + +#ifdef SDL_TTF +#include <SDL/SDL_ttf.h> +#else +#include <fontconfig/fontconfig.h> +#include <ft2build.h> +#include FT_FREETYPE_H +#include <freetype/ftglyph.h> +#endif +#include <event.h> + +#ifdef SDL_IMAGE +#include <SDL/SDL_image.h> +#endif + +#ifdef LINUX_TOUCHSCREEN +/* we use Linux evdev directly for the touchscreen. */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <linux/input.h> +#endif + +#include <alloca.h> + +#ifdef PROFILE +#include <sys/time.h> +#include <time.h> +#endif + + +/* TODO: union overlay + non-overlay to reduce size */ +struct graphics_priv; +struct graphics_priv { + SDL_Surface *screen; + int aa; + + /* <overlay> */ + int overlay_mode; + int overlay_x; + int overlay_y; + struct graphics_priv *overlay_parent; + int overlay_idx; + /* </overlay> */ + + /* <main> */ + struct graphics_priv *overlay_array[OVERLAY_MAX]; + int overlay_enable; + enum draw_mode_num draw_mode; + + int resize_callback_initial; + + struct navit *nav; + struct callback_list *cbl; + +#ifdef LINUX_TOUCHSCREEN + int ts_fd; + int32_t ts_hit; + uint32_t ts_x; + uint32_t ts_y; +#endif + +#ifndef SDL_TTF + FT_Library library; +#endif + +#ifdef PROFILE + struct timeval draw_begin_tv; + unsigned long draw_time_peak; +#endif + /* </main> */ +}; + +static int dummy; + + +struct graphics_font_priv { +#ifdef SDL_TTF + TTF_Font *font; +#else + FT_Face face; +#endif +}; + +struct graphics_gc_priv { + struct graphics_priv *gr; + Uint8 fore_r; + Uint8 fore_g; + Uint8 fore_b; + Uint8 fore_a; + Uint8 back_r; + Uint8 back_g; + Uint8 back_b; + Uint8 back_a; + int linewidth; +}; + +struct graphics_image_priv { + SDL_Surface *img; +}; + + +#ifdef LINUX_TOUCHSCREEN +static int input_ts_exit(struct graphics_priv *gr); +#endif + +static void +graphics_destroy(struct graphics_priv *gr) +{ + dbg(0, "graphics_destroy %p %u\n", gr, gr->overlay_mode); + + if(gr->overlay_mode) + { + SDL_FreeSurface(gr->screen); + gr->overlay_parent->overlay_array[gr->overlay_idx] = NULL; + } + else + { +#ifdef SDL_TTF + TTF_Quit(); +#else + FT_Done_FreeType(gr->library); + FcFini(); +#endif +#ifdef LINUX_TOUCHSCREEN + input_ts_exit(gr); +#endif + SDL_Quit(); + } + + g_free(gr); +} + +/* graphics_font */ +static char *fontfamilies[]={ + "Liberation Mono", + "Arial", + "DejaVu Sans", + "NcrBI4nh", + "luximbi", + "FreeSans", + NULL, +}; + +static void font_destroy(struct graphics_font_priv *gf) +{ +#ifdef SDL_TTF +#else + FT_Done_Face(gf->face); +#endif + g_free(gf); +} + +static struct graphics_font_methods font_methods = { + font_destroy +}; + +static struct graphics_font_priv *font_new(struct graphics_priv *gr, struct graphics_font_methods *meth, char *fontfamily, int size, int flags) +{ + struct graphics_font_priv *gf=g_new(struct graphics_font_priv, 1); + +#ifdef SDL_TTF + /* 'size' is in pixels, TTF_OpenFont wants pts. */ + size = size / 15; + +// gf->font = TTF_OpenFont("/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf", size); + if(flags) + { + gf->font = TTF_OpenFont("/usr/share/fonts/truetype/LiberationMono-Bold.ttf", size); + } + else + { + gf->font = TTF_OpenFont("/usr/share/fonts/truetype/LiberationMono-Regular.ttf", size); + } + + if(gf->font == NULL) + { + g_free(gf); + return NULL; + } + + if(flags) + { + /* apparently just means bold right now */ + TTF_SetFontStyle(gf->font, TTF_STYLE_BOLD); + } + else + { + TTF_SetFontStyle(gf->font, TTF_STYLE_NORMAL); + } +#else + /* copy-pasted from graphics_gtk_drawing_area.c + + FIXME: figure out some way to share this b/t gtk and sdl graphics plugin. + new 'font' plugin type that uses an abstracted bitmap fmt to pass to gfx plugin? + */ + + int exact, found; + char **family; + + if(gr->overlay_mode) + { + gr = gr->overlay_parent; + } + + found=0; + for (exact=1;!found && exact>=0;exact--) { + family=fontfamilies; + while (*family && !found) { + dbg(1, "Looking for font family %s. exact=%d\n", *family, exact); + FcPattern *required = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, *family, NULL); + if (flags) + FcPatternAddInteger(required,FC_WEIGHT,FC_WEIGHT_BOLD); + FcConfigSubstitute(FcConfigGetCurrent(), required, FcMatchFont); + FcDefaultSubstitute(required); + FcResult result; + FcPattern *matched = FcFontMatch(FcConfigGetCurrent(), required, &result); + if (matched) { + FcValue v1, v2; + FcChar8 *fontfile; + int fontindex; + FcPatternGet(required, FC_FAMILY, 0, &v1); + FcPatternGet(matched, FC_FAMILY, 0, &v2); + FcResult r1 = FcPatternGetString(matched, FC_FILE, 0, &fontfile); + FcResult r2 = FcPatternGetInteger(matched, FC_INDEX, 0, &fontindex); + if ((r1 == FcResultMatch) && (r2 == FcResultMatch) && (FcValueEqual(v1,v2) || !exact)) { + dbg(2, "About to load font from file %s index %d\n", fontfile, fontindex); + FT_New_Face( gr->library, (char *)fontfile, fontindex, &gf->face ); + found=1; + } + FcPatternDestroy(matched); + } + FcPatternDestroy(required); + family++; + } + } + if (!found) { + g_warning("Failed to load font, no labelling"); + g_free(gf); + return NULL; + } + FT_Set_Char_Size(gf->face, 0, size, 300, 300); + FT_Select_Charmap(gf->face, FT_ENCODING_UNICODE); +#endif + + *meth=font_methods; + + return gf; +} + + +/* graphics_gc */ + +static void +gc_destroy(struct graphics_gc_priv *gc) +{ + g_free(gc); +} + +static void +gc_set_linewidth(struct graphics_gc_priv *gc, int w) +{ +#ifdef DEBUG + printf("gc_set_linewidth %p %d\n", gc, w); +#endif + gc->linewidth = w; +} + +static void +gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n) +{ + /* TODO */ +} + +static void +gc_set_foreground(struct graphics_gc_priv *gc, struct color *c) +{ +#ifdef DEBUG + printf("gc_set_foreground: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b); +#endif + gc->fore_r = c->r/256; + gc->fore_g = c->g/256; + gc->fore_b = c->b/256; + gc->fore_a = c->a/256; +} + +static void +gc_set_background(struct graphics_gc_priv *gc, struct color *c) +{ +#ifdef DEBUG + printf("gc_set_background: %p %d %d %d %d\n", gc, c->a, c->r, c->g, c->b); +#endif + gc->back_r = c->r/256; + gc->back_g = c->g/256; + gc->back_b = c->b/256; + gc->back_a = c->a/256; +} + +static struct graphics_gc_methods gc_methods = { + gc_destroy, + gc_set_linewidth, + gc_set_dashes, + gc_set_foreground, + gc_set_background +}; + +static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth) +{ + struct graphics_gc_priv *gc=g_new0(struct graphics_gc_priv, 1); + *meth=gc_methods; + gc->gr=gr; + gc->linewidth=1; /* upper layer should override anyway? */ + return gc; +} + + +#if 0 /* unused by core? */ +static void image_destroy(struct graphics_image_priv *gi) +{ +#ifdef SDL_IMAGE + SDL_FreeSurface(gi->img); + g_free(gi); +#endif +} + +static struct graphics_image_methods gi_methods = +{ + image_destroy +}; +#endif + +static struct graphics_image_priv * +image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h, + struct point *hot, int rotation) +{ +#ifdef SDL_IMAGE + struct graphics_image_priv *gi; + + /* FIXME: meth is not used yet.. so gi leaks. at least xpm is small */ + + gi = g_new0(struct graphics_image_priv, 1); + gi->img = IMG_Load(name); + if(gi->img) + { + /* TBD: improves blit performance? */ + SDL_SetColorKey(gi->img, SDL_RLEACCEL, gi->img->format->colorkey); + *w=gi->img->w; + *h=gi->img->h; + hot->x=*w/2; + hot->y=*h/2; + } + else + { + /* TODO: debug "colour parse errors" on xpm */ + printf("graphics_sdl: image_new on '%s' failed: %s\n", name, IMG_GetError()); + g_free(gi); + gi = NULL; + } + + return gi; +#else + return NULL; +#endif +} + +static void +image_free(struct graphics_priv *gr, struct graphics_image_priv * gi) +{ +#ifdef SDL_IMAGE + SDL_FreeSurface(gi->img); + g_free(gi); +#endif +} + +static void +get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate) +{ + char *p=text; + FT_BBox bbox; + FT_UInt glyph_index; + FT_GlyphSlot slot = font->face->glyph; // a small shortcut + FT_Glyph glyph; + FT_Matrix matrix; + FT_Vector pen; + pen.x = 0 * 64; + pen.y = 0 * 64; + matrix.xx = dx; + matrix.xy = dy; + matrix.yx = -dy; + matrix.yy = dx; + int n,len,x=0,y=0; + + bbox.xMin = bbox.yMin = 32000; + bbox.xMax = bbox.yMax = -32000; + FT_Set_Transform( font->face, &matrix, &pen ); + len=g_utf8_strlen(text, -1); + for ( n = 0; n < len; n++ ) { + FT_BBox glyph_bbox; + glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p)); + p=g_utf8_next_char(p); + FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT ); + FT_Get_Glyph(font->face->glyph, &glyph); + FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &glyph_bbox ); + FT_Done_Glyph(glyph); + glyph_bbox.xMin += x >> 6; + glyph_bbox.xMax += x >> 6; + glyph_bbox.yMin += y >> 6; + glyph_bbox.yMax += y >> 6; + x += slot->advance.x; + y -= slot->advance.y; + if ( glyph_bbox.xMin < bbox.xMin ) + bbox.xMin = glyph_bbox.xMin; + if ( glyph_bbox.yMin < bbox.yMin ) + bbox.yMin = glyph_bbox.yMin; + if ( glyph_bbox.xMax > bbox.xMax ) + bbox.xMax = glyph_bbox.xMax; + if ( glyph_bbox.yMax > bbox.yMax ) + bbox.yMax = glyph_bbox.yMax; + } + if ( bbox.xMin > bbox.xMax ) { + bbox.xMin = 0; + bbox.yMin = 0; + bbox.xMax = 0; + bbox.yMax = 0; + } + ret[0].x=bbox.xMin; + ret[0].y=-bbox.yMin; + ret[1].x=bbox.xMin; + ret[1].y=-bbox.yMax; + ret[2].x=bbox.xMax; + ret[2].y=-bbox.yMax; + ret[3].x=bbox.xMax; + ret[3].y=-bbox.yMin; +} + +static void +draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count) +{ + Sint16 *vx, *vy; + Sint16 x, y; + int i; + + vx = alloca(count * sizeof(Sint16)); + vy = alloca(count * sizeof(Sint16)); + + for(i = 0; i < count; i++) + { + x = (Sint16)p[i].x; + y = (Sint16)p[i].y; + +#if 0 + if(x < 0) + { + x = 0; + } + if(y < 0) + { + y = 0; + } +#endif + + vx[i] = x; + vy[i] = y; + +#ifdef DEBUG + printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y); +#endif + } + +#ifdef RASTER + if(gr->aa) + { + raster_aapolygon(gr->screen, count, vx, vy, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b)); + } + else + { + raster_polygon(gr->screen, count, vx, vy, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b)); + } +#else +#ifdef SDL_SGE +#ifdef ALPHA + sge_FilledPolygonAlpha(gr->screen, count, vx, vy, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b), + gc->fore_a); +#else +#ifdef ANTI_ALIAS + sge_AAFilledPolygon(gr->screen, count, vx, vy, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b)); +#else + sge_FilledPolygon(gr->screen, count, vx, vy, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b)); +#endif +#endif +#else + filledPolygonRGBA(gr->screen, vx, vy, count, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#endif +#endif +} + + + +static void +draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h) +{ +#ifdef DEBUG + printf("draw_rectangle: %d %d %d %d r=%d g=%d b=%d a=%d\n", p->x, p->y, w, h, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#endif + if(w > gr->screen->w) + { + w = gr->screen->w; + } + if(h > gr->screen->h) + { + h = gr->screen->h; + } + +#ifdef RASTER + raster_rect(gr->screen, p->x, p->y, w, h, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b)); +#else +#ifdef SDL_SGE +#ifdef ALPHA + sge_FilledRectAlpha(gr->screen, p->x, p->y, p->x + w, p->y + h, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b), + gc->fore_a); +#else + /* no AA -- should use poly instead for that */ + sge_FilledRect(gr->screen, p->x, p->y, p->x + w, p->y + h, + SDL_MapRGB(gr->screen->format, + gc->fore_r, + gc->fore_g, + gc->fore_b)); +#endif +#else + boxRGBA(gr->screen, p->x, p->y, p->x + w, p->y + h, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#endif +#endif + +} + +static void +draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r) +{ +#if 0 + if(gc->fore_a != 0xff) + { + dbg(0, "%d %d %d %u %u:%u:%u:%u\n", p->x, p->y, r, gc->linewidth, + gc->fore_a, gc->fore_r, gc->fore_g, gc->fore_b); + } +#endif + + /* FIXME: does not quite match gtk */ + + /* hack for osd compass.. why is this needed!? */ + if(gr->overlay_mode) + { + r = r / 2; + } + +#ifdef RASTER + if(gr->aa) + { + raster_aacircle(gr->screen, p->x, p->y, r, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); + } + else + { + raster_circle(gr->screen, p->x, p->y, r, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); + } +#else +#ifdef SDL_SGE +#ifdef ALPHA + sge_FilledCircleAlpha(gr->screen, p->x, p->y, r, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b), + gc->fore_a); +#else +#ifdef ANTI_ALIAS + sge_AAFilledCircle(gr->screen, p->x, p->y, r, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); +#else + sge_FilledCircle(gr->screen, p->x, p->y, r, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); +#endif +#endif +#else +#ifdef ANTI_ALIAS + aacircleRGBA(gr->screen, p->x, p->y, r, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#else + filledCircleRGBA(gr->screen, p->x, p->y, r, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#endif +#endif +#endif +} + + +static void +draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count) +{ + /* you might expect lines to be simpler than the other shapes. + but, that would be wrong. 1 line can generate 1 polygon + 2 circles + and even worse, we have to calculate their parameters! + go dust off your trigonometry hat. + */ +#if 0 + int i, l, x_inc, y_inc, lw; + + lw = gc->linewidth; + + for(i = 0; i < count-1; i++) + { +#ifdef DEBUG + 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); +#endif + for(l = 0; l < lw; l++) + { + /* FIXME: center? */ +#if 1 + if(p[i].x != p[i+1].x) + { + x_inc = l - (lw/2); + } + else + { + x_inc = 0; + } + + if(p[i].y != p[i+1].y) + { + y_inc = l - (lw/2); + } + else + { + y_inc = 0; + } +#else + x_inc = 0; + y_inc = 0; +#endif + +#ifdef ANTI_ALIAS + 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, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#else + 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, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#endif + } + } +#else + /* sort of based on graphics_opengl.c::draw_lines */ + /* FIXME: should honor ./configure flag for no fp. + this could be 100% integer code pretty easily, + except that i am lazy + */ + struct point vert[4]; + int lw = gc->linewidth; + //int lw = 1; + int i; + + for(i = 0; i < count-1; i++) + { + float dx=p[i+1].x-p[i].x; + float dy=p[i+1].y-p[i].y; + +#if 0 + float cx=(p[i+1].x+p[i].x)/2; + float cy=(p[i+1].y+p[i].y)/2; +#endif + + float angle; + + int x_lw_adj, y_lw_adj; + + if(lw == 1) + { +#ifdef RASTER + if(gr->aa) + { + raster_aaline(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); + } + else + { + raster_line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); + } +#else +#ifdef SDL_SGE +#ifdef ALPHA + sge_LineAlpha(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b), + gc->fore_a); +#else +#ifdef ANTI_ALIAS + sge_AALine(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); +#else + sge_Line(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + SDL_MapRGB(gr->screen->format, + gc->fore_r, gc->fore_g, gc->fore_b)); +#endif +#endif +#else +#ifdef ANTI_ALIAS + aalineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#else + lineRGBA(gr->screen, p[i].x, p[i].y, p[i+1].x, p[i+1].y, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#endif +#endif +#endif + } + else + { + /* there is probably a much simpler way but this works ok */ + + /* FIXME: float + double mixture */ + /* FIXME: lrint(round())? */ + if(dy == 0.0) + { + angle = 0.0; + x_lw_adj = 0; + y_lw_adj = round((float)lw/2.0); + } + else if(dx == 0.0) + { + angle = 0.0; + x_lw_adj = round((float)lw/2.0); + y_lw_adj = 0; + } + else + { + angle = (M_PI/2.0) - atan(abs(dx)/abs(dy)); + x_lw_adj = round(sin(angle)*(float)lw/2.0); + y_lw_adj = round(cos(angle)*(float)lw/2.0); + if((x_lw_adj < 0) || (y_lw_adj < 0)) + { + printf("i=%d\n", i); + printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y); + printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI); + printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj); + } + } + + if(p[i+1].x > p[i].x) + { + x_lw_adj = -x_lw_adj; + } + if(p[i+1].y > p[i].y) + { + y_lw_adj = -y_lw_adj; + } + +#if 0 + if(((y_lw_adj*y_lw_adj)+(x_lw_adj*x_lw_adj)) != (lw/2)*(lw/2)) + { + printf("i=%d\n", i); + printf(" %d,%d->%d,%d\n", p[i].x, p[i].y, p[i+1].x, p[i+1].y); + printf(" lw=%d angle=%f\n", lw, 180.0 * angle / M_PI); + printf(" x_lw_adj=%d y_lw_adj=%d\n", x_lw_adj, y_lw_adj); + } +#endif + + /* FIXME: draw a circle/square if p[i]==p[i+1]? */ + /* FIXME: clipping, check for neg values. hoping sdl-gfx does this */ + vert[0].x = p[i].x + x_lw_adj; + vert[0].y = p[i].y - y_lw_adj; + vert[1].x = p[i].x - x_lw_adj; + vert[1].y = p[i].y + y_lw_adj; + vert[2].x = p[i+1].x - x_lw_adj; + vert[2].y = p[i+1].y + y_lw_adj; + vert[3].x = p[i+1].x + x_lw_adj; + vert[3].y = p[i+1].y - y_lw_adj; + + draw_polygon(gr, gc, vert, 4); + + /* draw small circles at the ends. this looks better than nothing, and slightly + * better than the triangle used by graphics_opengl, but is more expensive. + * should have an ifdef/xml attr? + */ + + /* FIXME: should just draw a half circle */ + + /* now some circular endcaps, if the width is over 2 */ + if(lw > 2) + { + if(i == 0) + { + draw_circle(gr, gc, &p[i], lw/2); + } + /* we truncate on the divide on purpose, so we don't go outside the line */ + draw_circle(gr, gc, &p[i+1], lw/2); + } + } + } +#endif +} + + +#ifdef SDL_TTF +static void +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) +{ + SDL_Surface *ss; + SDL_Color f, b; + SDL_Rect r; + +#if 0 + /* correct? */ + f.r = bg->back_r; + f.g = bg->back_g; + f.b = bg->back_b; + b.r = bg->back_r; + b.g = bg->back_g; + b.b = bg->back_b; +#else + f.r = 0xff; + f.g = 0xff; + f.b = 0xff; + b.r = 0x00; + b.g = 0x00; + b.b = 0x00; +#endif + + /* TODO: dx + dy? */ + + ss = TTF_RenderUTF8_Solid(gf->font, text, b); + if(ss) + { + r.x = p->x; + r.y = p->y; + r.w = ss->w; + r.h = ss->h; + //SDL_SetAlpha(ss, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); + SDL_BlitSurface(ss, NULL, gr->screen, &r); + } +} +#else + +struct text_glyph { + int x,y,w,h; + unsigned char *shadow; + unsigned char pixmap[0]; +}; + +struct text_render { + int x1,y1; + int x2,y2; + int x3,y3; + int x4,y4; + int glyph_count; + struct text_glyph *glyph[0]; +}; + +static unsigned char * +display_text_render_shadow(struct text_glyph *g) +{ + int mask0, mask1, mask2, x, y, w=g->w, h=g->h; + int str=(g->w+9)/8; + unsigned char *shadow; + unsigned char *p, *pm=g->pixmap; + + shadow=malloc(str*(g->h+2)); + memset(shadow, 0, str*(g->h+2)); + for (y = 0 ; y < h ; y++) { + p=shadow+str*y; + mask0=0x4000; + mask1=0xe000; + mask2=0x4000; + for (x = 0 ; x < w ; x++) { + if (pm[x+y*w]) { + p[0]|=(mask0 >> 8); + if (mask0 & 0xff) + p[1]|=mask0; + + p[str]|=(mask1 >> 8); + if (mask1 & 0xff) + p[str+1]|=mask1; + p[str*2]|=(mask2 >> 8); + if (mask2 & 0xff) + p[str*2+1]|=mask2; + } + mask0 >>= 1; + mask1 >>= 1; + mask2 >>= 1; + if (!((mask0 >> 8) | (mask1 >> 8) | (mask2 >> 8))) { + mask0<<=8; + mask1<<=8; + mask2<<=8; + p++; + } + } + } + return shadow; +} + + +static struct text_render * +display_text_render(char *text, struct graphics_font_priv *font, int dx, int dy, int x, int y) +{ + FT_GlyphSlot slot = font->face->glyph; // a small shortcut + FT_Matrix matrix; + FT_Vector pen; + FT_UInt glyph_index; + int n,len; + struct text_render *ret; + struct text_glyph *curr; + char *p=text; + + len=g_utf8_strlen(text, -1); + ret=g_malloc(sizeof(*ret)+len*sizeof(struct text_glyph *)); + ret->glyph_count=len; + + matrix.xx = dx; + matrix.xy = dy; + matrix.yx = -dy; + matrix.yy = dx; + + pen.x = 0 * 64; + pen.y = 0 * 64; + x <<= 6; + y <<= 6; + FT_Set_Transform( font->face, &matrix, &pen ); + + for ( n = 0; n < len; n++ ) + { + + glyph_index = FT_Get_Char_Index(font->face, g_utf8_get_char(p)); + FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT ); + FT_Render_Glyph(font->face->glyph, ft_render_mode_normal ); + + curr=g_malloc(sizeof(*curr)+slot->bitmap.rows*slot->bitmap.pitch); + ret->glyph[n]=curr; + + curr->x=(x>>6)+slot->bitmap_left; + curr->y=(y>>6)-slot->bitmap_top; + curr->w=slot->bitmap.width; + curr->h=slot->bitmap.rows; + if (slot->bitmap.width && slot->bitmap.rows) { + memcpy(curr->pixmap, slot->bitmap.buffer, slot->bitmap.rows*slot->bitmap.pitch); + curr->shadow=display_text_render_shadow(curr); + } + else + curr->shadow=NULL; +#if 0 + printf("height=%d\n", slot->metrics.height); + printf("height2=%d\n", face->height); + printf("bbox %d %d %d %d\n", face->bbox.xMin, face->bbox.yMin, face->bbox.xMax, face->bbox.yMax); +#endif +#if 0 + printf("slot->advance x %d y %d\n", + slot->advance.x, + slot->advance.y); +#endif + + x += slot->advance.x; + y -= slot->advance.y; + p=g_utf8_next_char(p); + } + return ret; +} + +#if 0 +static void hexdump(unsigned char *buf, unsigned int w, unsigned int h) +{ + int x, y; + printf("hexdump %u %u\n", w, h); + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + printf("%02x ", buf[y*w+x]); + } + printf("\n"); + } +} + +static void bitdump(unsigned char *buf, unsigned int w, unsigned int h) +{ + int x, pos; + printf("bitdump %u %u\n", w, h); + pos = 0; + for(x = 0; x < h * w; x++) + { + if(buf[pos] & (1 << (x&0x7))) + { + printf("00 "); + } + else + { + printf("ff "); + } + + if((x & 0x7) == 0x7) + { + pos++; + } + + if((x % w) == (w-1)) + { + printf("\n"); + } + } + printf("\n"); +} +#endif + +#if 0 +static void sdl_inv_grayscale_pal_set(SDL_Surface *ss) +{ + SDL_Color c; + int i; + + for(i = 0; i < 256; i++) + { + c.r = 255-i; + c.g = 255-i; + c.b = 255-i; + SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1); + } +} + +static void sdl_scale_pal_set(SDL_Surface *ss, Uint8 r, Uint8 g, Uint8 b) +{ + SDL_Color c; + int i; + + for(i = 0; i < 256; i++) + { + c.r = (i * r) / 256; + c.g = (i * g) / 256; + c.b = (i * b) / 256; + SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1); + } +} +#endif + +#if 0 +static void sdl_fixed_pal_set(SDL_Surface *ss, Uint8 r, Uint8 g, Uint8 b) +{ + SDL_Color c; + int i; + + c.r = r; + c.g = g; + c.b = b; + for(i = 0; i < 256; i++) + { + SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1); + } +} +#endif + +static void +display_text_draw(struct text_render *text, struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg) +{ + int i, x, y, poff, soff, col_lev; + struct text_glyph *gly, **gp; + Uint32 pix; + Uint8 r, g, b; + +#if 0 + dbg(0,"%u %u %u %u, %u %u %u %u\n", + fg->fore_a, fg->fore_r, fg->fore_g, fg->fore_b, + fg->back_a, fg->back_r, fg->back_g, fg->back_b); + + dbg(0,"%u %u %u %u, %u %u %u %u\n", + bg->fore_a, bg->fore_r, bg->fore_g, bg->fore_b, + bg->back_a, bg->back_r, bg->back_g, bg->back_b); +#endif + + if(bg) + { + col_lev = bg->fore_r + bg->fore_g + bg->fore_b; + } + else + { + col_lev = 0; + } + + /* TODO: lock/unlock in draw_mode() to reduce overhead */ + SDL_LockSurface(gr->screen); + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) + { + gly=*gp++; + if (gly->w && gly->h) + { +#if 0 + if(gly->shadow && bg) + { + hexdump(gly->pixmap, gly->w, gly->h); + bitdump(gly->shadow, gly->w+2, gly->h+2); + } +#endif + + for(y = 0; y < gly->h + 2; y++) + { + if(gly->y - 1 + y < 0) + { + continue; + } + + if(((gly->y-1) + y) >= gr->screen->h) + { + break; + } + + for(x = 0; x < gly->w + 2; x++) + { + if(gly->x - 1 + x < 0) + { + continue; + } + + if(((gly->x-1) + x) >= gr->screen->w) + { + break; + } + + poff = gr->screen->w * ((gly->y-1) + y) + ((gly->x-1) + x); + poff = poff * gr->screen->format->BytesPerPixel; + + switch(gr->screen->format->BytesPerPixel) + { + case 2: + { + pix = *(Uint16 *)((Uint8*)gr->screen->pixels + poff); + break; + } + case 4: + { + pix = *(Uint32 *)((Uint8*)gr->screen->pixels + poff); + break; + } + default: + { + pix = 0; + break; + } + } + + SDL_GetRGB(pix, + gr->screen->format, + &r, + &g, + &b); + +#ifdef DEBUG + printf("%u %u -> %u off\n", + gly->x, + gly->y, + off); + + printf("%u,%u: %u %u %u in\n", + x, y, + r, g, b, off); +#endif + + + + if(gly->shadow && bg) + { + soff = (8 * ((gly->w+9)/8) * y) + x; + pix = gly->shadow[soff/8]; + + if(pix & (1 << (7-(soff&0x7)))) + { + if(col_lev >= 3*0x80) + { + r |= bg->fore_r; + g |= bg->fore_g; + b |= bg->fore_b; + } + else + { + r &= ~bg->fore_r; + g &= ~bg->fore_g; + b &= ~bg->fore_b; + } + } + } + + /* glyph */ + if((x > 0) && (x <= gly->w) && + (y > 0) && (y <= gly->h)) + { + if(bg && (col_lev >= 3*0x80)) + { + r &= ~gly->pixmap[gly->w * (y-1) + (x-1)]; + g &= ~gly->pixmap[gly->w * (y-1) + (x-1)]; + b &= ~gly->pixmap[gly->w * (y-1) + (x-1)]; + } + else + { + r |= gly->pixmap[gly->w * (y-1) + (x-1)]; + g |= gly->pixmap[gly->w * (y-1) + (x-1)]; + b |= gly->pixmap[gly->w * (y-1) + (x-1)]; + } + } + +#ifdef DEBUG + printf("%u,%u: %u %u %u out\n", + x, y, + r, g, b); +#endif + + pix = SDL_MapRGB(gr->screen->format, + r, + g, + b); + + switch(gr->screen->format->BytesPerPixel) + { + case 2: + { + *(Uint16 *)((Uint8*)gr->screen->pixels + poff) = pix; + break; + } + case 4: + { + *(Uint32 *)((Uint8*)gr->screen->pixels + poff) = pix; + break; + } + default: + { + break; + } + } + } + } + + //dbg(0, "glyph %d %d %d %d\n", g->x, g->y, g->w, g->h); + } + } + SDL_UnlockSurface(gr->screen); +} + +static void +display_text_free(struct text_render *text) +{ + int i; + struct text_glyph **gp; + + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) { + if ((*gp)->shadow) { + free((*gp)->shadow); + } + g_free(*gp++); + } + g_free(text); +} + +static void +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) +{ + struct text_render *t; + + if (! font) + return; + +#if 0 + if (bg) { + gdk_gc_set_function(fg->gc, GDK_AND_INVERT); + gdk_gc_set_function(bg->gc, GDK_OR); + } +#endif + + t=display_text_render(text, font, dx, dy, p->x, p->y); + display_text_draw(t, gr, fg, bg); + display_text_free(t); +#if 0 + if (bg) { + gdk_gc_set_function(fg->gc, GDK_COPY); + gdk_gc_set_function(bg->gc, GDK_COPY); + } +#endif +} +#endif + + + +static void +draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img) +{ +#ifdef SDL_IMAGE + SDL_Rect r; + + r.x = p->x; + r.y = p->y; + r.w = img->img->w; + r.h = img->img->h; + + SDL_BlitSurface(img->img, NULL, gr->screen, &r); +#endif +} + +static void +draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data) +{ + /* TODO */ +} + +static void +draw_restore(struct graphics_priv *gr, struct point *p, int w, int h) +{ +#ifdef DEBUG + printf("draw_restore\n"); +#endif +} + +static void +background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc) +{ +#ifdef DEBUG + printf("background_gc\n"); +#endif +} + + +static void +draw_mode(struct graphics_priv *gr, enum draw_mode_num mode) +{ +#ifdef PROFILE + struct timeval now; + unsigned long elapsed; +#endif + struct graphics_priv *ov; + SDL_Rect rect; + int i; + + if(gr->overlay_mode) + { + /* will be drawn below */ + } + else + { +#ifdef DEBUG + printf("draw_mode: %d\n", mode); +#endif + +#ifdef PROFILE + if(mode == draw_mode_begin) + { + gettimeofday(&gr->draw_begin_tv, NULL); + } +#endif + + if(mode == draw_mode_end) + { + if((gr->draw_mode == draw_mode_begin) && gr->overlay_enable) + { + for(i = 0; i < OVERLAY_MAX; i++) + { + ov = gr->overlay_array[i]; + if(ov) + { + rect.x = ov->overlay_x; + rect.y = ov->overlay_y; + rect.w = ov->screen->w; + rect.h = ov->screen->h; + SDL_BlitSurface(ov->screen, NULL, + gr->screen, &rect); + } + } + } + + SDL_Flip(gr->screen); + +#ifdef PROFILE + gettimeofday(&now, NULL); + elapsed = 1000000 * (now.tv_sec - gr->draw_begin_tv.tv_sec); + elapsed += (now.tv_usec - gr->draw_begin_tv.tv_usec); + if(elapsed >= gr->draw_time_peak) + { + dbg(0, "draw elapsed %u usec\n", elapsed); + gr->draw_time_peak = elapsed; + } +#endif + } + + gr->draw_mode = mode; + } +} + +static void overlay_disable(struct graphics_priv *gr, int disable) +{ + gr->overlay_enable = !disable; +} + +static struct graphics_priv * +overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha, int wraparound); + +static int window_fullscreen(struct window *win, int on) +{ + /* TODO */ + return 0; +} + +static struct window sdl_win = +{ + NULL, + window_fullscreen + +}; + +static void * +get_data(struct graphics_priv *this, char *type) +{ + printf("get_data: %s\n", type); + + if(strcmp(type, "window") == 0) + { + return &sdl_win; + } + else + { + return &dummy; + } +} + +static void draw_drag(struct graphics_priv *gr, struct point *p) +{ + // FIXME +} + +static struct graphics_methods graphics_methods = { + graphics_destroy, + draw_mode, + draw_lines, + draw_polygon, + draw_rectangle, + draw_circle, + draw_text, + draw_image, + draw_image_warp, + draw_restore, + draw_drag, + font_new, + gc_new, + background_gc, + overlay_new, + image_new, + get_data, +// register_resize_callback, +// register_button_callback, +// register_motion_callback, + image_free, + get_text_bbox, + overlay_disable, +// register_keypress_callback +}; + +static struct graphics_priv * +overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h,int alpha, int wraparound) +{ + struct graphics_priv *ov; + int i, x, y; + + for(i = 0; i < OVERLAY_MAX; i++) + { + if(gr->overlay_array[i] == NULL) + { + break; + } + } + if(i == OVERLAY_MAX) + { + dbg(0, "too many overlays! increase OVERLAY_MAX\n"); + return NULL; + } + dbg(0, "x %d y %d\n", p->x, p->y); + + if(p->x < 0) + { + x = gr->screen->w + p->x; + } + else + { + x = p->x; + } + if(p->y < 0) + { + y = gr->screen->h + p->y; + } + else + { + y = p->y; + } + + dbg(1, "overlay_new %d %d %d %u %u\n", i, + x, + y, + w, + h); + + ov = g_new0(struct graphics_priv, 1); + + ov->screen = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, + w, h, +#if 1 + gr->screen->format->BitsPerPixel, + gr->screen->format->Rmask, + gr->screen->format->Gmask, + gr->screen->format->Bmask, + 0x00000000); +#else + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0xff000000); +#endif + SDL_SetAlpha(ov->screen, SDL_SRCALPHA, 128); + + ov->overlay_mode = 1; + ov->overlay_x = x; + ov->overlay_y = y; + ov->overlay_parent = gr; + ov->overlay_idx = i; + + gr->overlay_array[i] = ov; + + *meth=graphics_methods; + + return ov; +} + + +#ifdef LINUX_TOUCHSCREEN + +#define EVFN "/dev/input/eventX" + +static int input_ts_init(struct graphics_priv *gr) +{ + struct input_id ii; + char fn[32]; +#if 0 + char name[64]; +#endif + int n, fd, ret; + + gr->ts_fd = -1; + gr->ts_hit = -1; + gr->ts_x = 0; + gr->ts_y = 0; + + strcpy(fn, EVFN); + n = 0; + while(1) + { + fn[sizeof(EVFN)-2] = '0' + n; + + fd = open(fn, O_RDONLY); + if(fd >= 0) + { +#if 0 + ret = ioctl(fd, EVIOCGNAME(64), (void *)name); + if(ret > 0) + { + printf("input_ts: %s\n", name); + } +#endif + + ret = ioctl(fd, EVIOCGID, (void *)&ii); + if(ret == 0) + { +#if 1 + printf("bustype %04x vendor %04x product %04x version %04x\n", + ii.bustype, + ii.vendor, + ii.product, + ii.version); +#endif + + if((ii.bustype == BUS_USB) && + (ii.vendor == 0x0eef) && + (ii.product == 0x0001)) + { + ret = fcntl(fd, F_SETFL, O_NONBLOCK); + if(ret == 0) + { + gr->ts_fd = fd; + } + else + { + close(fd); + } + + break; + } + } + + close(fd); + } + + n = n + 1; + + /* FIXME: should check all 32 minors */ + if(n == 10) + { + /* not found */ + ret = -1; + break; + } + } + + return ret; +} + + +/* returns 0-based display coordinate for the given ts coord */ +static void input_ts_map(int *disp_x, int *disp_y, + uint32_t ts_x, uint32_t ts_y) +{ + /* Dynamix 7" (eGalax TS) + top left = 1986,103 + top right = 61,114 + bot left = 1986,1897 + bot right = 63,1872 + + calibrate your TS using input_event_dump + and touching all four corners. use the most extreme values. + */ + +#define INPUT_TS_LEFT 1978 +#define INPUT_TS_RIGHT 48 +#define INPUT_TS_TOP 115 +#define INPUT_TS_BOT 1870 + + /* clamp first */ + if(ts_x > INPUT_TS_LEFT) + { + ts_x = INPUT_TS_LEFT; + } + if(ts_x < INPUT_TS_RIGHT) + { + ts_x = INPUT_TS_RIGHT; + } + + ts_x = ts_x - INPUT_TS_RIGHT; + + *disp_x = ((DISPLAY_W-1) * ts_x) / (INPUT_TS_LEFT - INPUT_TS_RIGHT); + *disp_x = (DISPLAY_W-1) - *disp_x; + + + if(ts_y > INPUT_TS_BOT) + { + ts_y = INPUT_TS_BOT; + } + if(ts_y < INPUT_TS_TOP) + { + ts_y = INPUT_TS_TOP; + } + + ts_y = ts_y - INPUT_TS_TOP; + + *disp_y = ((DISPLAY_H-1) * ts_y) / (INPUT_TS_BOT - INPUT_TS_TOP); +/* *disp_y = (DISPLAY_H-1) - *disp_y; */ +} + +#if 0 +static void input_event_dump(struct input_event *ie) +{ + printf("input_event:\n" + "\ttv_sec\t%u\n" + "\ttv_usec\t%lu\n" + "\ttype\t%u\n" + "\tcode\t%u\n" + "\tvalue\t%d\n", + (unsigned int)ie->time.tv_sec, + ie->time.tv_usec, + ie->type, + ie->code, + ie->value); +} +#endif + +static int input_ts_exit(struct graphics_priv *gr) +{ + close(gr->ts_fd); + gr->ts_fd = -1; + + return 0; +} +#endif + + +static gboolean graphics_sdl_idle(void *data) +{ + struct graphics_priv *gr = (struct graphics_priv *)data; + struct point p; + SDL_Event ev; +#ifdef LINUX_TOUCHSCREEN + struct input_event ie; + ssize_t ss; +#endif + int ret, key; + char keybuf[2]; + + /* generate the initial resize callback, so the gui knows W/H + + its unsafe to do this directly inside register_resize_callback; + graphics_gtk does it during Configure, but SDL does not have + an equivalent event, so we use our own flag + */ + if(gr->resize_callback_initial != 0) + { + callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h); + gr->resize_callback_initial = 0; + } + +#ifdef LINUX_TOUCHSCREEN + if(gr->ts_fd >= 0) + { + ss = read(gr->ts_fd, (void *)&ie, sizeof(ie)); + if(ss == sizeof(ie)) + { + /* we (usually) get three events on a touchscreen hit: + 1: type =EV_KEY + code =330 [BTN_TOUCH] + value=1 + + 2: type =EV_ABS + code =0 [X] + value=X pos + + 3: type =EV_ABS + code =1 [Y] + value=Y pos + + 4: type =EV_SYN + + once hit, if the contact point changes, we'll get more + EV_ABS (for 1 or both axes), followed by an EV_SYN. + + and, on a lift: + + 5: type =EV_KEY + code =330 [BTN_TOUCH] + value=0 + + 6: type =EV_SYN + */ + switch(ie.type) + { + case EV_KEY: + { + if(ie.code == BTN_TOUCH) + { + gr->ts_hit = ie.value; + } + + break; + } + + case EV_ABS: + { + if(ie.code == 0) + { + gr->ts_x = ie.value; + } + else if(ie.code == 1) + { + gr->ts_y = ie.value; + } + + break; + } + + case EV_SYN: + { + input_ts_map(&p.x, &p.y, gr->ts_x, gr->ts_y); + + /* always send MOUSE_MOTION (first) */ + callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p); + if(gr->ts_hit > 0) + { + callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)SDL_BUTTON_LEFT, (void *)&p); + } + else if(gr->ts_hit == 0) + { + callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)SDL_BUTTON_LEFT, (void *)&p); + } + + /* reset ts_hit */ + gr->ts_hit = -1; + + break; + } + + default: + { + break; + } + } + } + } +#endif + + while(1) + { + ret = SDL_PollEvent(&ev); + if(ret == 0) + { + break; + } + + switch(ev.type) + { + case SDL_MOUSEMOTION: + { + p.x = ev.motion.x; + p.y = ev.motion.y; + callback_list_call_attr_1(gr->cbl, attr_motion, (void *)&p); + break; + } + + case SDL_KEYDOWN: + { + switch(ev.key.keysym.sym) + { + case SDLK_LEFT: + { + key = NAVIT_KEY_LEFT; + break; + } + case SDLK_RIGHT: + { + key = NAVIT_KEY_RIGHT; + break; + } + case SDLK_BACKSPACE: + { + key = NAVIT_KEY_BACKSPACE; + break; + } + case SDLK_RETURN: + { + key = NAVIT_KEY_RETURN; + break; + } + case SDLK_DOWN: + { + key = NAVIT_KEY_DOWN; + break; + } + case SDLK_PAGEUP: + { + key = NAVIT_KEY_ZOOM_OUT; + break; + } + case SDLK_UP: + { + key = NAVIT_KEY_UP; + break; + } + case SDLK_PAGEDOWN: + { + key = NAVIT_KEY_ZOOM_IN; + break; + } + default: + { + key = 0; + break; + } + } + + keybuf[0] = key; + keybuf[1] = '\0'; + callback_list_call_attr_1(gr->cbl, attr_keypress, (void *)keybuf); + + break; + } + + case SDL_KEYUP: + { + break; + } + + case SDL_MOUSEBUTTONDOWN: + { +#ifdef DEBUG + printf("SDL_MOUSEBUTTONDOWN %d %d %d %d %d\n", + ev.button.which, + ev.button.button, + ev.button.state, + ev.button.x, + ev.button.y); +#endif + + p.x = ev.button.x; + p.y = ev.button.y; + callback_list_call_attr_3(gr->cbl, attr_button, (void *)1, (void *)(int)ev.button.button, (void *)&p); + break; + } + + case SDL_MOUSEBUTTONUP: + { +#ifdef DEBUG + printf("SDL_MOUSEBUTTONUP %d %d %d %d %d\n", + ev.button.which, + ev.button.button, + ev.button.state, + ev.button.x, + ev.button.y); +#endif + + p.x = ev.button.x; + p.y = ev.button.y; + callback_list_call_attr_3(gr->cbl, attr_button, (void *)0, (void *)(int)ev.button.button, (void *)&p); + break; + } + + case SDL_QUIT: + { + navit_destroy(gr->nav); + break; + } + + case SDL_VIDEORESIZE: + { + + gr->screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE); + if(gr->screen == NULL) + { + navit_destroy(gr->nav); + } + else + { + callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->screen->w, (void *)gr->screen->h); + } + + break; + } + + default: + { +#ifdef DEBUG + printf("SDL_Event %d\n", ev.type); +#endif + break; + } + } + } + + return TRUE; +} + + +static struct graphics_priv * +graphics_sdl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl) +{ + struct graphics_priv *this=g_new0(struct graphics_priv, 1); + struct attr *attr; + int ret; + int w=DISPLAY_W,h=DISPLAY_H; + + this->nav = nav; + this->cbl = cbl; + + ret = SDL_Init(SDL_INIT_VIDEO); + if(ret < 0) + { + g_free(this); + return NULL; + } + +#ifdef SDL_TTF + ret = TTF_Init(); + if(ret < 0) + { + g_free(this); + SDL_Quit(); + return NULL; + } +#else + FT_Init_FreeType( &this->library ); +#endif + + if (! event_request_system("glib","graphics_sdl_new")) + return NULL; + + + /* TODO: xml params for BPP */ + if ((attr=attr_search(attrs, NULL, attr_w))) + w=attr->u.num; + if ((attr=attr_search(attrs, NULL, attr_h))) + h=attr->u.num; + + + this->screen = SDL_SetVideoMode(w, h, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE); + if(this->screen == NULL) + { + g_free(this); + SDL_Quit(); + return NULL; + } + + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + SDL_WM_SetCaption("navit", NULL); + +#ifdef LINUX_TOUCHSCREEN + input_ts_init(this); + if(this->ts_fd >= 0) + { + /* mouse cursor does not always display correctly in Linux FB. + anyway, it is unnecessary w/ a touch screen + */ + SDL_ShowCursor(0); + } +#endif + +#ifdef SDL_SGE + sge_Update_OFF(); + sge_Lock_ON(); +#endif + + *meth=graphics_methods; + + g_timeout_add(10, graphics_sdl_idle, this); + + this->overlay_enable = 1; + + this->aa = 1; + if((attr=attr_search(attrs, NULL, attr_antialias))) + this->aa = attr->u.num; + + this->resize_callback_initial=1; + return this; +} + +void +plugin_init(void) +{ + plugin_register_graphics_type("sdl", graphics_sdl_new); +} + |