From 9722e92e7a1105b90bf5f22c1d5f23f50158c6f6 Mon Sep 17 00:00:00 2001 From: martin-s Date: Sun, 15 Jun 2008 20:11:01 +0000 Subject: [PATCH] Add:graphics_sdl:Added graphics_sdl code from rphlx git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@1121 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- navit/configure.in | 38 +- navit/navit/graphics/Makefile.am | 3 + navit/navit/graphics/sdl/Makefile.am | 5 + navit/navit/graphics/sdl/graphics_sdl.c | 1313 +++++++++++++++++++++++++++++++ navit/navit/gui/internal/gui_internal.c | 40 +- navit/navit/route.c | 2 +- 6 files changed, 1390 insertions(+), 11 deletions(-) create mode 100644 navit/navit/graphics/sdl/Makefile.am create mode 100644 navit/navit/graphics/sdl/graphics_sdl.c diff --git a/navit/configure.in b/navit/configure.in index 167a248..50e5ba6 100644 --- a/navit/configure.in +++ b/navit/configure.in @@ -13,6 +13,8 @@ AC_PROG_CC if eval "test x$GCC = xyes"; then CFLAGS="$CFLAGS -Wall -Wcast-align -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith -Wreturn-type -D_GNU_SOURCE" fi +AM_PROG_CC_C_O + AC_PROG_CXX if eval "test x$GXX = xyes"; then CXXFLAGS="$CXXFLAGS -Wall -Wcast-align -Wmissing-prototypes -Wstrict-prototypes -Wpointer-arith -Wreturn-type -D_GNU_SOURCE" @@ -120,6 +122,39 @@ if test "x${enable_graphics_qt_qpainter}" = "xyes" ; then fi AM_CONDITIONAL(USE_GRAPHICS_QT_QPAINTER, test "x${enable_graphics_qt_qpainter}" = "xyes") +AC_ARG_ENABLE(graphics-sdl, [ --disable-graphics-sdl don't create graphics sdl], enable_graphics_sdl=$enableval, enable_graphics_sdl=yes) +if test "x${enable_graphics_sdl}" = "xyes" ; then + if test -z "$SDL_CONFIG"; then + AC_PATH_PROG([SDL_CONFIG], [sdl-config], []) + fi +fi +if test "x${enable_graphics_sdl}" = "xyes" ; then + AC_MSG_CHECKING([for SDL libraries with $SDL_CONFIG]) + if test ! -x "$SDL_CONFIG"; then + enable_graphics_sdl = "no" + AC_MSG_RESULT([no]) + else + SDL_CFLAGS="`$SDL_CONFIG --cflags`" + SDL_LIBS="`$SDL_CONFIG --libs`" + AC_SUBST(SDL_CFLAGS) + AC_SUBST(SDL_LIBS) + AC_MSG_RESULT([yes]) + fi +fi +if test "x${enable_graphics_sdl}" = "xyes" ; then + save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$($SDL_CONFIG --cflags) $CPPFLAGS" + AC_CHECK_HEADER(SDL_image.h,SDL_IMAGE_LIBS=-lSDL_image,enable_graphics_sdl=no) + AC_CHECK_HEADER(SDL_gfxPrimitives.h,SDL_GFX_LIBS=-lSDL_gfx,enable_graphics_sdl=no) + AC_SUBST(SDL_IMAGE_LIBS) + AC_SUBST(SDL_GFX_LIBS) + CPPFLAGS=$save_CPPFLAGS +fi +if test "x${enable_graphics_sdl}" = "xyes" ; then + AC_DEFINE(USE_GRAPICS_SDL, 1, [Build with graphics sdl]) +fi +AM_CONDITIONAL(USE_GRAPHICS_SDL, test "x${enable_graphics_sdl}" = "xyes") + AC_ARG_ENABLE(postgresql, [ --disable-postgresql don't add postgresql support to osm2navit], enable_postgresql=$enableval, enable_postgresql=yes) if test "x${enable_postgresql}" = "xyes" ; then if test -z "$PG_CONFIG"; then @@ -185,8 +220,6 @@ if test "x$MODULE_GUI_SDL" = "xyes"; then AC_MSG_WARN([*** no SDL/SDL.h -- SDL support disabled]) ) fi -AC_SUBST(SDL_CFLAGS) -AC_SUBST(SDL_LIBS) PKG_CHECK_MODULES( [CEGUI], @@ -501,6 +534,7 @@ navit/graphics/Makefile navit/graphics/gtk_drawing_area/Makefile navit/graphics/opengl/Makefile navit/graphics/null/Makefile +navit/graphics/sdl/Makefile navit/graphics/qt_qpainter/Makefile navit/gui/Makefile navit/gui/gtk/Makefile diff --git a/navit/navit/graphics/Makefile.am b/navit/navit/graphics/Makefile.am index 22bbc6e..1a6e89f 100644 --- a/navit/navit/graphics/Makefile.am +++ b/navit/navit/graphics/Makefile.am @@ -8,3 +8,6 @@ endif if USE_GRAPHICS_QT_QPAINTER SUBDIRS+=qt_qpainter endif +if USE_GRAPHICS_SDL + SUBDIRS+=sdl +endif diff --git a/navit/navit/graphics/sdl/Makefile.am b/navit/navit/graphics/sdl/Makefile.am new file mode 100644 index 0000000..7865ca5 --- /dev/null +++ b/navit/navit/graphics/sdl/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/Makefile.inc +AM_CPPFLAGS = @NAVIT_CFLAGS@ @SDL_CFLAGS@ @FREETYPE2_CFLAGS@ @FONTCONFIG_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=graphics_sdl +modulegraphics_LTLIBRARIES = libgraphics_sdl.la +libgraphics_sdl_la_SOURCES = graphics_sdl.c +libgraphics_sdl_la_LDFLAGS = @SDL_LIBS@ @SDL_IMAGE_LIBS@ @SDL_GFX_LIBS@ @FREETYPE2_LIBS@ @FONTCONFIG_LIBS@ @IMLIB2_LIBS@ diff --git a/navit/navit/graphics/sdl/graphics_sdl.c b/navit/navit/graphics/sdl/graphics_sdl.c new file mode 100644 index 0000000..f5396c1 --- /dev/null +++ b/navit/navit/graphics/sdl/graphics_sdl.c @@ -0,0 +1,1313 @@ +/* graphics_sdl.c -- barebones sdl graphics layer + + copyright (c) 2008 bryan rittmeyer + license: GPLv2 + + TODO: + - kb events + - raw linux touchscreen + - resize events (cannot be generated right now) + - SDL window title for X + - text visibility cleanup/tweaks + - dashed lines + - ifdef DEBUG -> dbg() + - valgrind + + revision history: + 2008-06-01 initial +*/ + +#include +#include "config.h" +#include "debug.h" +#include "point.h" +#include "graphics.h" +#include "color.h" +#include "plugin.h" + +#include +#include + +#undef SDL_TTF + +#ifdef SDL_TTF +#include +#else +#include +#include +#include FT_FREETYPE_H +#include +#endif + +#define SDL_IMAGE +#ifdef SDL_IMAGE +#include +#endif + +#include + +#define DISPLAY_W 800 +#define DISPLAY_H 600 + +#undef ANTI_ALIAS + +#undef DEBUG + + +struct graphics_priv { + SDL_Surface *screen; + + void (*resize_callback)(void *data, int w, int h); + void *resize_callback_data; + void (*motion_callback)(void *data, struct point *p); + void *motion_callback_data; + void (*button_callback)(void *data, int press, int button, struct point *p); + void *button_callback_data; + +#ifndef SDL_TTF + FT_Library library; + int library_init; +#endif +}; + +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; +}; + + +static void +graphics_destroy(struct graphics_priv *gr) +{ +#ifdef SDL_TTF + TTF_Quit(); +#endif + SDL_Quit(); +} + +/* graphics_font */ +static char *fontfamilies[]={ + "Liberation Mono", + "Arial", + "DejaVu Sans", + "NcrBI4nh", + "luximbi", + "FreeSans", + NULL, +}; + +static void font_destroy(struct graphics_font_priv *gf) +{ + /* TODO: free FT stuff? */ + 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, 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->library_init) { + FT_Init_FreeType( &gr->library ); + gr->library_init=1; + } + 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_new(struct graphics_gc_priv, 1); + *meth=gc_methods; + gc->gr=gr; + gc->linewidth=1; /* upper layer should override anyway? */ + return gc; +} + + +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 +}; + +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) +{ +#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; + *meth = gi_methods; + } + 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 * img) +{ + dbg(0,"TODO"); +} + +static void +get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret) +{ + 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 ); + 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; + int i; + + vx = alloca(count * sizeof(Sint16)); + vy = alloca(count * sizeof(Sint16)); + + for(i = 0; i < count; i++) + { + vx[i] = (Sint16)p[i].x; + vy[i] = (Sint16)p[i].y; +#ifdef DEBUG + printf("draw_polygon: %p %i %d,%d\n", gc, i, p[i].x, p[i].y); +#endif + } + + filledPolygonRGBA(gr->screen, vx, vy, count, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +} + + + +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 > DISPLAY_W) + { + w = DISPLAY_W-1; + } + if(h > DISPLAY_H) + { + h = DISPLAY_H-1; + } + 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); + +} + +static void +draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r) +{ + int l, a; +#ifdef DEBUG + printf("draw_circle: %d %d %d\n", p->x, p->y, r); +#endif + + /* FIXME: does not quite match gtk */ + + /* looks like GTK counts the outline in r, + sdl-gfx does not? + */ + r = r - 1; + + for(l = 0; l < gc->linewidth; l++) + { + a = l - (gc->linewidth/2); +#ifdef ANTI_ALIAS + aacircleRGBA(gr->screen, p->x, p->y, r - l, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#else + circleRGBA(gr->screen, p->x, p->y, r - l, + gc->fore_r, gc->fore_g, gc->fore_b, gc->fore_a); +#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 + + int l=round(sqrt(dx*dx+dy*dy)); + float angle; + + int x_lw_adj, y_lw_adj; + + if(lw == 1) + { +#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 + } + 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; + } + +#ifdef DEBUG + 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; + /* FIXME?: need extra copy of vert[0] here to "close" the poly? apparently not! */ + + 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]; +}; + +#ifndef _WIN32 +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)); /* do not use g_malloc() here */ + 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; +} +#else +/* TODO FIXME */ +static GdkImage * +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 *p, *pm=g->pixmap; + GdkImage *ret; + + ret=gdk_image_new( GDK_IMAGE_NORMAL , gdk_visual_get_system(), w+2, h+2); + + for (y = 0 ; y < h ; y++) { + p=ret->mem+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; + } + } + } + return ret; +} +#endif + +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; +} + +static void hexdump(unsigned char *buf, unsigned int n) +{ + int i; + for(i = 0; i < n; i++) + { + if((i&0xf)==0) + { + printf("\n%02x: ", i); + } + printf("%02x ", buf[i]); + } + printf("\n"); +} + +#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); + } +} +#endif + +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 = 255 - (i * r) / 256; + c.g = 255 - (i * g) / 256; + c.b = 255 - (i * b) / 256; + SDL_SetPalette(ss, SDL_LOGPAL, &c, i, 1); + } +} + +#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; + struct text_glyph *g, **gp; + SDL_Surface *ss; + SDL_Rect r; + SDL_Color b, f; + + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) + { + g=*gp++; + if(g->shadow && bg) + { + ss = SDL_CreateRGBSurfaceFrom(g->pixmap, g->w+2, g->h+2, 8, g->w+2, 0, 0, 0, 0); + if(ss) + { + //sdl_inv_grayscale_pal_set(ss); + sdl_scale_pal_set(ss, bg->back_r, bg->back_g, bg->back_b); + r.x = g->x-1; + r.y = g->y-1; + r.w = g->w+2; + r.h = g->h+2; + //printf("%d %d %d %d\n", g->x, g->y, g->w, g->h); + SDL_SetAlpha(ss, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); + //SDL_SetColorKey(ss, SDL_SRCCOLORKEY, 0x00); + SDL_BlitSurface(ss, NULL, gr->screen, &r); + SDL_FreeSurface(ss); + } + } + //if (g->shadow && bg) + //gdk_draw_image(gr->drawable, bg->gc, g->shadow, 0, 0, g->x-1, g->y-1, g->w+2, g->h+2); + } + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) + { + g=*gp++; + if (g->w && g->h) + { + //hexdump(g->pixmap, g->w * g->h); + + ss = SDL_CreateRGBSurfaceFrom(g->pixmap, g->w, g->h, 8, g->w, 0, 0, 0, 0); + if(ss) + { + //sdl_inv_grayscale_pal_set(ss); + sdl_scale_pal_set(ss, fg->fore_r, fg->fore_g, fg->fore_b); + //sdl_inv_bw_pal_set(ss); + r.x = g->x; + r.y = g->y; + r.w = g->w; + r.h = g->h; + //printf("%d %d %d %d\n", g->x, g->y, g->w, g->h); + //SDL_SetAlpha(ss, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); + SDL_SetColorKey(ss, SDL_SRCCOLORKEY, 0x00); + SDL_BlitSurface(ss, NULL, gr->screen, &r); + SDL_FreeSurface(ss); + } + } + //gdk_draw_gray_image(gr->drawable, fg->gc, g->x, g->y, g->w, g->h, GDK_RGB_DITHER_NONE, g->pixmap, g->w); + } +} + +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) +{ + SDL_Rect rect; + +#ifdef DEBUG + printf("draw_mode: %d\n", mode); +#endif + + if(mode == draw_mode_end) + { + /* TBD: just update the modified rects? that may be slower, actually */ + rect.x = 0; + rect.y = 0; + rect.w = DISPLAY_W; + rect.h = DISPLAY_H; + SDL_UpdateRects(gr->screen, 1, &rect); + } +} + +static struct graphics_priv * overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h); + +static void * +get_data(struct graphics_priv *this, char *type) +{ + printf("get_data: %s\n", type); + return &dummy; +} + + + +static void +register_resize_callback(struct graphics_priv *this, void (*callback)(void *data, int w, int h), void *data) +{ + this->resize_callback=callback; + this->resize_callback_data=data; + + if(this->resize_callback) + { + this->resize_callback(this->resize_callback_data, DISPLAY_W, DISPLAY_H); + } +} + +static void +register_motion_callback(struct graphics_priv *this, void (*callback)(void *data, struct point *p), void *data) +{ + this->motion_callback=callback; + this->motion_callback_data=data; +} + +static void +register_button_callback(struct graphics_priv *this, void (*callback)(void *data, int press, int button, struct point *p), void *data) +{ + this->button_callback=callback; + this->button_callback_data=data; +} + +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, + 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, +}; + +static struct graphics_priv * +overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h) +{ + return NULL; +} + +static gboolean graphics_sdl_idle(void *data) +{ + struct graphics_priv *gr = (struct graphics_priv *)data; + struct point p; + SDL_Event ev; + int ret; + + 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; + if(gr->motion_callback) + { + gr->motion_callback(gr->motion_callback_data, &p); + } + break; + } + + case SDL_KEYDOWN: + { + 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; + if(gr->button_callback) + { + gr->button_callback(gr->button_callback_data, 1, ev.button.button, &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; + if(gr->button_callback) + { + gr->button_callback(gr->button_callback_data, 0, ev.button.button, &p); + } + break; + } + + case SDL_QUIT: + { + //g_main_loop_quit(GMainLoop); + break; + } + +#if 0 + case SDL_VIDEOEXPOSE: + { + /* hack to repair damage */ + if(gr->resize_callback) + { + gr->resize_callback(gr->resize_callback_data, DISPLAY_W, DISPLAY_H); + } + break; + } +#endif + + default: + { +#ifdef DEBUG + printf("SDL_Event %d\n", ev.type); +#endif + break; + } + } + } + + return TRUE; +} + + +static struct graphics_priv * +graphics_sdl_new(struct graphics_methods *meth, struct attr **attrs) +{ + struct graphics_priv *this=g_new0(struct graphics_priv, 1); + int ret; + +#ifndef SDL_TTF + this->library_init = 0; +#endif + + 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; + } +#endif + + this->screen = SDL_SetVideoMode(DISPLAY_W, DISPLAY_H, 32, SDL_HWSURFACE); + if(this->screen == NULL) + { + g_free(this); + SDL_Quit(); + return NULL; + } + + SDL_WM_SetCaption("navit", NULL); + + *meth=graphics_methods; + + g_timeout_add(10, graphics_sdl_idle, this); + + return this; +} + +void +plugin_init(void) +{ + plugin_register_graphics_type("sdl", graphics_sdl_new); +} + diff --git a/navit/navit/gui/internal/gui_internal.c b/navit/navit/gui/internal/gui_internal.c index 2a74f67..25e4d0c 100644 --- a/navit/navit/gui/internal/gui_internal.c +++ b/navit/navit/gui/internal/gui_internal.c @@ -34,6 +34,7 @@ #include #include "config.h" #include "item.h" +#include "file.h" #include "navit.h" #include "debug.h" #include "gui.h" @@ -136,13 +137,29 @@ static struct widget * gui_internal_box_new(struct gui_priv *this, enum flags fl static void gui_internal_widget_append(struct widget *parent, struct widget *child); static void gui_internal_widget_destroy(struct gui_priv *this, struct widget *w); +static char * +image_path(char *name, int w, int h) +{ + char *full_name; + full_name=g_strdup_printf("%s/xpm/%s.svg", getenv("NAVIT_SHAREDIR"), name); + if (file_exists(full_name)) + return full_name; + full_name=g_strdup_printf("%s/xpm/%s.png", getenv("NAVIT_SHAREDIR"), name); + if (file_exists(full_name)) + return full_name; + return NULL; +} + static struct graphics_image * image_new(struct gui_priv *this, char *name) { - char *full_name=g_strdup_printf("xpm/%s.svg", name); - struct graphics_image *ret; + char *full_name=image_path(name, -1, -1); + struct graphics_image *ret=NULL; - ret=graphics_image_new(this->gra, full_name); + if (full_name); + ret=graphics_image_new(this->gra, full_name); + if (! ret) + dbg(0,"Failed to load %s\n", full_name); g_free(full_name); return ret; } @@ -151,10 +168,13 @@ image_new(struct gui_priv *this, char *name) static struct graphics_image * image_new_scaled(struct gui_priv *this, char *name, int w, int h) { - char *full_name=g_strdup_printf("xpm/%s.svg", name); - struct graphics_image *ret; + char *full_name=image_path(name, w, h); + struct graphics_image *ret=NULL; - ret=graphics_image_new_scaled(this->gra, full_name, w, h); + if (full_name); + ret=graphics_image_new_scaled(this->gra, full_name, w, h); + if (! ret) + dbg(0,"Failed to load %s\n", full_name); g_free(full_name); return ret; } @@ -227,8 +247,10 @@ gui_internal_image_new(struct gui_priv *this, struct graphics_image *image) struct widget *widget=g_new0(struct widget, 1); widget->type=widget_image; widget->img=image; - widget->w=widget->img->width; - widget->h=widget->img->height; + if (image) { + widget->w=image->width; + widget->h=image->height; + } return widget; } @@ -268,6 +290,8 @@ gui_internal_button_new_with_callback(struct gui_priv *this, char *text, struct ret=gui_internal_label_new(this, text); if (image) ret=gui_internal_image_new(this, image); + if (! ret) + ret=gui_internal_box_new(this, flags); } if (ret) { ret->func=func; diff --git a/navit/navit/route.c b/navit/navit/route.c index ad8cb9d..7b58b0a 100644 --- a/navit/navit/route.c +++ b/navit/navit/route.c @@ -1021,7 +1021,7 @@ route_graph_update(struct route *this) struct street_data * street_get_data (struct item *item) { - int maxcount=2000; + int maxcount=4000; struct coord c[maxcount]; int count=0; struct street_data *ret; -- 2.7.4