summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/Makefile.am19
-rw-r--r--graphics/gd/Makefile.am9
-rw-r--r--graphics/gd/graphics_gd.c547
-rw-r--r--graphics/gtk_drawing_area/Makefile.am5
-rw-r--r--graphics/gtk_drawing_area/graphics_gtk_drawing_area.c1096
-rw-r--r--graphics/gtk_gl_ext/graphics_gtk_gl_ext.c352
-rw-r--r--graphics/null/Makefile.am9
-rw-r--r--graphics/null/graphics_null.c231
-rw-r--r--graphics/opengl/Makefile.am6
-rw-r--r--graphics/opengl/graphics_opengl.c845
-rw-r--r--graphics/qt_qpainter/Makefile.am10
-rw-r--r--graphics/qt_qpainter/graphics_qt_qpainter.cpp1214
-rw-r--r--graphics/sdl/Makefile.am5
-rw-r--r--graphics/sdl/graphics_sdl.c2146
-rw-r--r--graphics/sdl/raster.c2022
-rw-r--r--graphics/sdl/raster.h25
-rw-r--r--graphics/win32/Makefile.am9
-rw-r--r--graphics/win32/graphics_win32.c1074
-rw-r--r--graphics/win32/graphics_win32.h59
-rw-r--r--graphics/win32/resources/resource.h4
-rw-r--r--graphics/win32/xpm2bmp.c588
-rw-r--r--graphics/win32/xpm2bmp.h44
22 files changed, 10319 insertions, 0 deletions
diff --git a/graphics/Makefile.am b/graphics/Makefile.am
new file mode 100644
index 00000000..af999d00
--- /dev/null
+++ b/graphics/Makefile.am
@@ -0,0 +1,19 @@
+SUBDIRS=null
+if GRAPHICS_GTK_DRAWING_AREA
+ SUBDIRS+=gtk_drawing_area
+endif
+if GRAPHICS_OPENGL
+ SUBDIRS+=opengl
+endif
+if GRAPHICS_QT_QPAINTER
+ SUBDIRS+=qt_qpainter
+endif
+if USE_GRAPHICS_SDL
+ SUBDIRS+=sdl
+endif
+if GRAPHICS_WIN32
+ SUBDIRS+=win32
+endif
+if GRAPHICS_GD
+ SUBDIRS+=gd
+endif
diff --git a/graphics/gd/Makefile.am b/graphics/gd/Makefile.am
new file mode 100644
index 00000000..67fc270a
--- /dev/null
+++ b/graphics/gd/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ @GD_CFLAGS@ -I$(top_srcdir) -I$(top_srcdir)/navit -DMODULE=graphics_gd
+libgraphics_gd_la_LDFLAGS = @GD_LIBS@ -module -avoid-version
+if PLUGINS
+modulegraphics_LTLIBRARIES = libgraphics_gd.la
+else
+noinst_LTLIBRARIES = libgraphics_gd.la
+endif
+libgraphics_gd_la_SOURCES = graphics_gd.c
diff --git a/graphics/gd/graphics_gd.c b/graphics/gd/graphics_gd.c
new file mode 100644
index 00000000..d53fcb62
--- /dev/null
+++ b/graphics/gd/graphics_gd.c
@@ -0,0 +1,547 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <gd.h>
+#include "config.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "plugin.h"
+#include "callback.h"
+#include "window.h"
+#include "navit.h"
+#include "debug.h"
+#include "navit/font/freetype/font_freetype.h"
+
+#define NAVIT_GD_XPM_TRANSPARENCY_HACK
+
+#ifdef NAVIT_GD_XPM_TRANSPARENCY_HACK
+#include <X11/xpm.h>
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromXpm (char *filename)
+{
+ XpmInfo info;
+ XpmImage image;
+ int i, j, k, number;
+ char buf[5];
+ gdImagePtr im = 0;
+ int *pointer;
+ int red = 0, green = 0, blue = 0, alpha = 0;
+ int *colors;
+ int ret;
+
+ ret = XpmReadFileToXpmImage (filename, &image, &info);
+ if (ret != XpmSuccess)
+ return 0;
+
+ if (!(im = gdImageCreate (image.width, image.height)))
+ return 0;
+
+ number = image.ncolors;
+ if (overflow2(sizeof (int), number)) {
+ return 0;
+ }
+ colors = (int *) gdMalloc (sizeof (int) * number);
+ if (colors == NULL)
+ return (0);
+ for (i = 0; i < number; i++)
+ {
+ alpha = 0;
+ switch (strlen (image.colorTable[i].c_color))
+ {
+ case 4:
+ if (!strcasecmp(image.colorTable[i].c_color,"none")) {
+ red = 0;
+ green = 0;
+ blue = 0;
+ alpha = 127;
+ } else {
+ buf[1] = '\0';
+ buf[0] = image.colorTable[i].c_color[1];
+ red = strtol (buf, NULL, 16);
+
+ buf[0] = image.colorTable[i].c_color[3];
+ green = strtol (buf, NULL, 16);
+
+ buf[0] = image.colorTable[i].c_color[5];
+ blue = strtol (buf, NULL, 16);
+ }
+ break;
+ case 7:
+ buf[2] = '\0';
+ buf[0] = image.colorTable[i].c_color[1];
+ buf[1] = image.colorTable[i].c_color[2];
+ red = strtol (buf, NULL, 16);
+
+ buf[0] = image.colorTable[i].c_color[3];
+ buf[1] = image.colorTable[i].c_color[4];
+ green = strtol (buf, NULL, 16);
+
+ buf[0] = image.colorTable[i].c_color[5];
+ buf[1] = image.colorTable[i].c_color[6];
+ blue = strtol (buf, NULL, 16);
+ break;
+ case 10:
+ buf[3] = '\0';
+ buf[0] = image.colorTable[i].c_color[1];
+ buf[1] = image.colorTable[i].c_color[2];
+ buf[2] = image.colorTable[i].c_color[3];
+ red = strtol (buf, NULL, 16);
+ red /= 64;
+
+ buf[0] = image.colorTable[i].c_color[4];
+ buf[1] = image.colorTable[i].c_color[5];
+ buf[2] = image.colorTable[i].c_color[6];
+ green = strtol (buf, NULL, 16);
+ green /= 64;
+
+ buf[0] = image.colorTable[i].c_color[7];
+ buf[1] = image.colorTable[i].c_color[8];
+ buf[2] = image.colorTable[i].c_color[9];
+ blue = strtol (buf, NULL, 16);
+ blue /= 64;
+ break;
+ case 13:
+ buf[4] = '\0';
+ buf[0] = image.colorTable[i].c_color[1];
+ buf[1] = image.colorTable[i].c_color[2];
+ buf[2] = image.colorTable[i].c_color[3];
+ buf[3] = image.colorTable[i].c_color[4];
+ red = strtol (buf, NULL, 16);
+ red /= 256;
+
+ buf[0] = image.colorTable[i].c_color[5];
+ buf[1] = image.colorTable[i].c_color[6];
+ buf[2] = image.colorTable[i].c_color[7];
+ buf[3] = image.colorTable[i].c_color[8];
+ green = strtol (buf, NULL, 16);
+ green /= 256;
+
+ buf[0] = image.colorTable[i].c_color[9];
+ buf[1] = image.colorTable[i].c_color[10];
+ buf[2] = image.colorTable[i].c_color[11];
+ buf[3] = image.colorTable[i].c_color[12];
+ blue = strtol (buf, NULL, 16);
+ blue /= 256;
+ break;
+ }
+
+
+ colors[i] = gdImageColorResolveAlpha(im, red, green, blue, alpha);
+ if (colors[i] == -1)
+ fprintf (stderr, "ARRRGH\n");
+ }
+
+ pointer = (int *) image.data;
+ for (i = 0; i < image.height; i++)
+ {
+ for (j = 0; j < image.width; j++)
+ {
+ k = *pointer++;
+ gdImageSetPixel (im, j, i, colors[k]);
+ }
+ }
+ gdFree (colors);
+ return (im);
+}
+#endif
+
+
+struct graphics_priv {
+ gdImagePtr im;
+ int w,h;
+ struct callback *cb;
+ struct callback_list *cbl;
+ struct navit *nav;
+ struct graphics_gc_priv *background;
+ struct font_freetype_methods freetype_methods;
+ struct window window;
+ struct graphics_data_image image;
+};
+
+struct graphics_gc_priv {
+ struct graphics_priv *gr;
+ int color;
+ int bgcolor;
+ int width;
+ unsigned char *dash_list;
+ int dash_count;
+ int dash_list_len;
+};
+
+struct graphics_image_priv {
+ gdImagePtr im;
+};
+
+
+static void
+graphics_destroy(struct graphics_priv *gr)
+{
+ g_free(gr);
+}
+
+static void
+gc_destroy(struct graphics_gc_priv *gc)
+{
+ if (gc->color != -1)
+ gdImageColorDeallocate(gc->gr->im, gc->color);
+ if (gc->bgcolor != -1)
+ gdImageColorDeallocate(gc->gr->im, gc->bgcolor);
+ g_free(gc->dash_list);
+ g_free(gc);
+}
+
+static void
+gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+ gc->width=w;
+}
+
+static void
+gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
+{
+ int i,count=0;
+ g_free(gc->dash_list);
+ gc->dash_list=g_new(unsigned char, n);
+ for (i = 0 ; i < n ; i++) {
+ gc->dash_list[i]=dash_list[i];
+ count+=dash_list[i];
+ }
+ gc->dash_list_len=n;
+ gc->dash_count=count;
+}
+
+static void
+gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->color=gdImageColorAllocate(gc->gr->im, c->r>>8, c->g>>8, c->b>>8);
+}
+
+static void
+gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->bgcolor=gdImageColorAllocate(gc->gr->im, c->r>>8, c->g>>8, c->b>>8);
+}
+
+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 *ret=g_new0(struct graphics_gc_priv, 1);
+ ret->gr=gr;
+ ret->width=1;
+ ret->color=-1;
+ ret->bgcolor=-1;
+ *meth=gc_methods;
+ return ret;
+}
+
+
+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)
+{
+ FILE *file;
+ struct graphics_image_priv *ret=NULL;
+ gdImagePtr im=NULL;
+ int len;
+
+ if (! name)
+ return NULL;
+ len=strlen(name);
+ if (len < 4)
+ return NULL;
+ file=fopen(name,"r");
+ if (file) {
+ if (!strcmp(name+len-4,".png"))
+ im=gdImageCreateFromPng(file);
+ else if (!strcmp(name+len-4,".xpm"))
+ im=gdImageCreateFromXpm(name);
+ fclose(file);
+ }
+ if (im) {
+ ret=g_new0(struct graphics_image_priv, 1);
+ ret->im=im;
+ *w=im->sx;
+ *h=im->sy;
+ hot->x=im->sx/2;
+ hot->y=im->sy/2;
+ }
+ return ret;
+}
+
+static void
+draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int color[gc->dash_count],cc;
+ int i,j,k=0;
+
+ if (gc->dash_count) {
+ cc=gc->color;
+ for (i = 0 ; i < gc->dash_list_len ; i++) {
+ for (j = 0 ; j < gc->dash_list[i] ; j++) {
+ color[k++]=cc;
+ }
+ if (cc == gdTransparent)
+ cc=gc->color;
+ else
+ cc=gdTransparent;
+ }
+ gdImageSetStyle(gr->im, color, gc->dash_count);
+ }
+ gdImageSetThickness(gr->im, gc->width);
+ gdImageOpenPolygon(gr->im, (gdPointPtr) p, count, gc->dash_count ? gdStyled : gc->color);
+}
+
+static void
+draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+
+ gdImageFilledPolygon(gr->im, (gdPointPtr) p, count, gc->color);
+}
+
+static void
+draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+ gdImageFilledRectangle(gr->im, p->x, p->y, p->x+w, p->y+h, gc->color);
+}
+
+static void
+draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+ gdImageSetThickness(gr->im, gc->width);
+ gdImageArc(gr->im, p->x, p->y, r, r, 0, 360, gc->color);
+}
+
+
+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 font_freetype_text *t;
+ struct font_freetype_glyph *g, **gp;
+ gdImagePtr im;
+ int i,x,y,w,h;
+ t=gr->freetype_methods.text_new(text, (struct font_freetype_font *)font, dx, dy);
+ struct color transparent = {0x0, 0x0, 0x0, 0x7f7f};
+ struct color white = {0xffff, 0xffff, 0xffff, 0x0};
+ struct color black = {0x0, 0x0, 0x0, 0x0};
+
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=t->glyph;
+ i=t->glyph_count;
+ while (i-- > 0)
+ {
+ g=*gp++;
+ w=g->w;
+ h=g->h;
+ if (w && h) {
+ im=gdImageCreateTrueColor(w+2, h+2);
+ gr->freetype_methods.get_shadow(g,(unsigned char *)(im->tpixels),32,0,&white,&transparent);
+ gdImageCopy(gr->im, im, ((x+g->x)>>6)-1, ((y+g->y)>>6)-1, 0, 0, w+2, h+2);
+ gdImageDestroy(im);
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=t->glyph;
+ i=t->glyph_count;
+ while (i-- > 0)
+ {
+ g=*gp++;
+ w=g->w;
+ h=g->h;
+ if (w && h) {
+ im=gdImageCreateTrueColor(w, h);
+ gr->freetype_methods.get_glyph(g,(unsigned char *)(im->tpixels),32,0,&black,&white,&transparent);
+ gdImageCopy(gr->im, im, (x+g->x)>>6, (y+g->y)>>6, 0, 0, w, h);
+ gdImageDestroy(im);
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ gr->freetype_methods.text_destroy(t);
+}
+
+static void
+draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+ gdImageCopy(gr->im, img->im, p->x, p->y, 0, 0, img->im->sx, img->im->sy);
+}
+
+static void
+draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
+{
+}
+
+static void
+draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+}
+
+static void
+background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ gr->background=gc;
+}
+
+static void
+draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ FILE *pngout;
+#if 0
+ if (mode == draw_mode_begin && gr->background) {
+ gdImageFilledRectangle(gr->im, 0, 0, gr->w, gr->h, gr->background->color);
+ }
+#endif
+ if (mode == draw_mode_end) {
+ rename("test.png","test.png.old");
+ pngout=fopen("test.png", "wb");
+ gdImagePng(gr->im, pngout);
+ fclose(pngout);
+ }
+}
+
+static struct graphics_priv * overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha);
+
+static void *
+get_data(struct graphics_priv *this, char *type)
+{
+ int b;
+ struct point p;
+ if (!strcmp(type,"window"))
+ return &this->window;
+ if (!strcmp(type,"image_png")) {
+ if (this->image.data)
+ gdFree(this->image.data);
+ this->image.data=gdImagePngPtr(this->im, &this->image.size);
+ return &this->image;
+ }
+ if (sscanf(type,"click_%d_%d_%d",&p.x,&p.y,&b) == 3) {
+ if (this->image.data)
+ gdFree(this->image.data);
+ this->image.data=0;
+ this->image.size=0;
+
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)b, (void *)1, (void *)&p);
+
+ return &this->image;
+ }
+ return NULL;
+}
+
+
+static void
+image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
+{
+ gdImageDestroy(priv->im);
+ g_free(priv);
+}
+
+static void
+overlay_disable(struct graphics_priv *gr, int disable)
+{
+ dbg(0,"enter\n");
+}
+
+
+
+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,
+ NULL,
+ NULL,
+ gc_new,
+ background_gc,
+ overlay_new,
+ image_new,
+ get_data,
+ image_free,
+ NULL,
+ overlay_disable,
+};
+
+static struct graphics_priv *
+overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h, int alpha)
+{
+ *meth=graphics_methods;
+ return NULL;
+}
+
+static void
+emit_callback(struct graphics_priv *priv)
+{
+ callback_list_call_attr_2(priv->cbl, attr_resize, (void *)priv->w, (void *)priv->h);
+}
+
+
+static struct graphics_priv *
+graphics_gd_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
+{
+ struct font_priv * (*font_freetype_new)(void *meth);
+ struct graphics_priv *ret;
+ struct attr *attr;
+ event_request_system("glib","graphics_gtk_drawing_area_new");
+ font_freetype_new=plugin_get_font_type("freetype");
+ if (!font_freetype_new)
+ return NULL;
+ *meth=graphics_methods;
+ ret=g_new0(struct graphics_priv, 1);
+ font_freetype_new(&ret->freetype_methods);
+ meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *, int, int))ret->freetype_methods.font_new;
+ meth->get_text_bbox=ret->freetype_methods.get_text_bbox;
+ ret->cb=callback_new_attr_1(callback_cast(emit_callback), attr_navit, ret);
+ navit_add_callback(nav, ret->cb);
+ ret->cbl=cbl;
+ ret->nav=nav;
+ attr=attr_search(attrs, NULL, attr_w);
+ if (attr)
+ ret->w=attr->u.num;
+ else
+ ret->w=800;
+ attr=attr_search(attrs, NULL, attr_h);
+ if (attr)
+ ret->h=attr->u.num;
+ else
+ ret->h=600;
+ ret->im=gdImageCreateTrueColor(ret->w,ret->h);
+ return ret;
+}
+
+void
+plugin_init(void)
+{
+ plugin_register_graphics_type("gd", graphics_gd_new);
+}
diff --git a/graphics/gtk_drawing_area/Makefile.am b/graphics/gtk_drawing_area/Makefile.am
new file mode 100644
index 00000000..79da228d
--- /dev/null
+++ b/graphics/gtk_drawing_area/Makefile.am
@@ -0,0 +1,5 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @GTK2_CFLAGS@ -I$(top_srcdir) -I$(top_srcdir)/navit -DMODULE=graphics_gtk_drawing_area
+modulegraphics_LTLIBRARIES = libgraphics_gtk_drawing_area.la
+libgraphics_gtk_drawing_area_la_SOURCES = graphics_gtk_drawing_area.c
+libgraphics_gtk_drawing_area_la_LDFLAGS = @GTK2_LIBS@ @IMLIB2_LIBS@ -module -avoid-version
diff --git a/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c b/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c
new file mode 100644
index 00000000..f9020067
--- /dev/null
+++ b/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c
@@ -0,0 +1,1096 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#define GDK_ENABLE_BROKEN
+#include "config.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/time.h>
+#if !defined(GDK_Book) || !defined(GDK_Calendar)
+#include <X11/XF86keysym.h>
+#endif
+#ifdef HAVE_IMLIB2
+#include <Imlib2.h>
+#endif
+
+#ifndef _WIN32
+#include <gdk/gdkx.h>
+#endif
+#include "event.h"
+#include "debug.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "item.h"
+#include "window.h"
+#include "callback.h"
+#include "keys.h"
+#include "plugin.h"
+#include "navit/font/freetype/font_freetype.h"
+#include "navit.h"
+
+#ifndef GDK_Book
+#define GDK_Book XF86XK_Book
+#endif
+#ifndef GDK_Calendar
+#define GDK_Calendar XF86XK_Calendar
+#endif
+
+
+struct graphics_priv {
+ GdkEventButton button_event;
+ int button_timeout;
+ GtkWidget *widget;
+ GtkWidget *win;
+ struct window window;
+ GdkDrawable *drawable;
+ GdkDrawable *background;
+ int background_ready;
+ GdkColormap *colormap;
+ struct point p;
+ struct point pclean;
+ int cleanup;
+ int width;
+ int height;
+ int win_w;
+ int win_h;
+ int visible;
+ int overlay_disabled;
+ int overlay_autodisabled;
+ int a;
+ int wraparound;
+ struct graphics_priv *parent;
+ struct graphics_priv *overlays;
+ struct graphics_priv *next;
+ struct graphics_gc_priv *background_gc;
+ enum draw_mode_num mode;
+ struct callback_list *cbl;
+ struct font_freetype_methods freetype_methods;
+ struct navit *nav;
+ int pid;
+ struct timeval button_press[8];
+ struct timeval button_release[8];
+};
+
+
+struct graphics_gc_priv {
+ GdkGC *gc;
+ GdkPixmap *pixmap;
+ struct graphics_priv *gr;
+ int level;
+ unsigned char r,g,b,a;
+};
+
+struct graphics_image_priv {
+ GdkPixbuf *pixbuf;
+ int w;
+ int h;
+};
+
+static void
+graphics_destroy(struct graphics_priv *gr)
+{
+}
+
+static void
+gc_destroy(struct graphics_gc_priv *gc)
+{
+ g_object_unref(gc->gc);
+ g_free(gc);
+}
+
+static void
+gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+ gdk_gc_set_line_attributes(gc->gc, w, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+}
+
+static void
+gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
+{
+ gdk_gc_set_dashes(gc->gc, offset, (gint8 *)dash_list, n);
+ gdk_gc_set_line_attributes(gc->gc, w, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+}
+
+static void
+gc_set_color(struct graphics_gc_priv *gc, struct color *c, int fg)
+{
+ GdkColor gdkc;
+ gdkc.pixel=0;
+ gdkc.red=c->r;
+ gdkc.green=c->g;
+ gdkc.blue=c->b;
+ gdk_colormap_alloc_color(gc->gr->colormap, &gdkc, FALSE, TRUE);
+ gdk_colormap_query_color(gc->gr->colormap, gdkc.pixel, &gdkc);
+ gc->r=gdkc.red >> 8;
+ gc->g=gdkc.green >> 8;
+ gc->b=gdkc.blue >> 8;
+ gc->a=c->a >> 8;
+ if (fg) {
+ gdk_gc_set_foreground(gc->gc, &gdkc);
+ gc->level=(c->r+c->g+c->b)/3;
+ } else
+ gdk_gc_set_background(gc->gc, &gdkc);
+}
+
+static void
+gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc_set_color(gc, c, 1);
+}
+
+static void
+gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc_set_color(gc, c, 0);
+}
+
+static void
+gc_set_stipple(struct graphics_gc_priv *gc, struct graphics_image_priv *img)
+{
+ char data[2]={0x2,0x1};
+ gdk_gc_set_fill(gc->gc, GDK_STIPPLED);
+ gc->pixmap=gdk_bitmap_create_from_data(gc->gr->widget->window, data, 2, 2);
+ gdk_gc_set_stipple(gc->gc, gc->pixmap);
+}
+
+static struct graphics_gc_methods gc_methods = {
+ gc_destroy,
+ gc_set_linewidth,
+ gc_set_dashes,
+ gc_set_foreground,
+ gc_set_background,
+ gc_set_stipple,
+};
+
+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->gc=gdk_gc_new(gr->widget->window);
+ gc->gr=gr;
+ return gc;
+}
+
+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)
+{
+ GdkPixbuf *pixbuf;
+ struct graphics_image_priv *ret;
+ const char *option;
+
+ if (*w == -1 && *h == -1)
+ pixbuf=gdk_pixbuf_new_from_file(name, NULL);
+ else
+ pixbuf=gdk_pixbuf_new_from_file_at_size(name, *w, *h, NULL);
+ if (! pixbuf)
+ return NULL;
+ if (rotation) {
+ GdkPixbuf *tmp;
+ switch (rotation) {
+ case 90:
+ rotation=270;
+ break;
+ case 180:
+ break;
+ case 270:
+ rotation=90;
+ break;
+ default:
+ return NULL;
+ }
+ tmp=gdk_pixbuf_rotate_simple(pixbuf, rotation);
+ g_object_unref(pixbuf);
+ if (! tmp) {
+ return NULL;
+ }
+ pixbuf=tmp;
+ }
+ ret=g_new0(struct graphics_image_priv, 1);
+ ret->pixbuf=pixbuf;
+ ret->w=gdk_pixbuf_get_width(pixbuf);
+ ret->h=gdk_pixbuf_get_height(pixbuf);
+ *w=ret->w;
+ *h=ret->h;
+ if (hot) {
+ option=gdk_pixbuf_get_option(pixbuf, "x_hot");
+ if (option)
+ hot->x=atoi(option);
+ else
+ hot->x=ret->w/2-1;
+ option=gdk_pixbuf_get_option(pixbuf, "y_hot");
+ if (option)
+ hot->y=atoi(option);
+ else
+ hot->y=ret->h/2-1;
+ }
+ return ret;
+}
+
+static void
+image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
+{
+ if (priv->pixbuf)
+ g_object_unref(priv->pixbuf);
+ g_free(priv);
+}
+
+static void
+draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+ gdk_draw_lines(gr->drawable, gc->gc, (GdkPoint *)p, count);
+ if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
+ gdk_draw_lines(gr->widget->window, gc->gc, (GdkPoint *)p, count);
+}
+
+static void
+draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+ gdk_draw_polygon(gr->drawable, gc->gc, TRUE, (GdkPoint *)p, count);
+ if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
+ gdk_draw_polygon(gr->widget->window, gc->gc, TRUE, (GdkPoint *)p, count);
+}
+
+static void
+draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+ gdk_draw_rectangle(gr->drawable, gc->gc, TRUE, p->x, p->y, w, h);
+}
+
+static void
+draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+ if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+ gdk_draw_arc(gr->drawable, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
+ if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
+ gdk_draw_arc(gr->widget->window, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
+}
+
+static void
+display_text_draw(struct font_freetype_text *text, struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct point *p)
+{
+ int i,x,y;
+ struct font_freetype_glyph *g, **gp;
+ unsigned char *shadow;
+ struct color transparent={0x0,0x0,0x0,0x0};
+ struct color white={0xffff,0xffff,0xffff,0xffff};
+
+ gp=text->glyph;
+ i=text->glyph_count;
+ x=p->x << 6;
+ y=p->y << 6;
+ while (i-- > 0)
+ {
+ g=*gp++;
+ if (g->w && g->h && bg ) {
+#if 1
+ shadow=g_malloc((g->w+2)*(g->h+2));
+ if (gr->freetype_methods.get_shadow(g, shadow, 8, g->w+2, &white, &transparent))
+ gdk_draw_gray_image(gr->drawable, bg->gc, ((x+g->x)>>6)-1, ((y+g->y)>>6)-1, g->w+2, g->h+2, GDK_RGB_DITHER_NONE, shadow, g->w+2);
+ g_free(shadow);
+#else
+ GdkImage *image;
+ stride=(g->w+9)/8;
+ shadow=malloc(stride*(g->h+2));
+
+ gr->freetype_methods.get_shadow(g, shadow, 1, stride);
+ image=gdk_image_new_bitmap(gdk_visual_get_system(),shadow,g->w+2, g->h+2);
+ gdk_draw_image(gr->drawable, bg->gc, image, 0, 0, ((x+g->x)>>6)-1, ((y+g->y)>>6)-1, g->w+2, g->h+2);
+ g_object_unref(image);
+#endif
+
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=text->glyph;
+ i=text->glyph_count;
+ while (i-- > 0)
+ {
+ g=*gp++;
+ if (g->w && g->h)
+ gdk_draw_gray_image(gr->drawable, fg->gc, (x+g->x)>>6, (y+g->y)>>6, g->w, g->h, GDK_RGB_DITHER_NONE, g->pixmap, g->w);
+ x+=g->dx;
+ y+=g->dy;
+ }
+}
+
+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 font_freetype_text *t;
+
+ if (! font)
+ {
+ dbg(0,"no font, returning\n");
+ return;
+ }
+#if 0 /* Temporarily disabled because it destroys text rendering of overlays and in gui internal in some places */
+ /*
+ This needs an improvement, no one checks if the strings are visible
+ */
+ if (p->x > gr->width-50 || p->y > gr->height-50) {
+ return;
+ }
+ if (p->x < -50 || p->y < -50) {
+ return;
+ }
+#endif
+
+ if (bg) {
+ if (bg->level > 32767) {
+ gdk_gc_set_function(fg->gc, GDK_AND_INVERT);
+ gdk_gc_set_function(bg->gc, GDK_OR);
+ } else {
+ gdk_gc_set_function(fg->gc, GDK_OR);
+ gdk_gc_set_function(bg->gc, GDK_AND_INVERT);
+ }
+ }
+
+ t=gr->freetype_methods.text_new(text, (struct font_freetype_font *)font, dx, dy);
+ display_text_draw(t, gr, fg, bg, p);
+ gr->freetype_methods.text_destroy(t);
+ if (bg) {
+ gdk_gc_set_function(fg->gc, GDK_COPY);
+ gdk_gc_set_function(bg->gc, GDK_COPY);
+ }
+#if 0
+ {
+ struct point pnt[5];
+ int i;
+ gr->freetype_methods.get_text_bbox(gr, font, text, dx, dy, pnt, 1);
+ for (i = 0 ; i < 4 ; i++) {
+ pnt[i].x+=p->x;
+ pnt[i].y+=p->y;
+ }
+ pnt[4]=pnt[0];
+ gdk_draw_lines(gr->drawable, fg->gc, (GdkPoint *)pnt, 5);
+ }
+#endif
+}
+
+static void
+draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+ gdk_draw_pixbuf(gr->drawable, fg->gc, img->pixbuf, 0, 0, p->x, p->y,
+ img->w, img->h, GDK_RGB_DITHER_NONE, 0, 0);
+}
+
+#ifdef HAVE_IMLIB2
+static void
+draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
+{
+ void *image;
+ int w,h;
+ dbg(1,"draw_image_warp data=%s\n", data);
+ image = imlib_load_image(data);
+ imlib_context_set_display(gdk_x11_drawable_get_xdisplay(gr->widget->window));
+ imlib_context_set_colormap(gdk_x11_colormap_get_xcolormap(gtk_widget_get_colormap(gr->widget)));
+ imlib_context_set_visual(gdk_x11_visual_get_xvisual(gtk_widget_get_visual(gr->widget)));
+ imlib_context_set_drawable(gdk_x11_drawable_get_xid(gr->drawable));
+ imlib_context_set_image(image);
+ w = imlib_image_get_width();
+ h = imlib_image_get_height();
+ if (count == 3) {
+ /* 0 1
+ 2 */
+ imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x, p[0].y, p[1].x-p[0].x, p[1].y-p[0].y, p[2].x-p[0].x, p[2].y-p[0].y);
+ }
+ if (count == 2) {
+ /* 0
+ 1 */
+ imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x, p[0].y, p[1].x-p[0].x, 0, 0, p[1].y-p[0].y);
+ }
+ if (count == 1) {
+ /*
+ 0
+ */
+ imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x-w/2, p[0].y-h/2, w, 0, 0, h);
+ }
+ imlib_free_image();
+}
+#endif
+
+static void
+overlay_rect(struct graphics_priv *parent, struct graphics_priv *overlay, int clean, GdkRectangle *r)
+{
+ if (clean) {
+ r->x=overlay->pclean.x;
+ r->y=overlay->pclean.y;
+ } else {
+ r->x=overlay->p.x;
+ r->y=overlay->p.y;
+ }
+ r->width=overlay->width;
+ r->height=overlay->height;
+ if (!overlay->wraparound)
+ return;
+ if (r->x < 0)
+ r->x += parent->width;
+ if (r->y < 0)
+ r->y += parent->height;
+ if (r->width < 0)
+ r->width += parent->width;
+ if (r->height < 0)
+ r->height += parent->height;
+}
+
+static void
+overlay_draw(struct graphics_priv *parent, struct graphics_priv *overlay, GdkRectangle *r, GdkPixmap *pixmap, GdkGC *gc)
+{
+ GdkPixbuf *pixbuf,*pixbuf2;
+ guchar *pixels1, *pixels2, *p1, *p2;
+ int x,y;
+ int rowstride1,rowstride2;
+ int n_channels1,n_channels2;
+ GdkRectangle or,ir;
+ struct graphics_gc_priv *bg=overlay->background_gc;
+
+ if (parent->overlay_disabled || overlay->overlay_disabled || overlay->overlay_autodisabled)
+ return;
+ dbg(1,"r->x=%d r->y=%d r->width=%d r->height=%d\n", r->x, r->y, r->width, r->height);
+ overlay_rect(parent, overlay, 0, &or);
+ dbg(1,"or.x=%d or.y=%d or.width=%d or.height=%d\n", or.x, or.y, or.width, or.height);
+ if (! gdk_rectangle_intersect(r, &or, &ir))
+ return;
+ or.x-=r->x;
+ or.y-=r->y;
+ pixbuf=gdk_pixbuf_get_from_drawable(NULL, overlay->drawable, NULL, 0, 0, 0, 0, or.width, or.height);
+ pixbuf2=gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pixbuf), TRUE, gdk_pixbuf_get_bits_per_sample(pixbuf),
+ or.width, or.height);
+ rowstride1 = gdk_pixbuf_get_rowstride (pixbuf);
+ rowstride2 = gdk_pixbuf_get_rowstride (pixbuf2);
+ pixels1=gdk_pixbuf_get_pixels (pixbuf);
+ pixels2=gdk_pixbuf_get_pixels (pixbuf2);
+ n_channels1 = gdk_pixbuf_get_n_channels (pixbuf);
+ n_channels2 = gdk_pixbuf_get_n_channels (pixbuf2);
+ for (y = 0 ; y < or.height ; y++) {
+ for (x = 0 ; x < or.width ; x++) {
+ p1 = pixels1 + y * rowstride1 + x * n_channels1;
+ p2 = pixels2 + y * rowstride2 + x * n_channels2;
+ p2[0]=p1[0];
+ p2[1]=p1[1];
+ p2[2]=p1[2];
+ if (bg && p1[0] == bg->r && p1[1] == bg->g && p1[2] == bg->b)
+ p2[3]=bg->a;
+ else
+ p2[3]=overlay->a;
+ }
+ }
+ gdk_draw_pixbuf(pixmap, gc, pixbuf2, 0, 0, or.x, or.y, or.width, or.height, GDK_RGB_DITHER_NONE, 0, 0);
+ g_object_unref(pixbuf);
+ g_object_unref(pixbuf2);
+}
+
+static void
+draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+ GtkWidget *widget=gr->widget;
+ gdk_draw_drawable(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ gr->drawable,
+ p->x, p->y, p->x, p->y, w, h);
+
+}
+
+static void
+draw_drag(struct graphics_priv *gr, struct point *p)
+{
+ if (!gr->cleanup) {
+ gr->pclean=gr->p;
+ gr->cleanup=1;
+ }
+ if (p)
+ gr->p=*p;
+ else {
+ gr->p.x=0;
+ gr->p.y=0;
+ }
+}
+
+
+static void
+background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ gr->background_gc=gc;
+}
+
+static void
+gtk_drawing_area_draw(struct graphics_priv *gr, GdkRectangle *r)
+{
+ GdkPixmap *pixmap;
+ GtkWidget *widget=gr->widget;
+ GdkGC *gc=widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
+ struct graphics_priv *overlay;
+
+ if (! gr->drawable)
+ return;
+ pixmap = gdk_pixmap_new(widget->window, r->width, r->height, -1);
+ if ((gr->p.x || gr->p.y) && gr->background_gc)
+ gdk_draw_rectangle(pixmap, gr->background_gc->gc, TRUE, 0, 0, r->width, r->height);
+ gdk_draw_drawable(pixmap, gc, gr->drawable, r->x, r->y, gr->p.x, gr->p.y, r->width, r->height);
+ overlay=gr->overlays;
+ while (overlay) {
+ overlay_draw(gr,overlay,r,pixmap,gc);
+ overlay=overlay->next;
+ }
+ gdk_draw_drawable(widget->window, gc, pixmap, 0, 0, r->x, r->y, r->width, r->height);
+ g_object_unref(pixmap);
+}
+
+static void
+draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ GdkRectangle r;
+ struct graphics_priv *overlay;
+#if 0
+ if (mode == draw_mode_begin) {
+ if (! gr->parent && gr->background_gc)
+ gdk_draw_rectangle(gr->drawable, gr->background_gc->gc, TRUE, 0, 0, gr->width, gr->height);
+ }
+#endif
+ if (mode == draw_mode_end && gr->mode != draw_mode_cursor) {
+ if (gr->parent) {
+ if (gr->cleanup) {
+ overlay_rect(gr->parent, gr, 1, &r);
+ gtk_drawing_area_draw(gr->parent, &r);
+ gr->cleanup=0;
+ }
+ overlay_rect(gr->parent, gr, 0, &r);
+ gtk_drawing_area_draw(gr->parent, &r);
+ } else {
+ r.x=0;
+ r.y=0;
+ r.width=gr->width;
+ r.height=gr->height;
+ gtk_drawing_area_draw(gr, &r);
+ overlay=gr->overlays;
+ while (overlay) {
+ overlay->cleanup=0;
+ overlay=overlay->next;
+ }
+ }
+ }
+ gr->mode=mode;
+}
+
+/* Events */
+
+static gint
+configure(GtkWidget * widget, GdkEventConfigure * event, gpointer user_data)
+{
+ struct graphics_priv *gra=user_data;
+ if (! gra->visible)
+ return TRUE;
+ if (gra->drawable != NULL) {
+ g_object_unref(gra->drawable);
+ }
+ if(gra->background_ready && gra->background != NULL) {
+ g_object_unref(gra->background);
+ gra->background_ready = 0;
+ }
+#ifndef _WIN32
+ dbg(1,"window=%d\n", GDK_WINDOW_XID(widget->window));
+#endif
+ gra->width=widget->allocation.width;
+ gra->height=widget->allocation.height;
+ gra->drawable = gdk_pixmap_new(widget->window, gra->width, gra->height, -1);
+ callback_list_call_attr_2(gra->cbl, attr_resize, (void *)gra->width, (void *)gra->height);
+ return TRUE;
+}
+
+static gint
+expose(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
+{
+ struct graphics_priv *gra=user_data;
+
+ gra->visible=1;
+ if (! gra->drawable)
+ configure(widget, NULL, user_data);
+ gtk_drawing_area_draw(gra, &event->area);
+#if 0
+ gdk_draw_drawable(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ gra->drawable, event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+#endif
+
+ return FALSE;
+}
+
+#if 0
+static gint
+button_timeout(gpointer user_data)
+{
+#if 0
+ struct container *co=user_data;
+ int x=co->gra->gra->button_event.x;
+ int y=co->gra->gra->button_event.y;
+ int button=co->gra->gra->button_event.button;
+
+ co->gra->gra->button_timeout=0;
+ popup(co, x, y, button);
+
+ return FALSE;
+#endif
+}
+#endif
+
+static int
+tv_delta(struct timeval *old, struct timeval *new)
+{
+ if (new->tv_sec-old->tv_sec >= INT_MAX/1000)
+ return INT_MAX;
+ return (new->tv_sec-old->tv_sec)*1000+(new->tv_usec-old->tv_usec)/1000;
+}
+
+static gint
+button_press(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ if (event->button < 8) {
+ if (tv_delta(&this->button_press[event->button], &tv) < 100)
+ return FALSE;
+ this->button_press[event->button]= tv;
+ this->button_release[event->button].tv_sec=0;
+ this->button_release[event->button].tv_usec=0;
+ }
+ p.x=event->x;
+ p.y=event->y;
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)1, (void *)event->button, (void *)&p);
+ return FALSE;
+}
+
+static gint
+button_release(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ if (event->button < 8) {
+ if (tv_delta(&this->button_release[event->button], &tv) < 100)
+ return FALSE;
+ this->button_release[event->button]= tv;
+ this->button_press[event->button].tv_sec=0;
+ this->button_press[event->button].tv_usec=0;
+ }
+ p.x=event->x;
+ p.y=event->y;
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)0, (void *)event->button, (void *)&p);
+ return FALSE;
+}
+
+
+
+static gint
+scroll(GtkWidget * widget, GdkEventScroll * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+ int button;
+
+ p.x=event->x;
+ p.y=event->y;
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ button=4;
+ break;
+ case GDK_SCROLL_DOWN:
+ button=5;
+ break;
+ default:
+ button=-1;
+ break;
+ }
+ if (button != -1) {
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)1, (void *)button, (void *)&p);
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)0, (void *)button, (void *)&p);
+ }
+ return FALSE;
+}
+
+static gint
+motion_notify(GtkWidget * widget, GdkEventMotion * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+
+ p.x=event->x;
+ p.y=event->y;
+ callback_list_call_attr_1(this->cbl, attr_motion, (void *)&p);
+ return FALSE;
+}
+
+/* *
+ * * Exit navit (X pressed)
+ * * @param widget active widget
+ * * @param event the event (delete_event)
+ * * @param nav our Navit context
+ * * @returns TRUE
+ * */
+static gint
+delete(GtkWidget *widget, GdkEventKey *event, struct navit *nav)
+{
+ navit_destroy(nav);
+ return TRUE;
+}
+
+static gint
+keypress(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ int len,ucode;
+ char key[8];
+ ucode=gdk_keyval_to_unicode(event->keyval);
+ len=g_unichar_to_utf8(ucode, key);
+ key[len]='\0';
+
+ switch (event->keyval) {
+ case GDK_Up:
+ key[0]=NAVIT_KEY_UP;
+ key[1]='\0';
+ break;
+ case GDK_Down:
+ key[0]=NAVIT_KEY_DOWN;
+ key[1]='\0';
+ break;
+ case GDK_Left:
+ key[0]=NAVIT_KEY_LEFT;
+ key[1]='\0';
+ break;
+ case GDK_Right:
+ key[0]=NAVIT_KEY_RIGHT;
+ key[1]='\0';
+ break;
+ case GDK_BackSpace:
+ key[0]=NAVIT_KEY_BACKSPACE;
+ key[1]='\0';
+ break;
+ case GDK_Return:
+ case GDK_KP_Enter:
+ key[0]=NAVIT_KEY_RETURN;
+ key[1]='\0';
+ break;
+ case GDK_Book:
+#ifdef USE_HILDON
+ case GDK_F7:
+#endif
+ key[0]=NAVIT_KEY_ZOOM_IN;
+ key[1]='\0';
+ break;
+ case GDK_Calendar:
+#ifdef USE_HILDON
+ case GDK_F8:
+#endif
+ key[0]=NAVIT_KEY_ZOOM_OUT;
+ key[1]='\0';
+ break;
+ }
+ if (key[0])
+ callback_list_call_attr_1(this->cbl, attr_keypress, (void *)key);
+ else
+ dbg(0,"keyval 0x%x\n", event->keyval);
+
+ return FALSE;
+}
+
+static struct graphics_priv *graphics_gtk_drawing_area_new_helper(struct graphics_methods *meth);
+
+static void
+overlay_disable(struct graphics_priv *gr, int disabled)
+{
+ gr->overlay_disabled=disabled;
+}
+
+static void
+overlay_resize(struct graphics_priv *this, struct point *p, int w, int h, int alpha, int wraparound)
+{
+ int changed = 0;
+ int w2,h2;
+
+ if (w == 0) {
+ w2 = 1;
+ } else {
+ w2 = w;
+ }
+
+ if (h == 0) {
+ h2 = 1;
+ } else {
+ h2 = h;
+ }
+
+ this->p = *p;
+ if (this->width != w2) {
+ this->width = w2;
+ changed = 1;
+ }
+
+ if (this->height != h2) {
+ this->height = h2;
+ changed = 1;
+ }
+
+ this->a = alpha >> 8;
+ this->wraparound = wraparound;
+
+ if (changed) {
+ // Set the drawables to the right sizes
+ g_object_unref(this->drawable);
+ g_object_unref(this->background);
+
+ this->drawable=gdk_pixmap_new(this->parent->widget->window, w2, h2, -1);
+ this->background=gdk_pixmap_new(this->parent->widget->window, w2, h2, -1);
+
+ if ((w == 0) || (h == 0)) {
+ this->overlay_autodisabled = 1;
+ } else {
+ this->overlay_autodisabled = 0;
+ }
+
+ callback_list_call_attr_2(this->cbl, attr_resize, (void *)this->width, (void *)this->height);
+ }
+}
+
+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)
+{
+ int w2,h2;
+ struct graphics_priv *this=graphics_gtk_drawing_area_new_helper(meth);
+ this->colormap=gr->colormap;
+ this->widget=gr->widget;
+ this->p=*p;
+ this->width=w;
+ this->height=h;
+ this->parent=gr;
+
+ /* If either height or width is 0, we set it to 1 to avoid warnings, and
+ * disable the overlay. */
+ if (h == 0) {
+ h2 = 1;
+ } else {
+ h2 = h;
+ }
+
+ if (w == 0) {
+ w2 = 1;
+ } else {
+ w2 = w;
+ }
+
+ this->background=gdk_pixmap_new(gr->widget->window, w2, h2, -1);
+ this->drawable=gdk_pixmap_new(gr->widget->window, w2, h2, -1);
+
+ if ((w == 0) || (h == 0)) {
+ this->overlay_autodisabled = 1;
+ } else {
+ this->overlay_autodisabled = 0;
+ }
+
+ this->next=gr->overlays;
+ this->a=alpha >> 8;
+ this->wraparound=wraparound;
+ gr->overlays=this;
+ return this;
+}
+
+static int gtk_argc;
+static char **gtk_argv={NULL};
+
+
+static int
+graphics_gtk_drawing_area_fullscreen(struct window *w, int on)
+{
+ struct graphics_priv *gr=w->priv;
+ if (on)
+ gtk_window_fullscreen(GTK_WINDOW(gr->win));
+ else
+ gtk_window_unfullscreen(GTK_WINDOW(gr->win));
+ return 1;
+}
+
+static void
+graphics_gtk_drawing_area_disable_suspend(struct window *w)
+{
+ struct graphics_priv *gr=w->priv;
+
+#ifndef _WIN32
+ if (gr->pid)
+ kill(gr->pid, SIGWINCH);
+#else
+ dbg(1, "failed to kill() under Windows\n");
+#endif
+}
+
+static void *
+get_data(struct graphics_priv *this, char *type)
+{
+ FILE *f;
+ if (!strcmp(type,"gtk_widget"))
+ return this->widget;
+#ifndef _WIN32
+ if (!strcmp(type,"xwindow_id"))
+ return (void *)GDK_WINDOW_XID(this->widget->window);
+#endif
+ if (!strcmp(type,"window")) {
+ char *cp = getenv("NAVIT_XID");
+ unsigned xid = 0;
+ if (cp)
+ xid = strtol(cp, NULL, 0);
+ if (!xid)
+ this->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ else
+ this->win = gtk_plug_new(xid);
+ gtk_window_set_default_size(GTK_WINDOW(this->win), this->win_w, this->win_h);
+ dbg(1,"h= %i, w= %i\n",this->win_h, this->win_w);
+ gtk_window_set_title(GTK_WINDOW(this->win), "Navit");
+ gtk_window_set_wmclass (GTK_WINDOW (this->win), "navit", "Navit");
+ gtk_widget_realize(this->win);
+ gtk_container_add(GTK_CONTAINER(this->win), this->widget);
+ gtk_widget_show_all(this->win);
+ GTK_WIDGET_SET_FLAGS (this->widget, GTK_CAN_FOCUS);
+ gtk_widget_set_sensitive(this->widget, TRUE);
+ gtk_widget_grab_focus(this->widget);
+ g_signal_connect(G_OBJECT(this->widget), "key-press-event", G_CALLBACK(keypress), this);
+ g_signal_connect(G_OBJECT(this->win), "delete_event", G_CALLBACK(delete), this->nav);
+ this->window.fullscreen=graphics_gtk_drawing_area_fullscreen;
+ this->window.disable_suspend=graphics_gtk_drawing_area_disable_suspend;
+ this->window.priv=this;
+#if !defined(_WIN32) && !defined(__CEGCC__)
+ f=popen("pidof /usr/bin/ipaq-sleep","r");
+ if (f) {
+ fscanf(f,"%d",&this->pid);
+ dbg(1,"ipaq_sleep pid=%d\n", this->pid);
+ pclose(f);
+ }
+#endif
+ return &this->window;
+ }
+ return NULL;
+}
+
+static struct graphics_methods graphics_methods = {
+ graphics_destroy,
+ draw_mode,
+ draw_lines,
+ draw_polygon,
+ draw_rectangle,
+ draw_circle,
+ draw_text,
+ draw_image,
+#ifdef HAVE_IMLIB2
+ draw_image_warp,
+#else
+ NULL,
+#endif
+ draw_restore,
+ draw_drag,
+ NULL,
+ gc_new,
+ background_gc,
+ overlay_new,
+ image_new,
+ get_data,
+ image_free,
+ NULL,
+ overlay_disable,
+ overlay_resize,
+};
+
+static struct graphics_priv *
+graphics_gtk_drawing_area_new_helper(struct graphics_methods *meth)
+{
+ struct font_priv * (*font_freetype_new)(void *meth);
+ font_freetype_new=plugin_get_font_type("freetype");
+ if (!font_freetype_new)
+ return NULL;
+ struct graphics_priv *this=g_new0(struct graphics_priv,1);
+ font_freetype_new(&this->freetype_methods);
+ *meth=graphics_methods;
+ meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *, int, int))this->freetype_methods.font_new;
+ meth->get_text_bbox=this->freetype_methods.get_text_bbox;
+
+ return this;
+}
+
+static struct graphics_priv *
+graphics_gtk_drawing_area_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
+{
+ int i;
+ GtkWidget *draw;
+ struct attr *attr;
+
+ if (! event_request_system("glib","graphics_gtk_drawing_area_new"))
+ return NULL;
+
+ draw=gtk_drawing_area_new();
+ struct graphics_priv *this=graphics_gtk_drawing_area_new_helper(meth);
+ this->nav = nav;
+ this->widget=draw;
+ this->win_w=792;
+ if ((attr=attr_search(attrs, NULL, attr_w)))
+ this->win_w=attr->u.num;
+ this->win_h=547;
+ if ((attr=attr_search(attrs, NULL, attr_h)))
+ this->win_h=attr->u.num;
+ this->cbl=cbl;
+ this->colormap=gdk_colormap_new(gdk_visual_get_system(),FALSE);
+ gtk_widget_set_events(draw, GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK|GDK_KEY_PRESS_MASK);
+ g_signal_connect(G_OBJECT(draw), "expose_event", G_CALLBACK(expose), this);
+ g_signal_connect(G_OBJECT(draw), "configure_event", G_CALLBACK(configure), this);
+ g_signal_connect(G_OBJECT(draw), "button_press_event", G_CALLBACK(button_press), this);
+ g_signal_connect(G_OBJECT(draw), "button_release_event", G_CALLBACK(button_release), this);
+ g_signal_connect(G_OBJECT(draw), "scroll_event", G_CALLBACK(scroll), this);
+ g_signal_connect(G_OBJECT(draw), "motion_notify_event", G_CALLBACK(motion_notify), this);
+ g_signal_connect(G_OBJECT(draw), "delete_event", G_CALLBACK(delete), nav);
+
+ for (i = 0; i < 8; i++) {
+ this->button_press[i].tv_sec = 0;
+ this->button_press[i].tv_usec = 0;
+ this->button_release[i].tv_sec = 0;
+ this->button_release[i].tv_usec = 0;
+ }
+
+ return this;
+}
+
+void
+plugin_init(void)
+{
+ gtk_init(&gtk_argc, &gtk_argv);
+ gtk_set_locale();
+ plugin_register_graphics_type("gtk_drawing_area", graphics_gtk_drawing_area_new);
+}
diff --git a/graphics/gtk_gl_ext/graphics_gtk_gl_ext.c b/graphics/gtk_gl_ext/graphics_gtk_gl_ext.c
new file mode 100644
index 00000000..7c94e0bd
--- /dev/null
+++ b/graphics/gtk_gl_ext/graphics_gtk_gl_ext.c
@@ -0,0 +1,352 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkgl.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "point.h"
+#include "graphics.h"
+#include "container.h"
+
+
+struct graphics_gra {
+ GtkWidget *widget;
+ int width;
+ int height;
+ int library_init;
+ int visible;
+ int buffer;
+};
+
+struct graphics_font {
+};
+
+struct graphics_gc {
+ double fr,fg,fb;
+ double br,bg,bb;
+ double width;
+ struct graphics_gra *gra;
+};
+
+static struct graphics_font *font_new(struct graphics *gr, int size)
+{
+ struct graphics_font *font=g_new(struct graphics_font, 1);
+ return font;
+}
+
+static struct graphics_gc *gc_new(struct graphics *gr)
+{
+ struct graphics_gc *gc=g_new(struct graphics_gc, 1);
+
+ gc->fr=1;
+ gc->fg=1;
+ gc->fb=1;
+ gc->br=0;
+ gc->bg=0;
+ gc->bb=0;
+ gc->width=1;
+ gc->gra=gr->gra;
+ return gc;
+}
+
+static void
+gc_set_linewidth(struct graphics_gc *gc, int w)
+{
+ gc->width=w;
+}
+
+static void
+gc_set_foreground(struct graphics_gc *gc, int r, int g, int b)
+{
+ gc->fr=r/65535.0;
+ gc->fg=g/65535.0;
+ gc->fb=b/65535.0;
+}
+
+static void
+gc_set_background(struct graphics_gc *gc, int r, int g, int b)
+{
+ gc->br=r/65535.0;
+ gc->bg=g/65535.0;
+ gc->bb=b/65535.0;
+}
+
+static void
+vertex(struct point *p)
+{
+ double x,y;
+ x=p->x;
+ y=p->y;
+ x/=792;
+ y/=469;
+ x-=0.5;
+ y=0.5-y;
+ glVertex3f(x,y,0);
+}
+
+static void
+draw_lines(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count)
+{
+ int i;
+
+ glLineWidth(gc->width);
+ glColor3f(gc->fr, gc->fg, gc->fb);
+ glBegin(GL_LINE_STRIP);
+ for (i=0 ; i < count ; i++)
+ vertex(p++);
+ glEnd();
+}
+
+static void
+draw_polygon(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count)
+{
+ int i;
+ double x,y;
+ glColor3f(gc->fr, gc->fg, gc->fb);
+ glBegin(GL_POLYGON);
+ for (i=0 ; i < count ; i++)
+ vertex(p++);
+ glEnd();
+}
+
+
+static void
+draw_circle(struct graphics *gr, struct graphics_gc *gc, struct point *p, int r)
+{
+
+}
+
+static void
+draw_text(struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font, unsigned char *text, int x, int y, int dx, int dy)
+{
+}
+
+static void
+draw_begin(struct graphics *gr)
+{
+ printf("draw_begin\n");
+ glClearColor(gr->gc[0]->br, gr->gc[0]->bg, gr->gc[0]->bb, 0);
+ glNewList(1, GL_COMPILE);
+ gr->gra->buffer=1;
+}
+
+static void
+draw_end(struct graphics *gr)
+{
+ printf("draw_end\n");
+ glEndList();
+ gr->gra->buffer=0;
+}
+
+static void realize(GtkWidget * widget, gpointer data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
+
+ GLUquadricObj *qobj;
+ static GLfloat light_diffuse[] = { 1.0, 0.0, 0.0, 1.0 };
+ static GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
+
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
+ return;
+
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+#if 0
+ glNewList(1, GL_COMPILE);
+ gluSphere(qobj, 1.0, 20, 20);
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(0.0,0.1,0.0);
+ glVertex3f(0.1,0.1,0.0);
+ glVertex3f(0.1,0.2,0.0);
+ glVertex3f(0.2,0.2,0.0);
+ glEnd();
+ glEndList();
+#endif
+
+#if 0
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
+ glLightfv(GL_LIGHT0, GL_POSITION, light_position);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+#endif
+
+ glClearColor(1.0, 1.0, 1.0, 1.0);
+ glClearDepth(1.0);
+
+ glViewport(0, 0,
+ widget->allocation.width, widget->allocation.height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(19.0, 1.0, 1.0, 10.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+ glTranslatef(0.0, 0.0, 0.0);
+
+ gdk_gl_drawable_gl_end(gldrawable);
+ /*** OpenGL END ***/
+}
+
+static gboolean
+configure(GtkWidget * widget, GdkEventConfigure * event, gpointer user_data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
+ struct container *co=user_data;
+ struct graphics_gra *gra=co->gra->gra;
+
+
+ printf("configure %d %d\n",gra->width, gra->height);
+ gra->width=widget->allocation.width;
+ gra->height=widget->allocation.height;
+
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
+ return FALSE;
+
+ glViewport(0, 0,
+ widget->allocation.width, widget->allocation.height);
+
+ gdk_gl_drawable_gl_end(gldrawable);
+ /*** OpenGL END ***/
+ if (gra->visible)
+ graphics_resize(co, gra->width, gra->height);
+
+ return TRUE;
+}
+
+static gboolean
+expose(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
+{
+ GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
+ struct container *co=user_data;
+ struct graphics_gra *gra=co->gra->gra;
+
+ printf("expose\n");
+ if (! gra->visible) {
+ gra->visible=1;
+ configure(widget, NULL, user_data);
+ }
+ /*** OpenGL BEGIN ***/
+ if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
+ return FALSE;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glCallList(1);
+
+ if (gdk_gl_drawable_is_double_buffered(gldrawable))
+ gdk_gl_drawable_swap_buffers(gldrawable);
+ else
+ glFlush();
+
+ gdk_gl_drawable_gl_end(gldrawable);
+ /*** OpenGL END ***/
+
+ return TRUE;
+}
+
+
+struct graphics *
+graphics_gtk_gl_area_new(struct container *co, GtkWidget **widget)
+{
+ GdkGLConfig *glconfig;
+ gint major, minor;
+ GtkWidget *drawing_area;
+
+ struct graphics *this=g_new0(struct graphics,1);
+ this->draw_lines=draw_lines;
+ this->draw_polygon=draw_polygon;
+ this->draw_circle=draw_circle;
+ this->draw_text=draw_text;
+#if 0
+ this->draw_begin=draw_begin;
+ this->draw_end=draw_end;
+#endif
+ this->gc_new=gc_new;
+ this->gc_set_linewidth=gc_set_linewidth;
+ this->gc_set_foreground=gc_set_foreground;
+ this->gc_set_background=gc_set_background;
+ this->font_new=font_new;
+ this->gra=g_new0(struct graphics_gra, 1);
+
+ /*
+ * Init GtkGLExt.
+ */
+
+ gtk_gl_init(NULL, NULL);
+
+ /*
+ * Query OpenGL extension version.
+ */
+
+ gdk_gl_query_version(&major, &minor);
+ g_print("OpenGL extension version - %d.%d\n", major, minor);
+
+ /*
+ * Configure OpenGL-capable visual.
+ */
+
+ /* Try double-buffered visual */
+ glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB |
+ GDK_GL_MODE_DEPTH |
+ GDK_GL_MODE_DOUBLE);
+ if (glconfig == NULL) {
+ g_print("*** Cannot find the double-buffered visual.\n");
+ g_print("*** Trying single-buffered visual.\n");
+
+ /* Try single-buffered visual */
+ glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB |
+ GDK_GL_MODE_DEPTH);
+ if (glconfig == NULL) {
+ g_print
+ ("*** No appropriate OpenGL-capable visual found.\n");
+ exit(1);
+ }
+ }
+
+
+ drawing_area = gtk_drawing_area_new();
+
+ /* Set OpenGL-capability to the widget. */
+ gtk_widget_set_gl_capability(drawing_area,
+ glconfig,
+ NULL, TRUE, GDK_GL_RGBA_TYPE);
+
+ g_signal_connect_after(G_OBJECT(drawing_area), "realize",
+ G_CALLBACK(realize), NULL);
+ g_signal_connect(G_OBJECT(drawing_area), "configure_event",
+ G_CALLBACK(configure), co);
+ g_signal_connect(G_OBJECT(drawing_area), "expose_event",
+ G_CALLBACK(expose), co);
+
+ *widget=drawing_area;
+ this->gra->widget=drawing_area;
+ return this;
+}
+
+
diff --git a/graphics/null/Makefile.am b/graphics/null/Makefile.am
new file mode 100644
index 00000000..9fe6ffc1
--- /dev/null
+++ b/graphics/null/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=graphics_null
+if PLUGINS
+modulegraphics_LTLIBRARIES = libgraphics_null.la
+else
+noinst_LTLIBRARIES = libgraphics_null.la
+endif
+libgraphics_null_la_SOURCES = graphics_null.c
+libgraphics_null_la_LDFLAGS = -module -avoid-version
diff --git a/graphics/null/graphics_null.c b/graphics/null/graphics_null.c
new file mode 100644
index 00000000..f1936475
--- /dev/null
+++ b/graphics/null/graphics_null.c
@@ -0,0 +1,231 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include "config.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "plugin.h"
+
+static int dummy;
+static struct graphics_priv {
+ int dummy;
+} graphics_priv;
+
+static struct graphics_font_priv {
+ int dummy;
+} graphics_font_priv;
+
+static struct graphics_gc_priv {
+ int dummy;
+} graphics_gc_priv;
+
+static struct graphics_image_priv {
+ int dummy;
+} graphics_image_priv;
+
+static void
+graphics_destroy(struct graphics_priv *gr)
+{
+}
+
+static void font_destroy(struct graphics_font_priv *font)
+{
+
+}
+
+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 *font, int size, int flags)
+{
+ *meth=font_methods;
+ return &graphics_font_priv;
+}
+
+static void
+gc_destroy(struct graphics_gc_priv *gc)
+{
+}
+
+static void
+gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+}
+
+static void
+gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
+{
+}
+
+static void
+gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+}
+
+static void
+gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+}
+
+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)
+{
+ *meth=gc_methods;
+ return &graphics_gc_priv;
+}
+
+static struct graphics_image_priv *
+image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *path, int *w, int *h, struct point *hot, int rotation)
+{
+ return &graphics_image_priv;
+}
+
+static void
+draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+}
+
+static void
+draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+}
+
+static void
+draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+}
+
+static void
+draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+}
+
+
+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)
+{
+}
+
+static void
+draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+}
+
+static void
+draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
+{
+}
+
+static void
+draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+}
+
+static void draw_drag(struct graphics_priv *gr, struct point *p)
+{
+}
+
+static void
+background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+}
+
+static void
+draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+}
+
+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 void *
+get_data(struct graphics_priv *this, char *type)
+{
+ return &dummy;
+}
+
+static void image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
+{
+}
+
+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)
+{
+}
+
+static void overlay_disable(struct graphics_priv *gr, int disable)
+{
+}
+
+static void overlay_resize(struct graphics_priv *gr, struct point *p, int w, int h, int alpha, int wraparound)
+{
+}
+
+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,
+ image_free,
+ get_text_bbox,
+ overlay_disable,
+ overlay_resize,
+};
+
+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)
+{
+ *meth=graphics_methods;
+ return &graphics_priv;
+}
+
+
+static struct graphics_priv *
+graphics_null_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
+{
+ *meth=graphics_methods;
+ return &graphics_priv;
+}
+
+void
+plugin_init(void)
+{
+ plugin_register_graphics_type("null", graphics_null_new);
+}
diff --git a/graphics/opengl/Makefile.am b/graphics/opengl/Makefile.am
new file mode 100644
index 00000000..02d356dd
--- /dev/null
+++ b/graphics/opengl/Makefile.am
@@ -0,0 +1,6 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ @OPENGL_CFLAGS@ @GLC_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=graphics_opengl
+modulegraphics_LTLIBRARIES = libgraphics_opengl.la
+libgraphics_opengl_la_SOURCES = graphics_opengl.c
+libgraphics_opengl_la_LIBADD = @OPENGL_LIBS@ @GLC_LIBS@
+libgraphics_opengl_la_LDFLAGS = -module -avoid-version
diff --git a/graphics/opengl/graphics_opengl.c b/graphics/opengl/graphics_opengl.c
new file mode 100644
index 00000000..a7163035
--- /dev/null
+++ b/graphics/opengl/graphics_opengl.c
@@ -0,0 +1,845 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <math.h>
+#include <glib.h>
+#include "config.h"
+#include <GL/glc.h>
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "plugin.h"
+
+#include "debug.h"
+
+#include <GL/glut.h>
+
+
+void CALLBACK tessBeginCB(GLenum which);
+void CALLBACK tessEndCB();
+void CALLBACK tessErrorCB(GLenum errorCode);
+void CALLBACK tessVertexCB(const GLvoid *data);
+void CALLBACK tessVertexCB2(const GLvoid *data);
+void CALLBACK tessCombineCB(const GLdouble newVertex[3], const GLdouble *neighborVertex[4],
+ const GLfloat neighborWeight[4], GLdouble **outData);
+
+
+struct graphics_priv {
+ int button_timeout;
+ struct point p;
+ int width;
+ int height;
+ int library_init;
+ int visible;
+ struct graphics_priv *parent;
+ struct graphics_priv *overlays;
+ struct graphics_priv *next;
+ struct graphics_gc_priv *background_gc;
+ enum draw_mode_num mode;
+ 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;
+ GLuint DLid;
+};
+
+struct graphics_font_priv {
+#if 0
+ FT_Face face;
+#endif
+};
+
+struct graphics_gc_priv {
+ struct graphics_priv *gr;
+ float fr,fg,fb,fa;
+ float br,bg,bb,ba;
+ int linewidth;
+};
+
+struct graphics_image_priv {
+ int w;
+ int h;
+};
+
+static void
+graphics_destroy(struct graphics_priv *gr)
+{
+}
+
+int frame=0;
+
+// http://quesoglc.sourceforge.net/tutorial.php
+
+
+static void font_destroy(struct graphics_font_priv *font)
+{
+ g_free(font);
+ /* TODO: free font->face */
+}
+
+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)
+{
+#if 0
+ char **filename=fontlist;
+ struct graphics_font_priv *font=g_new(struct graphics_font_priv, 1);
+
+ *meth=font_methods;
+
+ if (!gr->library_init) {
+ FT_Init_FreeType( &gr->library );
+ gr->library_init=1;
+ }
+
+ while (*filename) {
+ if (!FT_New_Face( gr->library, *filename, 0, &font->face ))
+ break;
+ filename++;
+ }
+ if (! *filename) {
+ g_warning("Failed to load font, no labelling");
+ g_free(font);
+ return NULL;
+ }
+ FT_Set_Char_Size(font->face, 0, size, 300, 300);
+ FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
+ return font;
+#endif
+ return NULL;
+}
+
+static void
+gc_destroy(struct graphics_gc_priv *gc)
+{
+ g_free(gc);
+}
+
+static void
+gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+ gc->linewidth=w;
+}
+
+static void
+gc_set_dashes(struct graphics_gc_priv *gc, int width, int offset, unsigned char *dash_list, int n)
+{
+#if 0
+ gdk_gc_set_dashes(gc->gc, offset, (gint8 *)dash_list, n);
+ gdk_gc_set_line_attributes(gc->gc, width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+#endif
+}
+
+
+static void
+gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->fr=c->r/65535.0;
+ gc->fg=c->g/65535.0;
+ gc->fb=c->b/65535.0;
+ gc->fa=c->a/65535.0;
+// printf("new alpha : %i\n",c->a);
+}
+
+static void
+gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->br=c->r/65535.0;
+ gc->bg=c->g/65535.0;
+ gc->bb=c->b/65535.0;
+ gc->ba=c->a/65535.0;
+}
+
+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;
+ return gc;
+}
+
+
+static struct graphics_image_priv *
+image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *name, int *w, int *h)
+{
+#if 0
+ GdkPixbuf *pixbuf;
+ struct graphics_image_priv *ret;
+
+ pixbuf=gdk_pixbuf_new_from_file(name, NULL);
+ if (! pixbuf)
+ return NULL;
+ ret=g_new0(struct graphics_image_priv, 1);
+ ret->pixbuf=pixbuf;
+ ret->w=gdk_pixbuf_get_width(pixbuf);
+ ret->h=gdk_pixbuf_get_height(pixbuf);
+ *w=ret->w;
+ *h=ret->h;
+ return ret;
+#endif
+ return NULL;
+}
+
+static void
+draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+/*
+ if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+ gdk_draw_lines(gr->drawable, gc->gc, (GdkPoint *)p, count);
+ if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
+ gdk_draw_lines(gr->widget->window, gc->gc, (GdkPoint *)p, count);
+*/
+ /*
+ if(gr->mode == draw_mode_begin){
+ printf("B");
+ } else if (gr->mode == draw_mode_end){
+ printf("E");
+ } else {
+ printf("x");
+ }
+*/
+
+ for (i = 0 ; i < count-1 ; i++) {
+
+// glEnable( GL_POLYGON_SMOOTH );
+// glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+// glEnable( GL_BLEND );
+
+ float dx=p[i+1].x-p[i].x;
+ float dy=p[i+1].y-p[i].y;
+
+ float cx=(p[i+1].x+p[i].x)/2;
+ float cy=(p[i+1].y+p[i].y)/2;
+// printf("(%lx,%lx) -> (%lx,%lx) : (%lx,%lx)\n",p[i].x,p[i].y,p[i+1].x,p[i+1].y,dx,dy);
+
+ int w=round(sqrt(pow((dx),2)+pow((dy),2)));
+
+ float angle=atan (dy/dx) * 180 / M_PI;
+
+ glPushMatrix();
+ glTranslatef(cx,cy,1);
+ // glColor4f( 0,0,0,1);
+ // glRasterPos2f( 1,1 );
+ glRotatef(angle,0.0,0.0,1.0);
+
+ glColor4f( gc->fr, gc->fg, gc->fb, gc->fa);
+
+ int linewidth=gc->linewidth;
+
+ glBegin( GL_POLYGON );
+ glVertex2f( -w/2,-linewidth/2 );
+ glVertex2f( -w/2-4,0 );
+ glVertex2f( -w/2,+linewidth/2 );
+ glVertex2f( +w/2,+linewidth/2 );
+ glVertex2f( +w/2+4,0 );
+ glVertex2f( +w/2,-linewidth/2 );
+ glVertex2f( -w/2,+linewidth/2 );
+ glEnd();
+
+
+ // FIXME Roads label can maybe be drawn here, avoid the display_label loop, when playing with Z axis position.
+ /*
+ if(attr==1){
+ glcRenderStyle(GLC_TEXTURE);
+ glColor3f(0., 0., 0.);
+ glScalef(12, 12, 0.);
+ glcRenderString(">>");
+ } else if(attr==-1){
+ glcRenderStyle(GLC_TEXTURE);
+ glColor3f(0., 0., 0.);
+ glScalef(12, 12, 0.);
+ glcRenderString("<<");
+ }
+
+ */
+ glPopMatrix();
+ }
+// glDisable( GL_BLEND );
+// glDisable( GL_POLYGON_SMOOTH );
+
+/*
+ if(label){
+ if((strlen(label)*6)<w){
+ SDL_print(label,cx, cy,-angle);
+ }
+ }
+*/
+}
+
+
+const char* getPrimitiveType(GLenum type)
+{
+ switch(type)
+ {
+ case 0x0000:
+ return "GL_POINTS";
+ break;
+ case 0x0001:
+ return "GL_LINES";
+ break;
+ case 0x0002:
+ return "GL_LINE_LOOP";
+ break;
+ case 0x0003:
+ return "GL_LINE_STRIP";
+ break;
+ case 0x0004:
+ return "GL_TRIANGLES";
+ break;
+ case 0x0005:
+ return "GL_TRIANGLE_STRIP";
+ break;
+ case 0x0006:
+ return "GL_TRIANGLE_FAN";
+ break;
+ case 0x0007:
+ return "GL_QUADS";
+ break;
+ case 0x0008:
+ return "GL_QUAD_STRIP";
+ break;
+ case 0x0009:
+ return "GL_POLYGON";
+ break;
+ }
+}
+
+void CALLBACK tessBeginCB(GLenum which)
+{
+ glBegin(which);
+
+ dbg(1,"glBegin( %s );\n",getPrimitiveType(which));
+}
+
+
+
+void CALLBACK tessEndCB()
+{
+ glEnd();
+
+ dbg(1,"glEnd();\n");
+}
+
+
+
+void CALLBACK tessVertexCB(const GLvoid *data)
+{
+ // cast back to double type
+ const GLdouble *ptr = (const GLdouble*)data;
+
+ glVertex3dv(ptr);
+
+ dbg(1," glVertex3d();\n");
+}
+
+
+static void
+draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+
+ GLUtesselator *tess = gluNewTess(); // create a tessellator
+ if(!tess) return 0; // failed to create tessellation object, return 0
+
+ GLdouble quad1[count][3];
+ for (i = 0 ; i < count ; i++) {
+ quad1[i][0]=(GLdouble)(p[i].x);
+ quad1[i][1]=(GLdouble)(p[i].y);
+ quad1[i][2]=0;
+ }
+
+
+ // register callback functions
+ gluTessCallback(tess, GLU_TESS_BEGIN, (void (*)(void))tessBeginCB);
+ gluTessCallback(tess, GLU_TESS_END, (void (*)(void))tessEndCB);
+ // gluTessCallback(tess, GLU_TESS_ERROR, (void (*)(void))tessErrorCB);
+ gluTessCallback(tess, GLU_TESS_VERTEX, (void (*)(void))tessVertexCB);
+
+ // tessellate and compile a concave quad into display list
+ // gluTessVertex() takes 3 params: tess object, pointer to vertex coords,
+ // and pointer to vertex data to be passed to vertex callback.
+ // The second param is used only to perform tessellation, and the third
+ // param is the actual vertex data to draw. It is usually same as the second
+ // param, but It can be more than vertex coord, for example, color, normal
+ // and UV coords which are needed for actual drawing.
+ // Here, we are looking at only vertex coods, so the 2nd and 3rd params are
+ // pointing same address.
+ glColor4f( gc->fr, gc->fg, gc->fb, gc->fa);
+ gluTessBeginPolygon(tess, 0); // with NULL data
+ gluTessBeginContour(tess);
+ for (i = 0 ; i < count ; i++) {
+ gluTessVertex(tess, quad1[i], quad1[i]);
+ }
+ gluTessEndContour(tess);
+ gluTessEndPolygon(tess);
+
+ gluDeleteTess(tess); // delete after tessellation
+
+}
+
+static void
+draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+#if 0
+ gdk_draw_rectangle(gr->drawable, gc->gc, TRUE, p->x, p->y, w, h);
+#endif
+}
+
+static void
+draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+#if 0
+ if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+ gdk_draw_arc(gr->drawable, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
+ if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
+ gdk_draw_arc(gr->widget->window, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
+#endif
+}
+
+
+
+void SDL_print(char * label,int x, int y, double angle)
+{
+ glPushMatrix();
+ glcRenderStyle(GLC_TEXTURE);
+ glColor4f(0,0,0,1);
+ glTranslatef(x, y, 1);
+ glRotatef(180,1,0,0);
+ glRotatef(angle,0,0,1);
+
+ glScalef(14, 14, 14);
+ // FIXME : add some error checking : glcGetError()
+ glcRenderString(label);
+ glPopMatrix();
+
+}
+
+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)
+{
+// dbg(0,"%s : %i,%i, %f\n",text,dx,dy,(180*atan2(dx,dy)/3.14));
+ SDL_print(text,p->x,p->y,(180*atan2(dx,dy)/3.14)-90);
+}
+
+static void
+draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+#if 0
+ gdk_draw_pixbuf(gr->drawable, fg->gc, img->pixbuf, 0, 0, p->x, p->y,
+ img->w, img->h, GDK_RGB_DITHER_NONE, 0, 0);
+#endif
+}
+
+#ifdef HAVE_IMLIB2
+static void
+draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
+{
+#if 0
+ void *image;
+ int w,h;
+ printf("draw_image_warp data=%s\n", data);
+ image = imlib_load_image(data);
+ imlib_context_set_display(gdk_x11_drawable_get_xdisplay(gr->widget->window));
+ imlib_context_set_colormap(gdk_x11_colormap_get_xcolormap(gtk_widget_get_colormap(gr->widget)));
+ imlib_context_set_visual(gdk_x11_visual_get_xvisual(gtk_widget_get_visual(gr->widget)));
+ imlib_context_set_drawable(gdk_x11_drawable_get_xid(gr->drawable));
+ imlib_context_set_image(image);
+ w = imlib_image_get_width();
+ h = imlib_image_get_height();
+ if (count == 3) {
+ imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x, p[0].y, p[1].x-p[0].x, p[1].y-p[0].y, p[2].x-p[0].x, p[2].y-p[0].y);
+ }
+ if (count == 2) {
+ imlib_render_image_on_drawable_skewed(0, 0, w, h, p[0].x, p[0].y, p[1].x-p[0].x, 0, 0, p[1].y-p[0].y);
+ }
+#endif
+}
+#endif
+
+static void
+overlay_draw(struct graphics_priv *parent, struct graphics_priv *overlay, int window)
+{
+#if 0
+ GdkPixbuf *pixbuf,*pixbuf2;
+ GtkWidget *widget=parent->widget;
+ guchar *pixels1, *pixels2, *p1, *p2;
+ int x,y;
+ int rowstride1,rowstride2;
+ int n_channels1,n_channels2;
+
+ if (! parent->drawable)
+ return;
+
+ pixbuf=gdk_pixbuf_get_from_drawable(NULL, overlay->drawable, NULL, 0, 0, 0, 0, overlay->width, overlay->height);
+ pixbuf2=gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pixbuf), TRUE, gdk_pixbuf_get_bits_per_sample(pixbuf),
+ gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf));
+
+ rowstride1 = gdk_pixbuf_get_rowstride (pixbuf);
+ rowstride2 = gdk_pixbuf_get_rowstride (pixbuf2);
+ pixels1=gdk_pixbuf_get_pixels (pixbuf);
+ pixels2=gdk_pixbuf_get_pixels (pixbuf2);
+ n_channels1 = gdk_pixbuf_get_n_channels (pixbuf);
+ n_channels2 = gdk_pixbuf_get_n_channels (pixbuf2);
+ for (y = 0 ; y < overlay->height ; y++) {
+ for (x = 0 ; x < overlay->width ; x++) {
+ p1 = pixels1 + y * rowstride1 + x * n_channels1;
+ p2 = pixels2 + y * rowstride2 + x * n_channels2;
+ p2[0]=p1[0];
+ p2[1]=p1[1];
+ p2[2]=p1[2];
+ p2[3]=127;
+ }
+ }
+ if (window)
+ gdk_draw_pixmap(parent->drawable, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], overlay->background, 0, 0, overlay->p.x, overlay->p.y, overlay->width, overlay->height);
+ else
+ gdk_draw_pixmap(overlay->background, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], parent->drawable, overlay->p.x, overlay->p.y, 0, 0, overlay->width, overlay->height);
+ gdk_draw_pixbuf(parent->drawable, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], pixbuf2, 0, 0, overlay->p.x, overlay->p.y, overlay->width, overlay->height, GDK_RGB_DITHER_NONE, 0, 0);
+ if (window)
+ gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], parent->drawable, overlay->p.x, overlay->p.y, overlay->p.x, overlay->p.y, overlay->width, overlay->height);
+#if 0
+ gdk_draw_pixmap(gr->gra->drawable,
+ gr->gra->widget->style->fg_gc[GTK_WIDGET_STATE(gr->gra->widget)],
+ img->gra->drawable,
+ 0, 0, p->x, p->y, img->gra->width, img->gra->height);
+#endif
+#endif
+}
+
+static void
+draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+#if 0
+ GtkWidget *widget=gr->widget;
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ gr->drawable,
+ p->x, p->y, p->x, p->y, w, h);
+#endif
+
+}
+
+static void
+background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ gr->background_gc=gc;
+}
+
+static void
+draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ if (gr->DLid) {
+ if (mode == draw_mode_begin)
+ glNewList(gr->DLid,GL_COMPILE);
+ if (mode == draw_mode_end)
+ glEndList();
+ }
+
+#if 0
+ struct graphics_priv *overlay;
+ GtkWidget *widget=gr->widget;
+
+ if (mode == draw_mode_begin) {
+ if (! gr->parent && gr->background_gc)
+ gdk_draw_rectangle(gr->drawable, gr->background_gc->gc, TRUE, 0, 0, gr->width, gr->height);
+ }
+ if (mode == draw_mode_end && gr->mode == draw_mode_begin) {
+ if (gr->parent) {
+ overlay_draw(gr->parent, gr, 1);
+ } else {
+ overlay=gr->overlays;
+ while (overlay) {
+ overlay_draw(gr, overlay, 0);
+ overlay=overlay->next;
+ }
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ gr->drawable,
+ 0, 0, 0, 0, gr->width, gr->height);
+ }
+ }
+ gr->mode=mode;
+#endif
+}
+
+#if 0
+/* Events */
+
+static gint
+configure(GtkWidget * widget, GdkEventConfigure * event, gpointer user_data)
+{
+ struct graphics_priv *gra=user_data;
+ if (! gra->visible)
+ return TRUE;
+ if (gra->drawable != NULL) {
+ gdk_pixmap_unref(gra->drawable);
+ }
+ gra->width=widget->allocation.width;
+ gra->height=widget->allocation.height;
+ gra->drawable = gdk_pixmap_new(widget->window, gra->width, gra->height, -1);
+ if (gra->resize_callback)
+ (*gra->resize_callback)(gra->resize_callback_data, gra->width, gra->height);
+ return TRUE;
+}
+
+static gint
+expose(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
+{
+ struct graphics_priv *gra=user_data;
+
+ gra->visible=1;
+ if (! gra->drawable)
+ configure(widget, NULL, user_data);
+ gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
+ gra->drawable, event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ return FALSE;
+}
+
+#if 0
+static gint
+button_timeout(gpointer user_data)
+{
+#if 0
+ struct container *co=user_data;
+ int x=co->gra->gra->button_event.x;
+ int y=co->gra->gra->button_event.y;
+ int button=co->gra->gra->button_event.button;
+
+ co->gra->gra->button_timeout=0;
+ popup(co, x, y, button);
+
+ return FALSE;
+#endif
+}
+#endif
+
+static gint
+button_press(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+
+ p.x=event->x;
+ p.y=event->y;
+ if (this->button_callback)
+ (*this->button_callback)(this->button_callback_data, 1, event->button, &p);
+ return FALSE;
+}
+
+static gint
+button_release(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+
+ p.x=event->x;
+ p.y=event->y;
+ if (this->button_callback)
+ (*this->button_callback)(this->button_callback_data, 0, event->button, &p);
+ return FALSE;
+}
+
+static gint
+scroll(GtkWidget * widget, GdkEventScroll * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+ int button;
+
+ p.x=event->x;
+ p.y=event->y;
+ if (this->button_callback) {
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ button=4;
+ break;
+ case GDK_SCROLL_DOWN:
+ button=5;
+ break;
+ default:
+ button=-1;
+ break;
+ }
+ if (button != -1) {
+ (*this->button_callback)(this->button_callback_data, 1, button, &p);
+ (*this->button_callback)(this->button_callback_data, 0, button, &p);
+ }
+ }
+ return FALSE;
+}
+
+static gint
+motion_notify(GtkWidget * widget, GdkEventMotion * event, gpointer user_data)
+{
+ struct graphics_priv *this=user_data;
+ struct point p;
+
+ p.x=event->x;
+ p.y=event->y;
+ if (this->motion_callback)
+ (*this->motion_callback)(this->motion_callback_data, &p);
+ return FALSE;
+}
+
+#endif
+
+
+static struct graphics_priv *
+overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p, int w, int h)
+{
+#if 0
+ struct graphics_priv *this=graphics_gtk_drawing_area_new_helper(meth);
+ this->drawable=gdk_pixmap_new(gr->widget->window, w, h, -1);
+ this->colormap=gr->colormap;
+ this->widget=gr->widget;
+ this->p=*p;
+ this->width=w;
+ this->height=h;
+ this->parent=gr;
+ this->background=gdk_pixmap_new(gr->widget->window, w, h, -1);
+ this->next=gr->overlays;
+ gr->overlays=this;
+ return this;
+#endif
+ return NULL;
+}
+
+static void *
+get_data(struct graphics_priv *this, char *type)
+{
+ if (strcmp(type,"opengl_displaylist"))
+ return NULL;
+#if 0
+ dbg(1,"Creating the DL from driver\n");
+ this->DLid = glGenLists(1);
+#endif
+ return &this->DLid;
+}
+
+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;
+}
+
+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,
+#ifdef HAVE_IMLIB2
+ draw_image_warp,
+#else
+ NULL,
+#endif
+ draw_restore,
+ font_new,
+ gc_new,
+ background_gc,
+ overlay_new,
+ image_new,
+ get_data,
+ register_resize_callback,
+ register_button_callback,
+ register_motion_callback,
+ NULL, // image_free
+};
+
+static struct graphics_priv *
+graphics_opengl_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs)
+{
+ struct graphics_priv *this=g_new0(struct graphics_priv,1);
+ *meth=graphics_methods;
+
+// GtkWidget *draw;
+
+// draw=gtk_drawnig_area_new();
+
+
+ // Initialize the fonts
+ int ctx = 0;
+ int font = 0;
+ ctx = glcGenContext();
+ glcContext(ctx);
+ font = glcNewFontFromFamily(glcGenFontID(), "Verdana");
+ glcFont(font);
+ glcStringType(GLC_UTF8_QSO);
+// glcFontFace(font, "Italic");
+
+
+/*
+ this->widget=draw;
+
+ this->colormap=gdk_colormap_new(gdk_visual_get_system(),FALSE);
+ gtk_widget_set_events(draw, GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK|GDK_KEY_PRESS_MASK);
+ g_signal_connect(G_OBJECT(draw), "expose_event", G_CALLBACK(expose), this);
+ g_signal_connect(G_OBJECT(draw), "configure_event", G_CALLBACK(configure), this);
+#if 0
+ g_signal_connect(G_OBJECT(draw), "realize_event", G_CALLBACK(realize), co);
+#endif
+ g_signal_connect(G_OBJECT(draw), "button_press_event", G_CALLBACK(button_press), this);
+ g_signal_connect(G_OBJECT(draw), "button_release_event", G_CALLBACK(button_release), this);
+ g_signal_connect(G_OBJECT(draw), "scroll_event", G_CALLBACK(scroll), this);
+ g_signal_connect(G_OBJECT(draw), "motion_notify_event", G_CALLBACK(motion_notify), this);
+ */
+ return this;
+}
+
+void
+plugin_init(void)
+{
+ plugin_register_graphics_type("opengl", graphics_opengl_new);
+}
diff --git a/graphics/qt_qpainter/Makefile.am b/graphics/qt_qpainter/Makefile.am
new file mode 100644
index 00000000..b222328e
--- /dev/null
+++ b/graphics/qt_qpainter/Makefile.am
@@ -0,0 +1,10 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @QT_GUI_CFLAGS@ @NAVIT_CFLAGS@ -I$(top_srcdir) -I$(top_srcdir)/navit -DMODULE=graphics_qt_qpainter
+modulegraphics_LTLIBRARIES = libgraphics_qt_qpainter.la
+libgraphics_qt_qpainter_la_SOURCES = graphics_qt_qpainter.cpp graphics_qt_qpainter.moc
+libgraphics_qt_qpainter_la_LDFLAGS = @QT_GUI_LIBS@ -module -avoid-version
+if GRAPHICS_QT_QPAINTER
+BUILT_SOURCES = graphics_qt_qpainter.moc
+graphics_qt_qpainter.moc:
+ @MOC@ $(srcdir)/graphics_qt_qpainter.cpp >graphics_qt_qpainter.moc
+endif
diff --git a/graphics/qt_qpainter/graphics_qt_qpainter.cpp b/graphics/qt_qpainter/graphics_qt_qpainter.cpp
new file mode 100644
index 00000000..9c05e8e8
--- /dev/null
+++ b/graphics/qt_qpainter/graphics_qt_qpainter.cpp
@@ -0,0 +1,1214 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+//##############################################################################################################
+//#
+//# File: graphics_qt_qpainter.cpp
+//# Description: Graphics interface for internal GUI using Qt (Trolltech.com)
+//# Comment:
+//# Authors: Martin Schaller (04/2008), Stefan Klumpp (04/2008)
+//#
+//##############################################################################################################
+
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+#include "point.h"
+#include "item.h"
+#include "graphics.h"
+#include "color.h"
+#include "debug.h"
+#include "plugin.h"
+#include "callback.h"
+#include "event.h"
+#include "window.h"
+#include "keys.h"
+#include "navit/font/freetype/font_freetype.h"
+
+#include <qglobal.h>
+#if QT_VERSION < 0x040000
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qlistview.h>
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#ifdef HAVE_QPE
+#include <qpe/qpeapplication.h>
+#endif
+#else
+#include <QResizeEvent>
+#include <QApplication>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QPainter>
+#include <QPen>
+#include <QBrush>
+#include <QPixmap>
+#include <QWidget>
+#include <QPolygonF>
+#include <QtGui>
+#endif
+
+
+//##############################################################################################################
+//# Description: RenderArea (QWidget) class for the main window (map, menu, ...)
+//# Comment:
+//# Authors: Martin Schaller (04/2008), Stefan Klumpp (04/2008)
+//##############################################################################################################
+class RenderArea : public QWidget
+ {
+ Q_OBJECT
+ public:
+ RenderArea(struct graphics_priv *priv, QWidget *parent = 0, int w=800, int h=800, int overlay=0);
+ QPixmap *pixmap;
+ struct callback_list *cbl;
+ struct graphics_priv *gra;
+
+#if QT_VERSION < 0x040000
+ GHashTable *timer_type;
+ GHashTable *timer_callback;
+ GHashTable *watches;
+#endif
+ protected:
+ int is_overlay;
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void mouseEvent(int pressed, QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+#if QT_VERSION < 0x040000
+ void timerEvent(QTimerEvent *event);
+#endif
+ protected slots:
+ void watchEvent(int fd);
+ };
+
+
+#include "graphics_qt_qpainter.moc"
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+struct graphics_gc_priv {
+ QPen *pen;
+ QBrush *brush;
+ struct color c;
+};
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+struct graphics_priv {
+#ifdef HAVE_QPE
+ QPEApplication *app;
+#else
+ QApplication *app;
+#endif
+ RenderArea *widget;
+ QPainter *painter;
+ struct graphics_gc_priv *background_gc;
+ unsigned char rgba[4];
+ enum draw_mode_num mode;
+ struct graphics_priv *parent,*overlays,*next;
+ struct point p,pclean;
+ int cleanup;
+ int overlay_disable;
+ int wraparound;
+ struct font_priv * (*font_freetype_new)(void *meth);
+ struct font_freetype_methods freetype_methods;
+ int w,h;
+};
+
+static void
+overlay_rect(struct graphics_priv *parent, struct graphics_priv *overlay, int clean, QRect *r)
+{
+ struct point p;
+ int w,h;
+ if (clean) {
+ p=overlay->pclean;
+ } else {
+ p=overlay->p;;
+ }
+ w=overlay->widget->pixmap->width();
+ h=overlay->widget->pixmap->height();
+ if (overlay->wraparound) {
+ if (p.x < 0)
+ p.x+=parent->widget->pixmap->width();
+ if (p.y < 0)
+ p.y+=parent->widget->pixmap->height();
+ if (w < 0)
+ w += parent->widget->pixmap->width();
+ if (h < 0)
+ h += parent->widget->pixmap->height();
+ }
+ r->setRect(p.x, p.y, w, h);
+}
+
+static void
+qt_qpainter_draw(struct graphics_priv *gr, const QRect *r, int paintev)
+{
+ if (!paintev) {
+ dbg(1,"update %d,%d %d x %d\n", r->x(), r->y(), r->width(), r->height());
+ if (r->x() <= -r->width())
+ return;
+ if (r->y() <= -r->height())
+ return;
+ if (r->x() > gr->widget->pixmap->width())
+ return;
+ if (r->y() > gr->widget->pixmap->height())
+ return;
+ dbg(1,"update valid %d,%d %dx%d\n", r->x(), r->y(), r->width(), r->height());
+ gr->widget->update(*r);
+ return;
+ }
+ QPixmap pixmap(r->width(),r->height());
+ QPainter painter(&pixmap);
+ struct graphics_priv *overlay=NULL;
+ if (! gr->overlay_disable)
+ overlay=gr->overlays;
+ if ((gr->p.x || gr->p.y) && gr->background_gc) {
+ painter.setPen(*gr->background_gc->pen);
+ painter.fillRect(0, 0, gr->widget->pixmap->width(), gr->widget->pixmap->height(), *gr->background_gc->brush);
+ }
+ painter.drawPixmap(QPoint(gr->p.x,gr->p.y), *gr->widget->pixmap, *r);
+ while (overlay) {
+ QRect ovr;
+ overlay_rect(gr, overlay, 0, &ovr);
+ if (!overlay->overlay_disable && r->intersects(ovr)) {
+ unsigned char *data;
+ int i,size=ovr.width()*ovr.height();
+#if QT_VERSION < 0x040000
+ QImage img=overlay->widget->pixmap->convertToImage();
+ img.setAlphaBuffer(1);
+#else
+ QImage img=overlay->widget->pixmap->toImage().convertToFormat(QImage::Format_ARGB32);
+#endif
+ data=img.bits();
+ for (i = 0 ; i < size ; i++) {
+ if (data[0] == overlay->rgba[0] && data[1] == overlay->rgba[1] && data[2] == overlay->rgba[2])
+ data[3]=overlay->rgba[3];
+ data+=4;
+ }
+#if QT_VERSION < 0x040000
+ painter.drawImage(QPoint(ovr.x()-r->x(),ovr.y()-r->y()), img, 0);
+#else
+ painter.drawImage(QPoint(ovr.x()-r->x(),ovr.y()-r->y()), img);
+#endif
+ }
+ overlay=overlay->next;
+ }
+ QPainter painterw(gr->widget);
+ painterw.drawPixmap(r->x(), r->y(), pixmap);
+}
+
+
+//##############################################################################################################
+//# Description: Constructor
+//# Comment: Using a QPixmap for rendering the graphics
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+RenderArea::RenderArea(struct graphics_priv *priv, QWidget *parent, int w, int h, int overlay)
+ : QWidget(parent)
+{
+ pixmap = new QPixmap(w, h);
+ if (!overlay) {
+#if QT_VERSION >= 0x040000
+ setWindowTitle("Navit");
+#else
+ setCaption("Navit");
+#endif
+ }
+ is_overlay=overlay;
+ gra=priv;
+#if QT_VERSION < 0x040000
+ timer_type=g_hash_table_new(NULL, NULL);
+ timer_callback=g_hash_table_new(NULL, NULL);
+ watches=g_hash_table_new(NULL, NULL);
+ setBackgroundMode(NoBackground);
+#endif
+}
+
+//##############################################################################################################
+//# Description: QWidget:sizeHint
+//# Comment: This property holds the recommended size for the widget
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+QSize RenderArea::sizeHint() const
+{
+ return QSize(gra->w, gra->h);
+}
+
+//##############################################################################################################
+//# Description: QWidget:paintEvent
+//# Comment: A paint event is a request to repaint all or part of the widget.
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+void RenderArea::paintEvent(QPaintEvent * event)
+{
+ qt_qpainter_draw(gra, &event->rect(), 1);
+#if 0
+ QPainter painter(this);
+ painter.drawPixmap(0, 0, *pixmap);
+#endif
+}
+
+
+//##############################################################################################################
+//# Description: QWidget::resizeEvent()
+//# Comment: When resizeEvent() is called, the widget already has its new geometry.
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+void RenderArea::resizeEvent(QResizeEvent * event)
+{
+ if (!this->is_overlay) {
+ QSize size=event->size();
+ delete pixmap;
+ pixmap=new QPixmap(size);
+ pixmap->fill();
+ QPainter painter(pixmap);
+ QBrush brush;
+ painter.fillRect(0, 0, size.width(), size.height(), brush);
+ dbg(0,"size %dx%d\n", size.width(), size.height());
+ dbg(0,"pixmap %p %dx%d\n", pixmap, pixmap->width(), pixmap->height());
+ callback_list_call_attr_2(this->cbl, attr_resize, (void *)size.width(), (void *)size.height());
+ }
+}
+
+//##############################################################################################################
+//# Description: Method to handle mouse clicks
+//# Comment: Delegate of QWidget::mousePressEvent and QWidget::mouseReleaseEvent (see below)
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+void RenderArea::mouseEvent(int pressed, QMouseEvent *event)
+{
+ struct point p;
+ p.x=event->x();
+ p.y=event->y();
+ switch (event->button()) {
+ case Qt::LeftButton:
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)pressed, (void *)1, (void *)&p);
+ break;
+ case Qt::MidButton:
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)pressed, (void *)2, (void *)&p);
+ break;
+ case Qt::RightButton:
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)pressed, (void *)3, (void *)&p);
+ break;
+ default:
+ break;
+ }
+}
+
+void RenderArea::mousePressEvent(QMouseEvent *event)
+{
+ mouseEvent(1, event);
+}
+
+void RenderArea::mouseReleaseEvent(QMouseEvent *event)
+{
+ mouseEvent(0, event);
+}
+
+//##############################################################################################################
+//# Description: QWidget::mouseMoveEvent
+//# Comment: If mouse tracking is switched on, mouse move events occur even if no mouse button is pressed.
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+void RenderArea::mouseMoveEvent(QMouseEvent *event)
+{
+ struct point p;
+ p.x=event->x();
+ p.y=event->y();
+ callback_list_call_attr_1(this->cbl, attr_motion, (void *)&p);
+}
+
+
+//##############################################################################################################
+//# Description: Qt Event :: Zoom in/out with the mouse's scrollwheel
+//# Comment:
+//# Authors: Stefan Klumpp (04/2008)
+//##############################################################################################################
+void RenderArea::wheelEvent(QWheelEvent *event)
+{
+ struct point p;
+ int button;
+
+ p.x=event->x(); // xy-coordinates of the mouse pointer
+ p.y=event->y();
+
+ if (event->delta() > 0) // wheel movement away from the person
+ button=4;
+ else if (event->delta() < 0) // wheel movement towards the person
+ button=5;
+ else
+ button=-1;
+
+ if (button != -1) {
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)1, (void *)button, (void *)&p);
+ callback_list_call_attr_3(this->cbl, attr_button, (void *)0, (void *)button, (void *)&p);
+ }
+
+ event->accept();
+}
+
+void RenderArea::keyPressEvent(QKeyEvent *event)
+{
+#if QT_VERSION < 0x040000
+ QString str=event->text();
+ QCString cstr=str.utf8();
+ const char *text=cstr;
+ dbg(0,"enter text='%s' 0x%x (%d) key=%d\n", text, text[0], strlen(text), event->key());
+ if (!text || !text[0] || text[0] == 0x7f) {
+ dbg(0,"special key\n");
+ switch (event->key()) {
+ case 4099:
+ {
+ text=(char []){NAVIT_KEY_BACKSPACE,'\0'};
+ }
+ break;
+ case 4101:
+ {
+ text=(char []){NAVIT_KEY_RETURN,'\0'};
+ }
+ break;
+ case 4114:
+ {
+ text=(char []){NAVIT_KEY_LEFT,'\0'};
+ }
+ break;
+ case 4115:
+ {
+ text=(char []){NAVIT_KEY_UP,'\0'};
+ }
+ break;
+ case 4116:
+ {
+ text=(char []){NAVIT_KEY_RIGHT,'\0'};
+ }
+ break;
+ case 4117:
+ {
+ text=(char []){NAVIT_KEY_DOWN,'\0'};
+ }
+ break;
+ }
+ }
+ callback_list_call_attr_1(this->cbl, attr_keypress, (void *)text);
+ event->accept();
+#endif
+}
+//##############################################################################################################
+// General comments:
+// -----------------
+// gr = graphics = draw area
+// gc = graphics context = pen to paint on the draw area
+//##############################################################################################################
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+struct graphics_font_priv {
+ QFont *font;
+};
+
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+struct graphics_image_priv {
+ QImage *image;
+};
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void graphics_destroy(struct graphics_priv *gr)
+{
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void font_destroy(struct graphics_font_priv *font)
+{
+
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static struct graphics_font_methods font_methods = {
+ font_destroy
+};
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+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 *ret=g_new0(struct graphics_font_priv, 1);
+ ret->font=new QFont("Arial",size/20);
+ *meth=font_methods;
+ return ret;
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void gc_destroy(struct graphics_gc_priv *gc)
+{
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+ gc->pen->setWidth(w);
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
+{
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+#if QT_VERSION >= 0x040000
+ QColor col(c->r >> 8, c->g >> 8, c->b >> 8 /* , c->a >> 8 */);
+#else
+ QColor col(c->r >> 8, c->g >> 8, c->b >> 8);
+#endif
+ gc->pen->setColor(col);
+ gc->brush->setColor(col);
+ gc->c=*c;
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static struct graphics_gc_methods gc_methods = {
+ gc_destroy,
+ gc_set_linewidth,
+ gc_set_dashes,
+ gc_set_foreground,
+ gc_set_background
+};
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
+{
+ *meth=gc_methods;
+ struct graphics_gc_priv *ret=g_new0(struct graphics_gc_priv, 1);
+ ret->pen=new QPen();
+ ret->brush=new QBrush(Qt::SolidPattern);
+ return ret;
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static struct graphics_image_priv * image_new(struct graphics_priv *gr, struct graphics_image_methods *meth, char *path, int *w, int *h, struct point *hot, int rotation)
+{
+ struct graphics_image_priv *ret;
+
+ ret=g_new0(struct graphics_image_priv, 1);
+
+ ret->image=new QImage(path);
+ if (ret->image->isNull()) {
+ delete(ret->image);
+ g_free(ret);
+ return NULL;
+ }
+ *w=ret->image->width();
+ *h=ret->image->height();
+ if (hot) {
+ hot->x=*w/2;
+ hot->y=*h/2;
+ }
+ return ret;
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+#if QT_VERSION >= 0x040000
+ QPolygon polygon;
+#else
+ QPointArray polygon;
+#endif
+
+ for (i = 0 ; i < count ; i++)
+ polygon.putPoints(i, 1, p[i].x, p[i].y);
+ gr->painter->setPen(*gc->pen);
+ gr->painter->drawPolyline(polygon);
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+#if QT_VERSION >= 0x040000
+ QPolygon polygon;
+#else
+ QPointArray polygon;
+#endif
+
+ for (i = 0 ; i < count ; i++)
+ polygon.putPoints(i, 1, p[i].x, p[i].y);
+ gr->painter->setPen(*gc->pen);
+ gr->painter->setBrush(*gc->brush);
+ gr->painter->drawPolygon(polygon);
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+ dbg(1,"gr=%p gc=%p %d,%d,%d,%d\n", gr, gc, p->x, p->y, w, h);
+ gr->painter->fillRect(p->x,p->y, w, h, *gc->brush);
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+ gr->painter->setPen(*gc->pen);
+ gr->painter->drawArc(p->x-r/2, p->y-r/2, r, r, 0, 360*16);
+
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+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)
+{
+ QPainter *painter=gr->painter;
+#if 0
+ QString tmp=QString::fromUtf8(text);
+#ifndef QT_NO_TRANSFORMATIONS
+#if QT_VERSION >= 0x040000
+ QMatrix sav=gr->painter->worldMatrix();
+ QMatrix m(dx/65535.0,dy/65535.0,-dy/65535.0,dx/65535.0,p->x,p->y);
+ painter->setWorldMatrix(m,TRUE);
+#else
+ QWMatrix sav=gr->painter->worldMatrix();
+ QWMatrix m(dx/65535.0,dy/65535.0,-dy/65535.0,dx/65535.0,p->x,p->y);
+ painter->setWorldMatrix(m,TRUE);
+#endif
+ painter->setPen(*fg->pen);
+ painter->setFont(*font->font);
+ painter->drawText(0, 0, tmp);
+ painter->setWorldMatrix(sav);
+#else
+ painter->setPen(*fg->pen);
+ painter->setFont(*font->font);
+ painter->drawText(p->x, p->y, tmp);
+#endif
+#else
+ struct font_freetype_text *t;
+ struct font_freetype_glyph *g, **gp;
+ struct color transparent = {0x0000, 0x0000, 0x0000, 0x0000};
+ struct color *fgc=&fg->c, *bgc=&bg->c;
+
+ int i,x,y;
+
+ if (! font)
+ return;
+ t=gr->freetype_methods.text_new(text, (struct font_freetype_font *)font, dx, dy);
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=t->glyph;
+ i=t->glyph_count;
+ if (bg) {
+ while (i-- > 0) {
+ g=*gp++;
+ if (g->w && g->h) {
+ unsigned char *data;
+#if QT_VERSION < 0x040000
+ QImage img(g->w+2, g->h+2, 32);
+ img.setAlphaBuffer(1);
+ data=img.bits();
+ gr->freetype_methods.get_shadow(g,(unsigned char *)(img.jumpTable()),32,0,bgc,&transparent);
+#else
+ QImage img(g->w+2, g->h+2, QImage::Format_ARGB32);
+ data=img.bits();
+ gr->freetype_methods.get_shadow(g,(unsigned char *)data,32,img.bytesPerLine(),bgc,&transparent);
+#endif
+
+ painter->drawImage(((x+g->x)>>6)-1, ((y+g->y)>>6)-1, img);
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ } else
+ bgc=&transparent;
+ x=p->x << 6;
+ y=p->y << 6;
+ gp=t->glyph;
+ i=t->glyph_count;
+ while (i-- > 0) {
+ g=*gp++;
+ if (g->w && g->h) {
+ unsigned char *data;
+#if QT_VERSION < 0x040000
+ QImage img(g->w, g->h, 32);
+ img.setAlphaBuffer(1);
+ data=img.bits();
+ gr->freetype_methods.get_glyph(g,(unsigned char *)(img.jumpTable()),32,0,fgc,bgc,&transparent);
+#else
+ QImage img(g->w, g->h, QImage::Format_ARGB32);
+ data=img.bits();
+ gr->freetype_methods.get_glyph(g,(unsigned char *)data,32,img.bytesPerLine(),fgc,bgc,&transparent);
+#endif
+ painter->drawImage((x+g->x)>>6, (y+g->y)>>6, img);
+ }
+ x+=g->dx;
+ y+=g->dy;
+ }
+ gr->freetype_methods.text_destroy(t);
+#endif
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+ gr->painter->drawImage(p->x, p->y, *img->image);
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_image_warp(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, int count, char *data)
+{
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+}
+
+
+static void
+draw_drag(struct graphics_priv *gr, struct point *p)
+{
+ if (!gr->cleanup) {
+ gr->pclean=gr->p;
+ gr->cleanup=1;
+ }
+ if (p)
+ gr->p=*p;
+ else {
+ gr->p.x=0;
+ gr->p.y=0;
+ }
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ gr->background_gc=gc;
+ gr->rgba[2]=gc->c.r >> 8;
+ gr->rgba[1]=gc->c.g >> 8;
+ gr->rgba[0]=gc->c.b >> 8;
+ gr->rgba[3]=gc->c.a >> 8;
+}
+
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ dbg(1,"mode for %p %d\n", gr, mode);
+ QRect r;
+ if (mode == draw_mode_begin) {
+ gr->painter->begin(gr->widget->pixmap);
+#if 0
+ gr->painter->fillRect(QRect(QPoint(0,0), gr->widget->size()), *gr->background_gc->brush);
+#endif
+ }
+#if QT_VERSION < 0x040000
+ if (mode == draw_mode_cursor) {
+ gr->painter->begin(gr->widget);
+ }
+#endif
+ if (mode == draw_mode_end) {
+#if 0
+ if (gr->mode == draw_mode_begin) {
+#endif
+ gr->painter->end();
+ if (gr->parent) {
+ if (gr->cleanup) {
+ overlay_rect(gr->parent, gr, 1, &r);
+ qt_qpainter_draw(gr->parent, &r, 0);
+ gr->cleanup=0;
+ }
+ overlay_rect(gr->parent, gr, 0, &r);
+ qt_qpainter_draw(gr->parent, &r, 0);
+ } else {
+ r.setRect(0, 0, gr->widget->pixmap->width(), gr->widget->pixmap->height());
+ qt_qpainter_draw(gr, &r, 0);
+ }
+#if 0
+ } else {
+#if QT_VERSION < 0x040000
+ gr->painter->end();
+#endif
+ }
+#endif
+ }
+#if QT_VERSION >= 0x040000
+ if (mode == draw_mode_end_lazy)
+ gr->painter->end();
+#endif
+ gr->mode=mode;
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+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 argc=1;
+static char *argv[]={(char *)"navit",NULL};
+
+static int
+fullscreen(struct window *win, int on)
+{
+ struct graphics_priv *this_=(struct graphics_priv *)win->priv;
+ if (on)
+ this_->widget->showFullScreen();
+ else
+ this_->widget->showMaximized();
+ return 1;
+}
+
+static void
+disable_suspend(struct window *win)
+{
+#ifdef HAVE_QPE
+ struct graphics_priv *this_=(struct graphics_priv *)win->priv;
+ this_->app->setTempScreenSaverMode(QPEApplication::DisableLightOff);
+#endif
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void * get_data(struct graphics_priv *this_, char *type)
+{
+ struct window *win;
+ if (strcmp(type, "window"))
+ return NULL;
+ win=g_new(struct window, 1);
+ this_->painter=new QPainter;
+ if (this_->w && this_->h)
+ this_->widget->show();
+ else
+ this_->widget->showMaximized();
+ win->priv=this_;
+ win->fullscreen=fullscreen;
+ win->disable_suspend=disable_suspend;
+ return win;
+}
+
+static void
+image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
+{
+ delete priv->image;
+ g_free(priv);
+}
+
+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)
+{
+ QPainter *painter=gr->painter;
+ QString tmp=QString::fromUtf8(text);
+ painter->setFont(*font->font);
+ QRect r=painter->boundingRect(0,0,gr->widget->width(),gr->widget->height(),0,tmp);
+ ret[0].x=0;
+ ret[0].y=-r.height();
+ ret[1].x=0;
+ ret[1].y=0;
+ ret[2].x=r.width();
+ ret[2].y=0;
+ ret[3].x=r.width();
+ ret[3].y=-r.height();
+}
+
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static void overlay_disable(struct graphics_priv *gr, int disable)
+{
+ gr->overlay_disable=disable;
+}
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+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,
+ image_free,
+ get_text_bbox,
+ overlay_disable,
+};
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+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)
+{
+ *meth=graphics_methods;
+ struct graphics_priv *ret=g_new0(struct graphics_priv, 1);
+ if (gr->font_freetype_new) {
+ ret->font_freetype_new=gr->font_freetype_new;
+ gr->font_freetype_new(&ret->freetype_methods);
+ meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *, int, int))ret->freetype_methods.font_new;
+ meth->get_text_bbox=(void (*)(struct graphics_priv*, struct graphics_font_priv*, char*, int, int, struct point*, int))ret->freetype_methods.get_text_bbox;
+ }
+ ret->widget= new RenderArea(ret,NULL,w,h,1);
+ ret->wraparound=wraparound;
+ ret->painter=new QPainter;
+ ret->p=*p;
+ ret->parent=gr;
+ ret->next=gr->overlays;
+ gr->overlays=ret;
+ return ret;
+}
+
+#if QT_VERSION < 0x040000
+
+
+static struct graphics_priv *event_gr;
+
+static void
+event_qt_main_loop_run(void)
+{
+ event_gr->app->exec();
+}
+
+static void event_qt_main_loop_quit(void)
+{
+ dbg(0,"enter\n");
+ exit(0);
+}
+
+struct event_watch {
+ QSocketNotifier *sn;
+ struct callback *cb;
+ void *fd;
+};
+
+static struct event_watch *
+event_qt_add_watch(void *fd, enum event_watch_cond cond, struct callback *cb)
+{
+ dbg(1,"enter fd=%d\n",(int)(long)fd);
+ struct event_watch *ret=g_new0(struct event_watch, 1);
+ ret->fd=fd;
+ ret->cb=cb;
+ g_hash_table_insert(event_gr->widget->watches, fd, ret);
+ ret->sn=new QSocketNotifier((int)(long)fd, QSocketNotifier::Read, event_gr->widget);
+ QObject::connect(ret->sn, SIGNAL(activated(int)), event_gr->widget, SLOT(watchEvent(int)));
+ return ret;
+}
+
+static void
+event_qt_remove_watch(struct event_watch *ev)
+{
+ g_hash_table_remove(event_gr->widget->watches, ev->fd);
+ delete(ev->sn);
+ g_free(ev);
+
+}
+
+static struct event_timeout *
+event_qt_add_timeout(int timeout, int multi, struct callback *cb)
+{
+ int id;
+ id=event_gr->widget->startTimer(timeout);
+ g_hash_table_insert(event_gr->widget->timer_callback, (void *)id, cb);
+ g_hash_table_insert(event_gr->widget->timer_type, (void *)id, (void *)!!multi);
+ return (struct event_timeout *)id;
+}
+
+static void
+event_qt_remove_timeout(struct event_timeout *ev)
+{
+ event_gr->widget->killTimer((int)(long)ev);
+ g_hash_table_remove(event_gr->widget->timer_callback, ev);
+ g_hash_table_remove(event_gr->widget->timer_type, ev);
+}
+
+static struct event_idle *
+event_qt_add_idle(int priority, struct callback *cb)
+{
+ dbg(0,"enter\n");
+ return (struct event_idle *)event_qt_add_timeout(0, 1, cb);
+}
+
+static void
+event_qt_remove_idle(struct event_idle *ev)
+{
+ dbg(0,"enter\n");
+ event_qt_remove_timeout((struct event_timeout *) ev);
+}
+
+static void
+event_qt_call_callback(struct callback_list *cb)
+{
+ dbg(0,"enter\n");
+}
+
+static struct event_methods event_qt_methods = {
+ event_qt_main_loop_run,
+ event_qt_main_loop_quit,
+ event_qt_add_watch,
+ event_qt_remove_watch,
+ event_qt_add_timeout,
+ event_qt_remove_timeout,
+ event_qt_add_idle,
+ event_qt_remove_idle,
+ event_qt_call_callback,
+};
+
+struct event_priv {
+};
+
+struct event_priv *
+event_qt_new(struct event_methods *meth)
+{
+ dbg(0,"enter\n");
+ *meth=event_qt_methods;
+ return NULL;
+}
+
+void RenderArea::timerEvent(QTimerEvent *event)
+{
+ int id=event->timerId();
+ struct callback *cb=(struct callback *)g_hash_table_lookup(timer_callback, (void *)id);
+ if (cb)
+ callback_call_0(cb);
+ if (!g_hash_table_lookup(timer_type, (void *)id))
+ event_qt_remove_timeout((struct event_timeout *)id);
+}
+#endif
+
+void RenderArea::watchEvent(int fd)
+{
+#if QT_VERSION < 0x040000
+ struct event_watch *ev=(struct event_watch *)g_hash_table_lookup(watches, (void *)fd);
+ dbg(1,"fd=%d ev=%p cb=%p\n", fd, ev, ev->cb);
+ callback_call_0(ev->cb);
+#endif
+}
+
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+static struct graphics_priv * graphics_qt_qpainter_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
+{
+ struct graphics_priv *ret;
+ struct font_priv * (*font_freetype_new)(void *meth);
+ struct attr *attr;
+
+ dbg(0,"enter\n");
+#if QT_VERSION < 0x040000
+ if (event_gr)
+ return NULL;
+ if (! event_request_system("qt","graphics_qt_qpainter_new"))
+ return NULL;
+#else
+ if (! event_request_system("glib","graphics_qt_qpainter_new"))
+ return NULL;
+#endif
+#if 1
+ font_freetype_new=(struct font_priv *(*)(void *))plugin_get_font_type("freetype");
+ if (!font_freetype_new)
+ return NULL;
+#endif
+ ret=g_new0(struct graphics_priv, 1);
+ ret->font_freetype_new=font_freetype_new;
+ *meth=graphics_methods;
+#if 1
+ font_freetype_new(&ret->freetype_methods);
+ meth->font_new=(struct graphics_font_priv *(*)(struct graphics_priv *, struct graphics_font_methods *, char *, int, int))ret->freetype_methods.font_new;
+ meth->get_text_bbox=(void (*)(struct graphics_priv*, struct graphics_font_priv*, char*, int, int, struct point*, int))ret->freetype_methods.get_text_bbox;
+#endif
+
+#ifdef HAVE_QPE
+ ret->app = new QPEApplication(argc, argv);
+#else
+ ret->app = new QApplication(argc, argv);
+#endif
+ ret->widget= new RenderArea(ret);
+ ret->widget->cbl=cbl;
+#if QT_VERSION < 0x040000
+ event_gr=ret;
+#endif
+ ret->w=800;
+ ret->h=600;
+ if ((attr=attr_search(attrs, NULL, attr_w)))
+ ret->w=attr->u.num;
+ if ((attr=attr_search(attrs, NULL, attr_h)))
+ ret->h=attr->u.num;
+
+ dbg(0,"return\n");
+ return ret;
+}
+
+
+//##############################################################################################################
+//# Description:
+//# Comment:
+//# Authors: Martin Schaller (04/2008)
+//##############################################################################################################
+void plugin_init(void)
+{
+ plugin_register_graphics_type("qt_qpainter", graphics_qt_qpainter_new);
+#if QT_VERSION < 0x040000
+ plugin_register_event_type("qt", event_qt_new);
+#endif
+}
+
+
+
+
+// *** EOF ***
diff --git a/graphics/sdl/Makefile.am b/graphics/sdl/Makefile.am
new file mode 100644
index 00000000..084bf3e9
--- /dev/null
+++ b/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 raster.c raster.h
+libgraphics_sdl_la_LDFLAGS = @SDL_LIBS@ @SDL_IMAGE_LIBS@ @FREETYPE2_LIBS@ @FONTCONFIG_LIBS@ -module -avoid-version
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);
+}
+
diff --git a/graphics/sdl/raster.c b/graphics/sdl/raster.c
new file mode 100644
index 00000000..dd54cd4a
--- /dev/null
+++ b/graphics/sdl/raster.c
@@ -0,0 +1,2022 @@
+/* raster.c -- line/rect/circle/poly rasterization
+
+ copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org>
+ license: LGPLv2
+
+ based on SDL_gfx (c) A. Schiffler
+ and SGE (c)1999-2003 Anders Lindström
+
+ + added filled anti-aliased polygons
+ + fixed some bugs and improved performance
+
+ revision history
+ 2008-07-05 initial
+ 2008-07-06 aacircle
+*/
+
+
+#include <math.h>
+
+#include "raster.h"
+
+#undef DEBUG
+#undef PARANOID
+
+
+/* raster_rect */
+
+static inline void raster_rect_inline(SDL_Surface *dst, int16_t x1, int16_t y1, int16_t w, int16_t h, uint32_t color)
+{
+ /* sge */
+ SDL_Rect rect;
+
+#if 1
+ if((w <= 0) || (h <= 0))
+ {
+ return;
+ }
+
+#if 0
+ if(x1 < 0)
+ {
+ if((x1 + w) < 0)
+ {
+ return;
+ }
+ else
+ {
+ w = w + x1;
+ x1 = 0;
+ }
+ }
+ if(y1 < 0)
+ {
+ if((y1 + h) < 0)
+ {
+ return;
+ }
+ else
+ {
+ h = h + y1;
+ y1 = 0;
+ }
+ }
+
+ if(x1 + w >= dst->w)
+ {
+ w = dst->w - x1;
+ }
+ if(y1 + h >= dst->h)
+ {
+ h = dst->h - y1;
+ }
+#endif
+
+ rect.x = x1;
+ rect.y = y1;
+ rect.w = w;
+ rect.h = h;
+
+ /* will clip internally */
+ SDL_FillRect(dst, &rect, color);
+
+#else
+
+ x2 = x1 + w;
+ y2 = y1 + h;
+
+ /*
+ * Order coordinates to ensure that
+ * x1<=x2 and y1<=y2
+ */
+ if (x1 > x2) {
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ }
+ if (y1 > y2) {
+ tmp = y1;
+ y1 = y2;
+ y2 = tmp;
+ }
+
+ /*
+ * Get clipping boundary and
+ * check visibility
+ */
+ left = dst->clip_rect.x;
+ if (x2<left) {
+ return(0);
+ }
+ right = dst->clip_rect.x + dst->clip_rect.w - 1;
+ if (x1>right) {
+ return(0);
+ }
+ top = dst->clip_rect.y;
+ if (y2<top) {
+ return(0);
+ }
+ bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
+ if (y1>bottom) {
+ return(0);
+ }
+
+ /* Clip all points */
+ if (x1<left) {
+ x1=left;
+ } else if (x1>right) {
+ x1=right;
+ }
+ if (x2<left) {
+ x2=left;
+ } else if (x2>right) {
+ x2=right;
+ }
+ if (y1<top) {
+ y1=top;
+ } else if (y1>bottom) {
+ y1=bottom;
+ }
+ if (y2<top) {
+ y2=top;
+ } else if (y2>bottom) {
+ y2=bottom;
+ }
+
+#if 0
+ /*
+ * Test for special cases of straight line or single point
+ */
+ if (x1 == x2) {
+ if (y1 == y2) {
+ return (pixelColor(dst, x1, y1, color));
+ } else {
+ return (vlineColor(dst, x1, y1, y2, color));
+ }
+ }
+ if (y1 == y2) {
+ return (hlineColor(dst, x1, x2, y1, color));
+ }
+#endif
+
+ /*
+ * Calculate width&height
+ */
+ w = x2 - x1;
+ h = y2 - y1;
+
+ /*
+ * No alpha-blending required
+ */
+
+#if 0
+ /*
+ * Setup color
+ */
+ colorptr = (Uint8 *) & color;
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
+ color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
+ } else {
+ color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
+ }
+#endif
+
+ /*
+ * Lock surface
+ */
+ SDL_LockSurface(dst);
+
+ /*
+ * More variable setup
+ */
+ dx = w;
+ dy = h;
+ pixx = dst->format->BytesPerPixel;
+ pixy = dst->pitch;
+ pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
+ pixellast = pixel + pixx * dx + pixy * dy;
+ dx++;
+
+ /*
+ * Draw
+ */
+ switch (dst->format->BytesPerPixel) {
+ case 1:
+ for (; pixel <= pixellast; pixel += pixy) {
+ memset(pixel, (Uint8) color, dx);
+ }
+ break;
+ case 2:
+ pixy -= (pixx * dx);
+ for (; pixel <= pixellast; pixel += pixy) {
+ for (x = 0; x < dx; x++) {
+ *(Uint16*) pixel = color;
+ pixel += pixx;
+ }
+ }
+ break;
+ case 3:
+ pixy -= (pixx * dx);
+ for (; pixel <= pixellast; pixel += pixy) {
+ for (x = 0; x < dx; x++) {
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
+ pixel[0] = (color >> 16) & 0xff;
+ pixel[1] = (color >> 8) & 0xff;
+ pixel[2] = color & 0xff;
+ } else {
+ pixel[0] = color & 0xff;
+ pixel[1] = (color >> 8) & 0xff;
+ pixel[2] = (color >> 16) & 0xff;
+ }
+ pixel += pixx;
+ }
+ }
+ break;
+ default: /* case 4 */
+ pixy -= (pixx * dx);
+ for (; pixel <= pixellast; pixel += pixy) {
+ for (x = 0; x < dx; x++) {
+ *(Uint32 *) pixel = color;
+ pixel += pixx;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Unlock surface
+ */
+ SDL_UnlockSurface(dst);
+
+#endif
+}
+
+void raster_rect(SDL_Surface *s, int16_t x, int16_t y, int16_t w, int16_t h, uint32_t col)
+{
+ raster_rect_inline(s, x, y, w, h, col);
+}
+
+#define raster_rect_inline raster_rect
+
+
+/* raster :: pixel */
+
+#define MODIFIED_ALPHA_PIXEL_ROUTINE
+
+
+#define clip_xmin(surface) surface->clip_rect.x
+#define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
+#define clip_ymin(surface) surface->clip_rect.y
+#define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
+
+
+static void raster_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ if(x>=clip_xmin(surface) && x<=clip_xmax(surface) && y>=clip_ymin(surface) && y<=clip_ymax(surface)){
+ switch (surface->format->BytesPerPixel) {
+ case 1: { /* Assuming 8-bpp */
+ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+ }
+ break;
+
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+ }
+ break;
+
+ case 3: { /* Slow 24-bpp mode, usually not used */
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ /* Gack - slow, but endian correct */
+ *(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
+ *(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
+ *(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
+ *(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
+ }
+ break;
+
+ case 4: { /* Probably 32-bpp */
+ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+ }
+ break;
+ }
+ }
+}
+
+/* PutPixel routine with alpha blending, input color in destination format */
+
+/* New, faster routine - default blending pixel */
+
+static void raster_PutPixelAlpha(SDL_Surface * surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
+{
+ /* sdl-gfx */
+ Uint32 Rmask = surface->format->Rmask, Gmask =
+ surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
+ Uint32 R = 0, G = 0, B = 0, A = 0;
+
+ if (x >= clip_xmin(surface) && x <= clip_xmax(surface)
+ && y >= clip_ymin(surface) && y <= clip_ymax(surface)) {
+
+ switch (surface->format->BytesPerPixel) {
+ case 1:{ /* Assuming 8-bpp */
+ if (alpha == 255) {
+ *((Uint8 *) surface->pixels + y * surface->pitch + x) = color;
+ } else {
+ Uint8 *pixel = (Uint8 *) surface->pixels + y * surface->pitch + x;
+
+ Uint8 dR = surface->format->palette->colors[*pixel].r;
+ Uint8 dG = surface->format->palette->colors[*pixel].g;
+ Uint8 dB = surface->format->palette->colors[*pixel].b;
+ Uint8 sR = surface->format->palette->colors[color].r;
+ Uint8 sG = surface->format->palette->colors[color].g;
+ Uint8 sB = surface->format->palette->colors[color].b;
+
+ dR = dR + ((sR - dR) * alpha >> 8);
+ dG = dG + ((sG - dG) * alpha >> 8);
+ dB = dB + ((sB - dB) * alpha >> 8);
+
+ *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
+ }
+ }
+ break;
+
+ case 2:{ /* Probably 15-bpp or 16-bpp */
+ if (alpha == 255) {
+ *((Uint16 *) surface->pixels + y * surface->pitch / 2 + x) = color;
+ } else {
+ Uint16 *pixel = (Uint16 *) surface->pixels + y * surface->pitch / 2 + x;
+ Uint32 dc = *pixel;
+
+ R = ((dc & Rmask) + (((color & Rmask) - (dc & Rmask)) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (((color & Gmask) - (dc & Gmask)) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (((color & Bmask) - (dc & Bmask)) * alpha >> 8)) & Bmask;
+ if (Amask)
+ A = ((dc & Amask) + (((color & Amask) - (dc & Amask)) * alpha >> 8)) & Amask;
+
+ *pixel = R | G | B | A;
+ }
+ }
+ break;
+
+ case 3:{ /* Slow 24-bpp mode, usually not used */
+ Uint8 *pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
+ Uint8 rshift8 = surface->format->Rshift / 8;
+ Uint8 gshift8 = surface->format->Gshift / 8;
+ Uint8 bshift8 = surface->format->Bshift / 8;
+ Uint8 ashift8 = surface->format->Ashift / 8;
+
+
+ if (alpha == 255) {
+ *(pix + rshift8) = color >> surface->format->Rshift;
+ *(pix + gshift8) = color >> surface->format->Gshift;
+ *(pix + bshift8) = color >> surface->format->Bshift;
+ *(pix + ashift8) = color >> surface->format->Ashift;
+ } else {
+ Uint8 dR, dG, dB, dA = 0;
+ Uint8 sR, sG, sB, sA = 0;
+
+ pix = (Uint8 *) surface->pixels + y * surface->pitch + x * 3;
+
+ dR = *((pix) + rshift8);
+ dG = *((pix) + gshift8);
+ dB = *((pix) + bshift8);
+ dA = *((pix) + ashift8);
+
+ sR = (color >> surface->format->Rshift) & 0xff;
+ sG = (color >> surface->format->Gshift) & 0xff;
+ sB = (color >> surface->format->Bshift) & 0xff;
+ sA = (color >> surface->format->Ashift) & 0xff;
+
+ dR = dR + ((sR - dR) * alpha >> 8);
+ dG = dG + ((sG - dG) * alpha >> 8);
+ dB = dB + ((sB - dB) * alpha >> 8);
+ dA = dA + ((sA - dA) * alpha >> 8);
+
+ *((pix) + rshift8) = dR;
+ *((pix) + gshift8) = dG;
+ *((pix) + bshift8) = dB;
+ *((pix) + ashift8) = dA;
+ }
+ }
+ break;
+
+#ifdef ORIGINAL_ALPHA_PIXEL_ROUTINE
+
+ case 4:{ /* Probably :-) 32-bpp */
+ if (alpha == 255) {
+ *((Uint32 *) surface->pixels + y * surface->pitch / 4 + x) = color;
+ } else {
+ Uint32 Rshift, Gshift, Bshift, Ashift;
+ Uint32 *pixel = (Uint32 *) surface->pixels + y * surface->pitch / 4 + x;
+ Uint32 dc = *pixel;
+
+ Rshift = surface->format->Rshift;
+ Gshift = surface->format->Gshift;
+ Bshift = surface->format->Bshift;
+ Ashift = surface->format->Ashift;
+
+ R = ((dc & Rmask) + (((((color & Rmask) - (dc & Rmask)) >> Rshift) * alpha >> 8) << Rshift)) & Rmask;
+ G = ((dc & Gmask) + (((((color & Gmask) - (dc & Gmask)) >> Gshift) * alpha >> 8) << Gshift)) & Gmask;
+ B = ((dc & Bmask) + (((((color & Bmask) - (dc & Bmask)) >> Bshift) * alpha >> 8) << Bshift)) & Bmask;
+ if (Amask)
+ A = ((dc & Amask) + (((((color & Amask) - (dc & Amask)) >> Ashift) * alpha >> 8) << Ashift)) & Amask;
+
+ *pixel = R | G | B | A;
+ }
+ }
+ break;
+#endif
+
+#ifdef MODIFIED_ALPHA_PIXEL_ROUTINE
+
+ case 4:{ /* Probably :-) 32-bpp */
+ if (alpha == 255) {
+ *((Uint32 *) surface->pixels + y * surface->pitch / 4 + x) = color;
+ } else {
+ Uint32 Rshift, Gshift, Bshift, Ashift;
+ Uint32 *pixel = (Uint32 *) surface->pixels + y * surface->pitch / 4 + x;
+ Uint32 dc = *pixel;
+ Uint32 dR = (color & Rmask), dG = (color & Gmask), dB = (color & Bmask);
+ Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
+ Uint32 aTmp;
+
+ Rshift = surface->format->Rshift;
+ Gshift = surface->format->Gshift;
+ Bshift = surface->format->Bshift;
+ Ashift = surface->format->Ashift;
+
+ preMultR = (alpha * (dR>>Rshift));
+ preMultG = (alpha * (dG>>Gshift));
+ preMultB = (alpha * (dB>>Bshift));
+
+ surfaceAlpha = ((dc & Amask) >> Ashift);
+ aTmp = (255 - alpha);
+ if ((A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 ))) {
+ aTmp *= surfaceAlpha;
+ R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
+ G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
+ B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
+ }
+ *pixel = R | G | B | (A << Ashift & Amask);
+
+ }
+ }
+ break;
+#endif
+ }
+ }
+}
+
+
+/* FIXME: eliminate these 2 functions */
+
+static int raster_pixelColorNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color)
+{
+ int result = 0;
+
+#if 0
+ /*
+ * Setup color
+ */
+ alpha = color & 0x000000ff;
+ mcolor =
+ SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
+ (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
+#endif
+
+ /*
+ * Draw
+ */
+ raster_PutPixel(dst, x, y, color);
+
+ return (result);
+}
+
+
+/* Pixel - using alpha weight on color for AA-drawing - no locking */
+
+static int raster_pixelColorWeightNolock(SDL_Surface * dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight)
+{
+#if 0
+ Uint32 a;
+
+ /*
+ * Get alpha
+ */
+ a = (color & (Uint32) 0x000000ff);
+
+ /*
+ * Modify Alpha by weight
+ */
+ a = ((a * weight) >> 8);
+#endif
+
+ raster_PutPixelAlpha(dst, x, y, color, weight);
+
+ return 0;
+}
+
+
+/* raster :: line */
+
+
+
+static inline void raster_hline(SDL_Surface * dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color)
+{
+#if 1
+ SDL_Rect l;
+
+ /* sge */
+ if(x1>x2){Sint16 tmp=x1; x1=x2; x2=tmp;}
+
+ l.x=x1; l.y=y; l.w=x2-x1+1; l.h=1;
+
+ SDL_FillRect(dst, &l, color);
+
+#else
+ /* sdl_gfx */
+ Sint16 left, right, top, bottom;
+ Uint8 *pixel, *pixellast;
+ int dx;
+ int pixx, pixy;
+ Sint16 w;
+ Sint16 xtmp;
+ int result = -1;
+#if 0
+ int i;
+ union
+ {
+ double d;
+ uint16_t col[4];
+ } doub;
+
+ for(i = 0; i < 4; i++)
+ {
+ doub.col[i] = color;
+ }
+#endif
+
+ /*
+ * Check visibility of clipping rectangle
+ */
+ if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
+ return(0);
+ }
+
+ /*
+ * Swap x1, x2 if required to ensure x1<=x2
+ */
+ if (x1 > x2) {
+ xtmp = x1;
+ x1 = x2;
+ x2 = xtmp;
+ }
+
+ /*
+ * Get clipping boundary and
+ * check visibility of hline
+ */
+ left = dst->clip_rect.x;
+ if (x2<left) {
+ return(0);
+ }
+ right = dst->clip_rect.x + dst->clip_rect.w - 1;
+ if (x1>right) {
+ return(0);
+ }
+ top = dst->clip_rect.y;
+ bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
+ if ((y<top) || (y>bottom)) {
+ return (0);
+ }
+
+ /*
+ * Clip x
+ */
+ if (x1 < left) {
+ x1 = left;
+ }
+ if (x2 > right) {
+ x2 = right;
+ }
+
+ /*
+ * Calculate width
+ */
+ w = x2 - x1;
+
+#if 0
+ printf("raster_hline %d %d %d %d\n", x1, x2, y, w);
+#endif
+
+ /*
+ * Lock surface
+ */
+ if (SDL_MUSTLOCK(dst)) {
+ SDL_LockSurface(dst);
+ }
+
+ /*
+ * More variable setup
+ */
+ dx = w;
+ pixx = dst->format->BytesPerPixel;
+ pixy = dst->pitch;
+ pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
+
+ /*
+ * Draw
+ */
+ switch (dst->format->BytesPerPixel) {
+ case 1:
+ memset(pixel, color, dx);
+ break;
+ case 2:
+ pixellast = pixel + dx + dx;
+#if 0
+ for (; (pixel+3) <= pixellast; pixel += 4*pixx)
+ {
+ *(double *)pixel = doub.d;
+ }
+#endif
+ for (; pixel <= pixellast; pixel += pixx) {
+ *(Uint16 *) pixel = color;
+ }
+ break;
+ case 3:
+ pixellast = pixel + dx + dx + dx;
+ for (; pixel <= pixellast; pixel += pixx) {
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
+ pixel[0] = (color >> 16) & 0xff;
+ pixel[1] = (color >> 8) & 0xff;
+ pixel[2] = color & 0xff;
+ } else {
+ pixel[0] = color & 0xff;
+ pixel[1] = (color >> 8) & 0xff;
+ pixel[2] = (color >> 16) & 0xff;
+ }
+ }
+ break;
+ default: /* case 4 */
+ dx = dx + dx;
+ pixellast = pixel + dx + dx;
+ for (; pixel <= pixellast; pixel += pixx) {
+ *(Uint32 *) pixel = color;
+ }
+ break;
+ }
+
+ /*
+ * Unlock surface
+ */
+ if (SDL_MUSTLOCK(dst)) {
+ SDL_UnlockSurface(dst);
+ }
+
+ /*
+ * Set result code
+ */
+ result = 0;
+
+ return (result);
+#endif
+}
+
+static void raster_vline(SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
+{
+ SDL_Rect l;
+
+ if(y1>y2){Sint16 tmp=y1; y1=y2; y2=tmp;}
+
+ l.x=x; l.y=y1; l.w=1; l.h=y2-y1+1;
+
+ SDL_FillRect(dst, &l, color);
+}
+
+
+
+/* raster_line */
+#define CLIP_LEFT_EDGE 0x1
+#define CLIP_RIGHT_EDGE 0x2
+#define CLIP_BOTTOM_EDGE 0x4
+#define CLIP_TOP_EDGE 0x8
+#define CLIP_INSIDE(a) (!a)
+#define CLIP_REJECT(a,b) (a&b)
+#define CLIP_ACCEPT(a,b) (!(a|b))
+
+static int clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
+{
+ int code = 0;
+
+ if (x < left) {
+ code |= CLIP_LEFT_EDGE;
+ } else if (x > right) {
+ code |= CLIP_RIGHT_EDGE;
+ }
+ if (y < top) {
+ code |= CLIP_TOP_EDGE;
+ } else if (y > bottom) {
+ code |= CLIP_BOTTOM_EDGE;
+ }
+ return code;
+}
+
+static int clipLine(SDL_Surface * dst, Sint16 * x1, Sint16 * y1, Sint16 * x2, Sint16 * y2)
+{
+ Sint16 left, right, top, bottom;
+ int code1, code2;
+ int draw = 0;
+ Sint16 swaptmp;
+ float m;
+
+ /*
+ * Get clipping boundary
+ */
+ left = dst->clip_rect.x;
+ right = dst->clip_rect.x + dst->clip_rect.w - 1;
+ top = dst->clip_rect.y;
+ bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
+
+ while (1) {
+ code1 = clipEncode(*x1, *y1, left, top, right, bottom);
+ code2 = clipEncode(*x2, *y2, left, top, right, bottom);
+ if (CLIP_ACCEPT(code1, code2)) {
+ draw = 1;
+ break;
+ } else if (CLIP_REJECT(code1, code2))
+ break;
+ else {
+ if (CLIP_INSIDE(code1)) {
+ swaptmp = *x2;
+ *x2 = *x1;
+ *x1 = swaptmp;
+ swaptmp = *y2;
+ *y2 = *y1;
+ *y1 = swaptmp;
+ swaptmp = code2;
+ code2 = code1;
+ code1 = swaptmp;
+ }
+ if (*x2 != *x1) {
+ m = (*y2 - *y1) / (float) (*x2 - *x1);
+ } else {
+ m = 1.0f;
+ }
+ if (code1 & CLIP_LEFT_EDGE) {
+ *y1 += (Sint16) ((left - *x1) * m);
+ *x1 = left;
+ } else if (code1 & CLIP_RIGHT_EDGE) {
+ *y1 += (Sint16) ((right - *x1) * m);
+ *x1 = right;
+ } else if (code1 & CLIP_BOTTOM_EDGE) {
+ if (*x2 != *x1) {
+ *x1 += (Sint16) ((bottom - *y1) / m);
+ }
+ *y1 = bottom;
+ } else if (code1 & CLIP_TOP_EDGE) {
+ if (*x2 != *x1) {
+ *x1 += (Sint16) ((top - *y1) / m);
+ }
+ *y1 = top;
+ }
+ }
+ }
+
+ return draw;
+}
+
+
+void raster_line(SDL_Surface *dst, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t color)
+{
+ /* sdl-gfx */
+ int pixx, pixy;
+ int x, y;
+ int dx, dy;
+ int sx, sy;
+ int swaptmp;
+ Uint8 *pixel;
+
+ /*
+ * Clip line and test if we have to draw
+ */
+ if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
+ return;
+ }
+
+ /*
+ * Test for special cases of straight lines or single point
+ */
+ if (x1 == x2) {
+ if (y1 < y2) {
+ raster_vline(dst, x1, y1, y2, color);
+ return;
+ } else if (y1 > y2) {
+ raster_vline(dst, x1, y2, y1, color);
+ return;
+ } else {
+ raster_PutPixel(dst, x1, y1, color);
+ return;
+ }
+ }
+ if (y1 == y2) {
+ if (x1 < x2) {
+ raster_hline(dst, x1, x2, y1, color);
+ return;
+ } else if (x1 > x2) {
+ raster_hline(dst, x2, x1, y1, color);
+ return;
+ }
+ }
+
+
+ /*
+ * Variable setup
+ */
+ dx = x2 - x1;
+ dy = y2 - y1;
+ sx = (dx >= 0) ? 1 : -1;
+ sy = (dy >= 0) ? 1 : -1;
+
+ /* Lock surface */
+ if (SDL_MUSTLOCK(dst)) {
+ if (SDL_LockSurface(dst) < 0) {
+ return;
+ }
+ }
+
+ /*
+ * No alpha blending - use fast pixel routines
+ */
+
+#if 0
+ /*
+ * Setup color
+ */
+ colorptr = (Uint8 *) & color;
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
+ color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
+ } else {
+ color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
+ }
+#endif
+
+ /*
+ * More variable setup
+ */
+ dx = sx * dx + 1;
+ dy = sy * dy + 1;
+ pixx = dst->format->BytesPerPixel;
+ pixy = dst->pitch;
+ pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
+ pixx *= sx;
+ pixy *= sy;
+ if (dx < dy) {
+ swaptmp = dx;
+ dx = dy;
+ dy = swaptmp;
+ swaptmp = pixx;
+ pixx = pixy;
+ pixy = swaptmp;
+ }
+
+ /*
+ * Draw
+ */
+ x = 0;
+ y = 0;
+ switch (dst->format->BytesPerPixel) {
+ case 1:
+ for (; x < dx; x++, pixel += pixx) {
+ *pixel = color;
+ y += dy;
+ if (y >= dx) {
+ y -= dx;
+ pixel += pixy;
+ }
+ }
+ break;
+ case 2:
+ for (; x < dx; x++, pixel += pixx) {
+ *(Uint16 *) pixel = color;
+ y += dy;
+ if (y >= dx) {
+ y -= dx;
+ pixel += pixy;
+ }
+ }
+ break;
+ case 3:
+ for (; x < dx; x++, pixel += pixx) {
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
+ pixel[0] = (color >> 16) & 0xff;
+ pixel[1] = (color >> 8) & 0xff;
+ pixel[2] = color & 0xff;
+ } else {
+ pixel[0] = color & 0xff;
+ pixel[1] = (color >> 8) & 0xff;
+ pixel[2] = (color >> 16) & 0xff;
+ }
+ y += dy;
+ if (y >= dx) {
+ y -= dx;
+ pixel += pixy;
+ }
+ }
+ break;
+ default: /* case 4 */
+ for (; x < dx; x++, pixel += pixx) {
+ *(Uint32 *) pixel = color;
+ y += dy;
+ if (y >= dx) {
+ y -= dx;
+ pixel += pixy;
+ }
+ }
+ break;
+ }
+
+ /* Unlock surface */
+ if (SDL_MUSTLOCK(dst)) {
+ SDL_UnlockSurface(dst);
+ }
+
+ return;
+}
+
+
+#define AAlevels 256
+#define AAbits 8
+
+static void raster_aalineColorInt(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint)
+{
+ Sint32 xx0, yy0, xx1, yy1;
+ int result;
+ Uint32 intshift, erracc, erradj;
+ Uint32 erracctmp, wgt, wgtcompmask;
+ int dx, dy, tmp, xdir, y0p1, x0pxdir;
+
+ /*
+ * Check visibility of clipping rectangle
+ */
+ if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
+ return;
+ }
+
+ /*
+ * Clip line and test if we have to draw
+ */
+ if (!(clipLine(dst, &x1, &y1, &x2, &y2))) {
+ return;
+ }
+
+ /*
+ * Keep on working with 32bit numbers
+ */
+ xx0 = x1;
+ yy0 = y1;
+ xx1 = x2;
+ yy1 = y2;
+
+ /*
+ * Reorder points if required
+ */
+ if (yy0 > yy1) {
+ tmp = yy0;
+ yy0 = yy1;
+ yy1 = tmp;
+ tmp = xx0;
+ xx0 = xx1;
+ xx1 = tmp;
+ }
+
+ /*
+ * Calculate distance
+ */
+ dx = xx1 - xx0;
+ dy = yy1 - yy0;
+
+ /*
+ * Adjust for negative dx and set xdir
+ */
+ if (dx >= 0) {
+ xdir = 1;
+ } else {
+ xdir = -1;
+ dx = (-dx);
+ }
+
+ /*
+ * Check for special cases
+ */
+ if (dx == 0) {
+ /*
+ * Vertical line
+ */
+ raster_vline(dst, x1, y1, y2, color);
+ return;
+ } else if (dy == 0) {
+ /*
+ * Horizontal line
+ */
+ raster_hline(dst, x1, x2, y1, color);
+ return;
+ } else if (dx == dy) {
+ /*
+ * Diagonal line
+ */
+ raster_line(dst, x1, y1, x2, y2, color);
+ return;
+ }
+
+ /*
+ * Line is not horizontal, vertical or diagonal
+ */
+ result = 0;
+
+ /*
+ * Zero accumulator
+ */
+ erracc = 0;
+
+ /*
+ * # of bits by which to shift erracc to get intensity level
+ */
+ intshift = 32 - AAbits;
+ /*
+ * Mask used to flip all bits in an intensity weighting
+ */
+ wgtcompmask = AAlevels - 1;
+
+ /* Lock surface */
+ if (SDL_MUSTLOCK(dst)) {
+ if (SDL_LockSurface(dst) < 0) {
+ return;
+ }
+ }
+
+ /*
+ * Draw the initial pixel in the foreground color
+ */
+ raster_pixelColorNolock(dst, x1, y1, color);
+
+ /*
+ * x-major or y-major?
+ */
+ if (dy > dx) {
+
+ /*
+ * y-major. Calculate 16-bit fixed point fractional part of a pixel that
+ * X advances every time Y advances 1 pixel, truncating the result so that
+ * we won't overrun the endpoint along the X axis
+ */
+ /*
+ * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
+ */
+ erradj = ((dx << 16) / dy) << 16;
+
+ /*
+ * draw all pixels other than the first and last
+ */
+ x0pxdir = xx0 + xdir;
+ while (--dy) {
+ erracctmp = erracc;
+ erracc += erradj;
+ if (erracc <= erracctmp) {
+ /*
+ * rollover in error accumulator, x coord advances
+ */
+ xx0 = x0pxdir;
+ x0pxdir += xdir;
+ }
+ yy0++; /* y-major so always advance Y */
+
+ /*
+ * the AAbits most significant bits of erracc give us the intensity
+ * weighting for this pixel, and the complement of the weighting for
+ * the paired pixel.
+ */
+ wgt = (erracc >> intshift) & 255;
+ raster_pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
+ raster_pixelColorWeightNolock (dst, x0pxdir, yy0, color, wgt);
+ }
+
+ } else {
+
+ /*
+ * x-major line. Calculate 16-bit fixed-point fractional part of a pixel
+ * that Y advances each time X advances 1 pixel, truncating the result so
+ * that we won't overrun the endpoint along the X axis.
+ */
+ /*
+ * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
+ */
+ erradj = ((dy << 16) / dx) << 16;
+
+ /*
+ * draw all pixels other than the first and last
+ */
+ y0p1 = yy0 + 1;
+ while (--dx) {
+
+ erracctmp = erracc;
+ erracc += erradj;
+ if (erracc <= erracctmp) {
+ /*
+ * Accumulator turned over, advance y
+ */
+ yy0 = y0p1;
+ y0p1++;
+ }
+ xx0 += xdir; /* x-major so always advance X */
+ /*
+ * the AAbits most significant bits of erracc give us the intensity
+ * weighting for this pixel, and the complement of the weighting for
+ * the paired pixel.
+ */
+ wgt = (erracc >> intshift) & 255;
+ raster_pixelColorWeightNolock (dst, xx0, yy0, color, 255 - wgt);
+ raster_pixelColorWeightNolock (dst, xx0, y0p1, color, wgt);
+ }
+ }
+
+ /*
+ * Do we have to draw the endpoint
+ */
+ if (draw_endpoint) {
+ /*
+ * Draw final pixel, always exactly intersected by the line and doesn't
+ * need to be weighted.
+ */
+ raster_pixelColorNolock (dst, x2, y2, color);
+ }
+
+ /* Unlock surface */
+ if (SDL_MUSTLOCK(dst)) {
+ SDL_UnlockSurface(dst);
+ }
+}
+
+void raster_aaline(SDL_Surface *s, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t col)
+{
+ raster_aalineColorInt(s, x1, y1, x2, y2, col, 1);
+}
+
+
+
+/* raster :: circle */
+
+void raster_circle(SDL_Surface *dst, int16_t x, int16_t y, int16_t r, uint32_t color)
+{
+ /* sdl-gfx */
+ Sint16 left, right, top, bottom;
+ int result;
+ Sint16 x1, y1, x2, y2;
+ Sint16 cx = 0;
+ Sint16 cy = r;
+ Sint16 ocx = (Sint16) 0xffff;
+ Sint16 ocy = (Sint16) 0xffff;
+ Sint16 df = 1 - r;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * r + 5;
+ Sint16 xpcx, xmcx, xpcy, xmcy;
+ Sint16 ypcy, ymcy, ypcx, ymcx;
+
+ /*
+ * Check visibility of clipping rectangle
+ */
+ if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
+ return;
+ }
+
+ /*
+ * Sanity check radius
+ */
+ if (r < 0) {
+ return;
+ }
+
+ /*
+ * Special case for r=0 - draw a point
+ */
+ if (r == 0) {
+ return (raster_PutPixel(dst, x, y, color));
+ }
+
+ /*
+ * Get circle and clipping boundary and
+ * test if bounding box of circle is visible
+ */
+ x2 = x + r;
+ left = dst->clip_rect.x;
+ if (x2<left) {
+ return;
+ }
+ x1 = x - r;
+ right = dst->clip_rect.x + dst->clip_rect.w - 1;
+ if (x1>right) {
+ return;
+ }
+ y2 = y + r;
+ top = dst->clip_rect.y;
+ if (y2<top) {
+ return;
+ }
+ y1 = y - r;
+ bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
+ if (y1>bottom) {
+ return;
+ }
+
+ /*
+ * Draw
+ */
+ result = 0;
+ do {
+ xpcx = x + cx;
+ xmcx = x - cx;
+ xpcy = x + cy;
+ xmcy = x - cy;
+ if (ocy != cy) {
+ if (cy > 0) {
+ ypcy = y + cy;
+ ymcy = y - cy;
+ raster_hline(dst, xmcx, xpcx, ypcy, color);
+ raster_hline(dst, xmcx, xpcx, ymcy, color);
+// raster_rect_inline(dst, xmcx, ypcy, 2*cx, 1, color);
+// raster_rect_inline(dst, xmcx, ymcy, 2*cx, 1, color);
+
+ } else {
+ raster_hline(dst, xmcx, xpcx, y, color);
+// raster_rect_inline(dst, xmcx, y, 2*cx, 1, color);
+ }
+ ocy = cy;
+ }
+ if (ocx != cx) {
+ if (cx != cy) {
+ if (cx > 0) {
+ ypcx = y + cx;
+ ymcx = y - cx;
+ raster_hline(dst, xmcy, xpcy, ymcx, color);
+ raster_hline(dst, xmcy, xpcy, ypcx, color);
+ //raster_rect_inline(dst, xmcy, ymcx, 2*cy, 1, color);
+ //raster_rect_inline(dst, xmcy, ypcx, 2*cy, 1, color);
+ } else {
+ raster_hline(dst, xmcy, xpcy, y, color);
+ //raster_rect_inline(dst, xmcy, y, 2*cy, 1, color);
+ }
+ }
+ ocx = cx;
+ }
+ /*
+ * Update
+ */
+ if (df < 0) {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ } else {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ } while (cx <= cy);
+}
+
+
+/* FIXME: convert to fixed pt */
+static void raster_AAFilledEllipse(SDL_Surface *surface, Sint16 xc, Sint16 yc, Sint16 rx, Sint16 ry, Uint32 color)
+{
+ /* sge */
+ /* Sanity check */
+ if (rx < 1)
+ rx = 1;
+ if (ry < 1)
+ ry = 1;
+
+ int a2 = rx * rx;
+ int b2 = ry * ry;
+
+ int ds = 2 * a2;
+ int dt = 2 * b2;
+
+ int dxt = (int)(a2 / sqrt(a2 + b2));
+
+ int t = 0;
+ int s = -2 * a2 * ry;
+ int d = 0;
+
+ Sint16 x = xc;
+ Sint16 y = yc - ry;
+
+ Sint16 xs, ys, dyt;
+ float cp, is, ip, imax = 1.0;
+
+ /* Lock surface */
+ if ( SDL_MUSTLOCK(surface) )
+ if ( SDL_LockSurface(surface) < 0 )
+ return;
+
+ /* "End points" */
+ raster_PutPixel(surface, x, y, color);
+ raster_PutPixel(surface, 2*xc-x, y, color);
+
+ raster_PutPixel(surface, x, 2*yc-y, color);
+ raster_PutPixel(surface, 2*xc-x, 2*yc-y, color);
+
+ /* unlock surface */
+ if (SDL_MUSTLOCK(surface) )
+ SDL_UnlockSurface(surface);
+
+ raster_vline(surface, x, y+1, 2*yc-y-1, color);
+
+ int i;
+
+ for (i = 1; i <= dxt; i++)
+ {
+ x--;
+ d += t - b2;
+
+ if (d >= 0)
+ ys = y - 1;
+ else if ((d - s - a2) > 0)
+ {
+ if ((2 * d - s - a2) >= 0)
+ ys = y + 1;
+ else
+ {
+ ys = y;
+ y++;
+ d -= s + a2;
+ s += ds;
+ }
+ }
+ else
+ {
+ y++;
+ ys = y + 1;
+ d -= s + a2;
+ s += ds;
+ }
+
+ t -= dt;
+
+ /* Calculate alpha */
+ cp = (float) abs(d) / abs(s);
+ is = cp * imax;
+ ip = imax - is;
+
+
+ /* Lock surface */
+ if ( SDL_MUSTLOCK(surface) )
+ if ( SDL_LockSurface(surface) < 0 )
+ return;
+
+ /* Upper half */
+ raster_PutPixelAlpha(surface, x, y, color, (Uint8)(ip*255));
+ raster_PutPixelAlpha(surface, 2*xc-x, y, color, (Uint8)(ip*255));
+
+ raster_PutPixelAlpha(surface, x, ys, color, (Uint8)(is*255));
+ raster_PutPixelAlpha(surface, 2*xc-x, ys, color, (Uint8)(is*255));
+
+
+ /* Lower half */
+ raster_PutPixelAlpha(surface, x, 2*yc-y, color, (Uint8)(ip*255));
+ raster_PutPixelAlpha(surface, 2*xc-x, 2*yc-y, color, (Uint8)(ip*255));
+
+ raster_PutPixelAlpha(surface, x, 2*yc-ys, color, (Uint8)(is*255));
+ raster_PutPixelAlpha(surface, 2*xc-x, 2*yc-ys, color, (Uint8)(is*255));
+
+ /* unlock surface */
+ if (SDL_MUSTLOCK(surface) )
+ SDL_UnlockSurface(surface);
+
+
+ /* Fill */
+ raster_vline(surface, x, y+1, 2*yc-y-1, color);
+ raster_vline(surface, 2*xc-x, y+1, 2*yc-y-1, color);
+ raster_vline(surface, x, ys+1, 2*yc-ys-1, color);
+ raster_vline(surface, 2*xc-x, ys+1, 2*yc-ys-1, color);
+ }
+
+ dyt = abs(y - yc);
+
+ for (i = 1; i <= dyt; i++)
+ {
+ y++;
+ d -= s + a2;
+
+ if (d <= 0)
+ xs = x + 1;
+ else if ((d + t - b2) < 0)
+ {
+ if ((2 * d + t - b2) <= 0)
+ xs = x - 1;
+ else
+ {
+ xs = x;
+ x--;
+ d += t - b2;
+ t -= dt;
+ }
+ }
+ else
+ {
+ x--;
+ xs = x - 1;
+ d += t - b2;
+ t -= dt;
+ }
+
+ s += ds;
+
+ /* Calculate alpha */
+ cp = (float) abs(d) / abs(t);
+ is = cp * imax;
+ ip = imax - is;
+
+
+ /* Lock surface */
+ if ( SDL_MUSTLOCK(surface) )
+ if ( SDL_LockSurface(surface) < 0 )
+ return;
+
+ /* Upper half */
+ raster_PutPixelAlpha(surface, x, y, color, (Uint8)(ip*255));
+ raster_PutPixelAlpha(surface, 2*xc-x, y, color, (Uint8)(ip*255));
+
+ raster_PutPixelAlpha(surface, xs, y, color, (Uint8)(is*255));
+ raster_PutPixelAlpha(surface, 2*xc-xs, y, color, (Uint8)(is*255));
+
+
+ /* Lower half*/
+ raster_PutPixelAlpha(surface, x, 2*yc-y, color, (Uint8)(ip*255));
+ raster_PutPixelAlpha(surface, 2*xc-x, 2*yc-y, color, (Uint8)(ip*255));
+
+ raster_PutPixelAlpha(surface, xs, 2*yc-y, color, (Uint8)(is*255));
+ raster_PutPixelAlpha(surface, 2*xc-xs, 2*yc-y, color, (Uint8)(is*255));
+
+ /* unlock surface */
+ if (SDL_MUSTLOCK(surface) )
+ SDL_UnlockSurface(surface);
+
+ /* Fill */
+ raster_hline(surface, x+1, 2*xc-x-1, y, color);
+ raster_hline(surface, xs+1, 2*xc-xs-1, y, color);
+ raster_hline(surface, x+1, 2*xc-x-1, 2*yc-y, color);
+ raster_hline(surface, xs+1, 2*xc-xs-1, 2*yc-y, color);
+ }
+}
+
+void raster_aacircle(SDL_Surface *s, int16_t x, int16_t y, int16_t r, uint32_t col)
+{
+ raster_AAFilledEllipse(s, x, y, r, r, col);
+}
+
+#if 0
+void raster_aacircle(SDL_Surface *s, int16_t x, int16_t y, int16_t r, uint32_t col)
+{
+ /* sdl-gfx */
+ Sint16 left, right, top, bottom;
+ int result;
+ Sint16 x1, y1, x2, y2;
+ Sint16 cx = 0;
+ Sint16 cy = r;
+ Sint16 ocx = (Sint16) 0xffff;
+ Sint16 ocy = (Sint16) 0xffff;
+ Sint16 df = 1 - r;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * r + 5;
+ Sint16 xpcx, xmcx, xpcy, xmcy;
+ Sint16 ypcy, ymcy, ypcx, ymcx;
+
+ /*
+ * Check visibility of clipping rectangle
+ */
+ if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
+ return;
+ }
+
+ /*
+ * Sanity check radius
+ */
+ if (r < 0) {
+ return;
+ }
+
+#if 0
+ /*
+ * Special case for r=0 - draw a point
+ */
+ if (r == 0) {
+ return (pixelColor(dst, x, y, color));
+ }
+#endif
+
+ /*
+ * Get circle and clipping boundary and
+ * test if bounding box of circle is visible
+ */
+ x2 = x + r;
+ left = dst->clip_rect.x;
+ if (x2<left) {
+ return;
+ }
+ x1 = x - r;
+ right = dst->clip_rect.x + dst->clip_rect.w - 1;
+ if (x1>right) {
+ return;
+ }
+ y2 = y + r;
+ top = dst->clip_rect.y;
+ if (y2<top) {
+ return;
+ }
+ y1 = y - r;
+ bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
+ if (y1>bottom) {
+ return;
+ }
+
+ /*
+ * Draw
+ */
+ result = 0;
+ do {
+ xpcx = x + cx;
+ xmcx = x - cx;
+ xpcy = x + cy;
+ xmcy = x - cy;
+ if (ocy != cy) {
+ if (cy > 0) {
+ ypcy = y + cy;
+ ymcy = y - cy;
+ raster_hlineColor(dst, xmcx, xpcx, ypcy, color);
+ raster_hlineColor(dst, xmcx, xpcx, ymcy, color);
+// raster_rect_inline(dst, xmcx, ypcy, 2*cx, 1, color);
+// raster_rect_inline(dst, xmcx, ymcy, 2*cx, 1, color);
+
+ } else {
+ raster_hlineColor(dst, xmcx, xpcx, y, color);
+// raster_rect_inline(dst, xmcx, y, 2*cx, 1, color);
+ }
+ ocy = cy;
+ }
+ if (ocx != cx) {
+ if (cx != cy) {
+ if (cx > 0) {
+ ypcx = y + cx;
+ ymcx = y - cx;
+ raster_hlineColor(dst, xmcy, xpcy, ymcx, color);
+ raster_hlineColor(dst, xmcy, xpcy, ypcx, color);
+ //raster_rect_inline(dst, xmcy, ymcx, 2*cy, 1, color);
+ //raster_rect_inline(dst, xmcy, ypcx, 2*cy, 1, color);
+ } else {
+ raster_hlineColor(dst, xmcy, xpcy, y, color);
+ //raster_rect_inline(dst, xmcy, y, 2*cy, 1, color);
+ }
+ }
+ ocx = cx;
+ }
+ /*
+ * Update
+ */
+ if (df < 0) {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ } else {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ } while (cx <= cy);
+#if 0
+ /* sge */
+ Sint16 cx = 0;
+ Sint16 cy = r;
+ int draw=1;
+ Sint16 df = 1 - r;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * r + 5;
+
+#ifdef DEBUG
+ printf("raster_circle %d %d %d\n", x, y, r);
+#endif
+
+ if(r < 0)
+ {
+ return;
+ }
+
+ do {
+ if(draw)
+ {
+ raster_rect_inline(s, x-cx, y+cy, 2*cx, 1, col);
+ raster_rect_inline(s, x-cx, y-cy, 2*cx, 1, col);
+ draw=0;
+ }
+ if(cx!=cy)
+ {
+ if(cx)
+ {
+ raster_rect_inline(s, x-cy, y-cx, 2*cy, 1, col);
+ raster_rect_inline(s, x-cy, y+cx, 2*cy, 1, col);
+ }
+ else
+ {
+ raster_rect_inline(s, x-cy, y, 2*cy, 1, col);
+ }
+ }
+
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ draw=1;
+ }
+ cx++;
+ } while(cx <= cy);
+#endif
+}
+#endif
+
+
+
+/* raster :: poly */
+
+
+/* ---- Filled Polygon */
+
+/* Helper qsort callback for polygon drawing */
+
+static int gfxPrimitivesCompareInt(const void *a, const void *b)
+{
+ return (*(const int *) a) - (*(const int *) b);
+}
+
+
+/* Global vertex array to use if optional parameters are not given in polygon calls. */
+static int *gfxPrimitivesPolyIntsGlobal = NULL;
+static int gfxPrimitivesPolyAllocatedGlobal = 0;
+
+/* (Note: The last two parameters are optional; but required for multithreaded operation.) */
+
+static inline int raster_filledPolygonColorMT(SDL_Surface * dst, const Sint16 * vx, const Sint16 * vy, int n, Uint32 color, int **polyInts, int *polyAllocated)
+{
+ /* sdl-gfx */
+ int result;
+ int i;
+ int y, xa, xb;
+ int miny, maxy;
+ int x1, y1;
+ int x2, y2;
+ int ind1, ind2;
+ int ints;
+ int *gfxPrimitivesPolyInts = NULL;
+ int gfxPrimitivesPolyAllocated = 0;
+
+ /*
+ * Check visibility of clipping rectangle
+ */
+ if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
+ return(0);
+ }
+
+ /*
+ * Sanity check number of edges
+ */
+ if (n < 3) {
+ return -1;
+ }
+
+ /*
+ * Map polygon cache
+ */
+ if ((polyInts==NULL) || (polyAllocated==NULL)) {
+ /* Use global cache */
+ gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
+ gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
+ } else {
+ /* Use local cache */
+ gfxPrimitivesPolyInts = *polyInts;
+ gfxPrimitivesPolyAllocated = *polyAllocated;
+ }
+
+ /*
+ * Allocate temp array, only grow array
+ */
+ if (!gfxPrimitivesPolyAllocated) {
+ gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
+ gfxPrimitivesPolyAllocated = n;
+ } else {
+ if (gfxPrimitivesPolyAllocated < n) {
+ gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
+ gfxPrimitivesPolyAllocated = n;
+ }
+ }
+
+ /*
+ * Check temp array
+ */
+ if (gfxPrimitivesPolyInts==NULL) {
+ gfxPrimitivesPolyAllocated = 0;
+ }
+
+ /*
+ * Update cache variables
+ */
+ if ((polyInts==NULL) || (polyAllocated==NULL)) {
+ gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
+ gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
+ } else {
+ *polyInts = gfxPrimitivesPolyInts;
+ *polyAllocated = gfxPrimitivesPolyAllocated;
+ }
+
+ /*
+ * Check temp array again
+ */
+ if (gfxPrimitivesPolyInts==NULL) {
+ return(-1);
+ }
+
+ /*
+ * Determine Y maxima
+ */
+ miny = vy[0];
+ maxy = vy[0];
+ for (i = 1; (i < n); i++) {
+ if (vy[i] < miny) {
+ miny = vy[i];
+ } else if (vy[i] > maxy) {
+ maxy = vy[i];
+ }
+ }
+
+ /*
+ * Draw, scanning y
+ */
+ result = 0;
+ for (y = miny; (y <= maxy); y++) {
+ ints = 0;
+ for (i = 0; (i < n); i++) {
+ if (!i) {
+ ind1 = n - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ y1 = vy[ind1];
+ y2 = vy[ind2];
+ if (y1 < y2) {
+ x1 = vx[ind1];
+ x2 = vx[ind2];
+ } else if (y1 > y2) {
+ y2 = vy[ind1];
+ y1 = vy[ind2];
+ x2 = vx[ind1];
+ x1 = vx[ind2];
+ } else {
+ continue;
+ }
+ if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
+ gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
+ }
+ }
+
+ qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
+
+ for (i = 0; (i < ints); i += 2) {
+ xa = gfxPrimitivesPolyInts[i] + 1;
+ xa = (xa >> 16) + ((xa & 32768) >> 15);
+ xb = gfxPrimitivesPolyInts[i+1] - 1;
+ xb = (xb >> 16) + ((xb & 32768) >> 15);
+ raster_hline(dst, xa, xb, y, color);
+// raster_rect_inline(dst, xa, y, xb - xa, 1, color);
+ }
+ }
+
+ return (result);
+}
+
+void raster_polygon(SDL_Surface *s, int16_t n, int16_t *vx, int16_t *vy, uint32_t col)
+{
+ raster_filledPolygonColorMT(s, vx, vy, n, col, NULL, NULL);
+}
+
+
+void raster_aapolygon(SDL_Surface *dst, int16_t n, int16_t *vx, int16_t *vy, uint32_t color)
+{
+ /* sdl-gfx + sge w/ rphlx changes: basically, draw aaline border,
+ then fill.
+
+ the output is not perfect yet but usually looks better than aliasing
+ */
+ int result;
+ int i;
+ int y, xa, xb;
+ int miny, maxy;
+ int x1, y1;
+ int x2, y2;
+ int ind1, ind2;
+ int ints;
+ int *gfxPrimitivesPolyInts = NULL;
+ int gfxPrimitivesPolyAllocated = 0;
+ const Sint16 *px1, *py1, *px2, *py2;
+ int **polyInts;
+ int *polyAllocated;
+
+ polyInts = NULL;
+ polyAllocated = NULL;
+
+ /*
+ * Check visibility of clipping rectangle
+ */
+ if ((dst->clip_rect.w==0) || (dst->clip_rect.h==0)) {
+ return;
+ }
+
+ /*
+ * Sanity check number of edges
+ */
+ if (n < 3) {
+ return;
+ }
+
+
+ /*
+ * Pointer setup
+ */
+ px1 = px2 = vx;
+ py1 = py2 = vy;
+ px2++;
+ py2++;
+
+ /*
+ * Draw
+ */
+ result = 0;
+ for (i = 1; i < n; i++) {
+ raster_aalineColorInt(dst, *px1, *py1, *px2, *py2, color, 0);
+ px1 = px2;
+ py1 = py2;
+ px2++;
+ py2++;
+ }
+ raster_aalineColorInt(dst, *px1, *py1, *vx, *vy, color, 0);
+
+ /*
+ * Map polygon cache
+ */
+ if ((polyInts==NULL) || (polyAllocated==NULL)) {
+ /* Use global cache */
+ gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
+ gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
+ } else {
+ /* Use local cache */
+ gfxPrimitivesPolyInts = *polyInts;
+ gfxPrimitivesPolyAllocated = *polyAllocated;
+ }
+
+ /*
+ * Allocate temp array, only grow array
+ */
+ if (!gfxPrimitivesPolyAllocated) {
+ gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
+ gfxPrimitivesPolyAllocated = n;
+ } else {
+ if (gfxPrimitivesPolyAllocated < n) {
+ gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
+ gfxPrimitivesPolyAllocated = n;
+ }
+ }
+
+ /*
+ * Check temp array
+ */
+ if (gfxPrimitivesPolyInts==NULL) {
+ gfxPrimitivesPolyAllocated = 0;
+ }
+
+ /*
+ * Update cache variables
+ */
+ if ((polyInts==NULL) || (polyAllocated==NULL)) {
+ gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
+ gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
+ } else {
+ *polyInts = gfxPrimitivesPolyInts;
+ *polyAllocated = gfxPrimitivesPolyAllocated;
+ }
+
+ /*
+ * Check temp array again
+ */
+ if (gfxPrimitivesPolyInts==NULL) {
+ return;
+ }
+
+ /*
+ * Determine Y maxima
+ */
+ miny = vy[0];
+ maxy = vy[0];
+ for (i = 1; (i < n); i++) {
+ if (vy[i] < miny) {
+ miny = vy[i];
+ } else if (vy[i] > maxy) {
+ maxy = vy[i];
+ }
+ }
+
+ /*
+ * Draw, scanning y
+ */
+ result = 0;
+ for (y = miny; (y <= maxy); y++) {
+ ints = 0;
+ for (i = 0; (i < n); i++) {
+ if (!i) {
+ ind1 = n - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ y1 = vy[ind1];
+ y2 = vy[ind2];
+ if (y1 < y2) {
+ x1 = vx[ind1];
+ x2 = vx[ind2];
+ } else if (y1 > y2) {
+ y2 = vy[ind1];
+ y1 = vy[ind2];
+ x2 = vx[ind1];
+ x1 = vx[ind2];
+ } else {
+ continue;
+ }
+ if ( ((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2)) ) {
+ gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
+ }
+ }
+
+ qsort(gfxPrimitivesPolyInts, ints, sizeof(int), gfxPrimitivesCompareInt);
+
+// o = p = -1;
+ for (i = 0; (i < ints); i +=2) {
+#if 0
+ xa = gfxPrimitivesPolyInts[i] + 1;
+ xa = (xa >> 16) + ((xa & 32768) >> 15);
+ xb = gfxPrimitivesPolyInts[i+1] - 1;
+ xb = (xb >> 16) + ((xb & 32768) >> 15);
+#else
+ xa = (gfxPrimitivesPolyInts[i] >> 16);
+ xb = (gfxPrimitivesPolyInts[i+1] >> 16);
+#endif
+
+#if 0
+ if(o < 0)
+ {
+ o = xa+1;
+ }
+ else if(p < 0)
+ {
+ p = xa;
+ }
+
+ if( (o >= 0) && (p >= 0))
+ {
+ if(p-o < 0)
+ {
+ o = p = -1;
+ continue;
+ }
+
+ raster_hlineColor(dst, o, p, y, color);
+
+ o = p = -1;
+ }
+#else
+
+ raster_hline(dst, xa+1, xb, y, color);
+#endif
+
+// raster_rect_inline(dst, xa, y, xb - xa, 1, color);
+ }
+ }
+}
+
diff --git a/graphics/sdl/raster.h b/graphics/sdl/raster.h
new file mode 100644
index 00000000..8f50b271
--- /dev/null
+++ b/graphics/sdl/raster.h
@@ -0,0 +1,25 @@
+/* raster.h -- line/rect/circle/poly rasterization
+
+ copyright (c) 2008 bryan rittmeyer <bryanr@bryanr.org>
+
+ license: LGPLv2
+*/
+
+#ifndef __RASTER_H
+#define __RASTER_H
+
+#include <stdint.h>
+#include <SDL/SDL.h>
+
+void raster_rect(SDL_Surface *s, int16_t x, int16_t y, int16_t w, int16_t h, uint32_t col);
+
+void raster_line(SDL_Surface *s, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t col);
+void raster_circle(SDL_Surface *s, int16_t x, int16_t y, int16_t r, uint32_t col);
+void raster_polygon(SDL_Surface *s, int16_t n, int16_t *vx, int16_t *vy, uint32_t col);
+
+void raster_aaline(SDL_Surface *s, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t col);
+void raster_aacircle(SDL_Surface *s, int16_t x, int16_t y, int16_t r, uint32_t col);
+void raster_aapolygon(SDL_Surface *s, int16_t n, int16_t *vx, int16_t *vy, uint32_t col);
+
+#endif /* __RASTER_H */
+
diff --git a/graphics/win32/Makefile.am b/graphics/win32/Makefile.am
new file mode 100644
index 00000000..a6fb52f9
--- /dev/null
+++ b/graphics/win32/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=graphics_win32
+if PLUGINS
+modulegraphics_LTLIBRARIES = libgraphics_win32.la
+else
+noinst_LTLIBRARIES = libgraphics_win32.la
+endif
+libgraphics_win32_la_SOURCES = graphics_win32.c xpm2bmp.c
+libgraphics_win32_la_LDFLAGS = -module -avoid-version
diff --git a/graphics/win32/graphics_win32.c b/graphics/win32/graphics_win32.c
new file mode 100644
index 00000000..b740b8d8
--- /dev/null
+++ b/graphics/win32/graphics_win32.c
@@ -0,0 +1,1074 @@
+#include <windows.h>
+#include <wingdi.h>
+#include <glib.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "debug.h"
+#include "point.h"
+#include "graphics.h"
+#include "color.h"
+#include "callback.h"
+#include "plugin.h"
+#include "item.h"
+#include "window.h"
+#include "graphics_win32.h"
+#include "xpm2bmp.h"
+#include "support/win32/ConvertUTF.h"
+
+struct graphics_priv {
+ struct navit *nav;
+ struct window window;
+ struct point p;
+ int width;
+ int height;
+ int library_init;
+ int visible;
+ HANDLE wnd_parent_handle;
+ HANDLE wnd_handle;
+ COLORREF bg_color;
+ struct callback_list *cbl;
+ enum draw_mode_num mode;
+};
+
+static HWND g_hwnd;
+
+#ifndef GET_WHEEL_DELTA_WPARAM
+ #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam))
+#endif
+
+
+static GHashTable *image_cache_hash = NULL;
+
+
+HFONT EzCreateFont (HDC hdc, TCHAR * szFaceName, int iDeciPtHeight,
+ int iDeciPtWidth, int iAttributes, BOOL fLogRes) ;
+
+#define EZ_ATTR_BOLD 1
+#define EZ_ATTR_ITALIC 2
+#define EZ_ATTR_UNDERLINE 4
+#define EZ_ATTR_STRIKEOUT 8
+
+HFONT EzCreateFont (HDC hdc, TCHAR * szFaceName, int iDeciPtHeight,
+ int iDeciPtWidth, int iAttributes, BOOL fLogRes)
+{
+ FLOAT cxDpi, cyDpi ;
+ HFONT hFont ;
+ LOGFONT lf ;
+ POINT pt ;
+ TEXTMETRIC tm ;
+
+ SaveDC (hdc) ;
+
+#ifndef HAVE_API_WIN32_CE
+ SetGraphicsMode (hdc, GM_ADVANCED) ;
+ ModifyWorldTransform (hdc, NULL, MWT_IDENTITY) ;
+#endif
+ SetViewportOrgEx (hdc, 0, 0, NULL) ;
+#ifndef HAVE_API_WIN32_CE
+ SetWindowOrgEx (hdc, 0, 0, NULL) ;
+#endif
+
+ if (fLogRes)
+ {
+ cxDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSX) ;
+ cyDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSY) ;
+ }
+ else
+ {
+ cxDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, HORZRES) /
+ GetDeviceCaps (hdc, HORZSIZE)) ;
+
+ cyDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, VERTRES) /
+ GetDeviceCaps (hdc, VERTSIZE)) ;
+ }
+
+ pt.x = (int) (iDeciPtWidth * cxDpi / 72) ;
+ pt.y = (int) (iDeciPtHeight * cyDpi / 72) ;
+
+#ifndef HAVE_API_WIN32_CE
+ DPtoLP (hdc, &pt, 1) ;
+#endif
+ lf.lfHeight = - (int) (fabs (pt.y) / 10.0 + 0.5) ;
+ lf.lfWidth = 0 ;
+ lf.lfEscapement = 0 ;
+ lf.lfOrientation = 0 ;
+ lf.lfWeight = iAttributes & EZ_ATTR_BOLD ? 700 : 0 ;
+ lf.lfItalic = iAttributes & EZ_ATTR_ITALIC ? 1 : 0 ;
+ lf.lfUnderline = iAttributes & EZ_ATTR_UNDERLINE ? 1 : 0 ;
+ lf.lfStrikeOut = iAttributes & EZ_ATTR_STRIKEOUT ? 1 : 0 ;
+ lf.lfCharSet = DEFAULT_CHARSET ;
+ lf.lfOutPrecision = 0 ;
+ lf.lfClipPrecision = 0 ;
+ lf.lfQuality = 0 ;
+ lf.lfPitchAndFamily = 0 ;
+
+ lstrcpy (lf.lfFaceName, szFaceName) ;
+
+ hFont = CreateFontIndirect (&lf) ;
+
+ if (iDeciPtWidth != 0)
+ {
+ hFont = (HFONT) SelectObject (hdc, hFont) ;
+
+ GetTextMetrics (hdc, &tm) ;
+
+ DeleteObject (SelectObject (hdc, hFont)) ;
+
+ lf.lfWidth = (int) (tm.tmAveCharWidth *
+ fabs (pt.x) / fabs (pt.y) + 0.5) ;
+
+ hFont = CreateFontIndirect (&lf) ;
+ }
+
+ RestoreDC (hdc, -1) ;
+ return hFont ;
+}
+
+struct graphics_image_priv {
+ PXPM2BMP pxpm;
+};
+
+
+static void ErrorExit(LPTSTR lpszFunction)
+{
+ // Retrieve the system error message for the last-error code
+
+ LPVOID lpMsgBuf;
+ LPVOID lpDisplayBuf;
+ DWORD dw = GetLastError();
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
+ wprintf((LPTSTR)lpDisplayBuf, TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf);
+
+ dbg(0, "%s failed with error %d: %s", lpszFunction, dw, lpMsgBuf);
+ MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
+
+ LocalFree(lpMsgBuf);
+ LocalFree(lpDisplayBuf);
+ ExitProcess(dw);
+}
+
+
+
+struct graphics_gc_priv {
+ HWND hwnd;
+ int line_width;
+ COLORREF fg_color;
+ COLORREF bg_color;
+ struct graphics_priv *gr;
+};
+
+
+//struct graphics_priv *g_gra;
+
+static HDC hMemDC;
+static HBITMAP hBitmap;
+static HBITMAP hOldBitmap;
+
+// Fills the region 'rgn' in graded colours
+static void MakeMemoryDC(HANDLE hWnd, HDC hdc )
+{
+ if ( hMemDC )
+ {
+ if ( hOldBitmap )
+ {
+ SelectObject( hMemDC, hOldBitmap );
+ DeleteObject( hBitmap );
+ hBitmap = NULL;
+ hOldBitmap = NULL;
+ }
+ }
+
+ // Creates memory DC
+ hMemDC = CreateCompatibleDC(hdc);
+ if ( hMemDC )
+ {
+ RECT rectRgn;
+ GetClientRect( hWnd, &rectRgn );
+
+ int Width = rectRgn.right - rectRgn.left;
+ int Height = rectRgn.bottom - rectRgn.top;
+ dbg(0, "resize memDC to: %d %d \n", Width, Height );
+
+ hBitmap = CreateCompatibleBitmap(hdc, Width, Height );
+
+ if ( hBitmap )
+ {
+ hOldBitmap = (HBITMAP) SelectObject( hMemDC, hBitmap);
+ }
+ }
+}
+
+static void HandleButtonClick( struct graphics_priv *gra_priv, int updown, int button, long lParam )
+{
+ POINTS p = MAKEPOINTS(lParam);
+ struct point pt;
+ pt.x = p.x;
+ pt.y = p.y;
+ callback_list_call_attr_3(gra_priv->cbl, attr_button, (void *)updown, (void *)button, (void *)&pt);
+}
+
+static LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+
+//if ( Message != 15 )
+//printf( "CHILD %d %d %d \n", Message, wParam, lParam );
+
+ struct graphics_priv* gra_priv = (struct graphics_priv*)GetWindowLongPtr( hwnd , DWLP_USER );
+
+ switch(Message)
+ {
+ case WM_CREATE:
+ {
+ HDC hdc;
+ hdc = GetDC( hwnd );
+ MakeMemoryDC(hwnd, hdc );
+ ReleaseDC( hwnd, hdc );
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case WM_USER + 1:
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ break;
+ case WM_USER+1:
+ if ( gra_priv )
+ {
+ RECT rc ;
+ HDC hdc;
+
+ GetClientRect( hwnd, &rc );
+ gra_priv->width = rc.right;
+ gra_priv->height = rc.bottom;
+
+ hdc = GetDC( hwnd );
+ MakeMemoryDC(hwnd, hdc );
+ ReleaseDC( hwnd, hdc );
+ callback_list_call_attr_2(gra_priv->cbl, attr_resize, (void *)gra_priv->width, (void *)gra_priv->height);
+ }
+ break;
+ case WM_USER+2:
+ {
+ struct callback_list *cbl = wParam;
+#ifdef HAVE_API_WIN32_CE
+ /* FIXME: Reset the idle timer need a better place */
+ SystemIdleTimerReset();
+#endif
+ callback_list_call_0(cbl);
+ }
+ break;
+
+ case WM_SIZE:
+ /*
+ if ( gra_priv )
+ {
+ //graphics = GetWindowLong( hwnd, DWL_USER, 0 );
+
+
+ {
+ HDC hdc;
+ hdc = GetDC( hwnd );
+ MakeMemoryDC(hwnd, hdc );
+ ReleaseDC( hwnd, hdc );
+ }
+ (*gra_priv->resize_callback)(gra_priv->resize_callback_data, gra_priv->width, gra_priv->height);
+
+
+ }
+ */
+ if ( gra_priv )
+ {
+ gra_priv->width = LOWORD( lParam );
+ gra_priv->height = HIWORD( lParam );
+ dbg(0, "resize gfx to: %d %d \n", gra_priv->width, gra_priv->height );
+ }
+ break;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ //exit( 0 );
+ break;
+ case WM_PAINT:
+ if ( gra_priv )
+ {
+ PAINTSTRUCT ps = { 0 };
+ HDC hdc = BeginPaint(hwnd, &ps);
+ if ( hMemDC )
+ {
+ BitBlt( hdc, 0, 0, gra_priv->width , gra_priv->height, hMemDC, 0, 0, SRCCOPY );
+ }
+ EndPaint(hwnd, &ps);
+ }
+ break;
+ case WM_MOUSEMOVE:
+ {
+ POINTS p = MAKEPOINTS(lParam);
+ struct point pt;
+ pt.x = p.x;
+ pt.y = p.y;
+
+ //dbg(1, "WM_MOUSEMOVE: %d %d \n", p.x, p.y );
+ callback_list_call_attr_1(gra_priv->cbl, attr_motion, (void *)&pt);
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ {
+ dbg(1, "LBUTTONDOWN\n");
+ HandleButtonClick( gra_priv, 1, 1, lParam);
+ }
+ break;
+ case WM_LBUTTONUP:
+ {
+ dbg(1, "LBUTTONUP\n");
+ HandleButtonClick( gra_priv, 0, 1, lParam);
+ }
+ break;
+ case WM_RBUTTONDOWN:
+ HandleButtonClick( gra_priv, 1, 3,lParam );
+ break;
+ case WM_RBUTTONUP:
+ HandleButtonClick( gra_priv, 0, 3,lParam );
+ break;
+ case WM_LBUTTONDBLCLK:
+ dbg(1, "LBUTTONDBLCLK\n");
+ HandleButtonClick( gra_priv, 1, 6,lParam );
+ break;
+ default:
+ return DefWindowProc(hwnd, Message, wParam, lParam);
+ }
+ return 0;
+}
+
+
+static const wchar_t g_szClassName[] = {'N','A','V','G','R','A','\0'};
+
+static HANDLE CreateGraphicsWindows( struct graphics_priv* gr )
+{
+#ifdef HAVE_API_WIN32_CE
+ WNDCLASS wc;
+#else
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.hIconSm = NULL;
+#endif
+ HWND hwnd;
+ RECT rcParent;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
+ wc.lpfnWndProc = WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 64;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = g_szClassName;
+
+ GetClientRect( gr->wnd_parent_handle,&rcParent);
+
+#ifdef HAVE_API_WIN32_CE
+ if(!RegisterClass(&wc))
+#else
+ if(!RegisterClassEx(&wc))
+#endif
+ {
+ ErrorExit( TEXT("Window Registration Failed!") );
+ return NULL;
+ }
+
+ gr->width = rcParent.right - rcParent.left;
+ gr->height = rcParent.bottom - rcParent.top;
+ callback_list_call_attr_2(gr->cbl, attr_resize, (void *)gr->width, (void *)gr->height);
+
+ g_hwnd = hwnd = CreateWindow(g_szClassName,
+ TEXT(""),
+#ifdef HAVE_API_WIN32_CE
+ WS_VISIBLE,
+#elif 1
+ WS_CHILD,
+#else
+ WS_OVERLAPPEDWINDOW,
+#endif
+ 0,
+ 0,
+ gr->width,
+ gr->height,
+#if 1
+ gr->wnd_parent_handle,
+#else
+ NULL,
+#endif
+#if 1
+ (HMENU)ID_CHILD_GFX,
+#else
+ NULL,
+#endif
+ GetModuleHandle(NULL),
+ NULL);
+
+ if(hwnd == NULL)
+ {
+ ErrorExit( TEXT("Window Creation Failed!") );
+ return NULL;
+ }
+ gr->wnd_handle = hwnd;
+
+ SetWindowLongPtr( hwnd , DWLP_USER, gr );
+
+ ShowWindow( hwnd, TRUE );
+ UpdateWindow( hwnd );
+
+
+ PostMessage( gr->wnd_parent_handle, WM_USER + 1, 0, 0 );
+
+ return hwnd;
+}
+
+
+
+static void graphics_destroy(struct graphics_priv *gr)
+{
+ g_free( gr );
+}
+
+
+static void gc_destroy(struct graphics_gc_priv *gc)
+{
+ g_free( gc );
+}
+
+static void gc_set_linewidth(struct graphics_gc_priv *gc, int w)
+{
+ gc->line_width = w;
+}
+
+static void gc_set_dashes(struct graphics_gc_priv *gc, int width, int offset, unsigned char dash_list[], int n)
+{
+// gdk_gc_set_dashes(gc->gc, 0, (gint8 *)dash_list, n);
+// gdk_gc_set_line_attributes(gc->gc, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND);
+}
+
+
+
+static void gc_set_color(struct graphics_gc_priv *gc, struct color *c, int fg)
+{
+
+ gc->fg_color = RGB( c->r, c->g, c->b );
+}
+
+static void gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->fg_color = RGB( c->r, c->g, c->b );
+}
+
+static void gc_set_background(struct graphics_gc_priv *gc, struct color *c)
+{
+ gc->bg_color = RGB( c->r, c->g, c->b );
+ if ( hMemDC )
+ SetBkColor( hMemDC, gc->bg_color );
+
+}
+
+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->hwnd = gr->wnd_handle;
+ gc->line_width = 1;
+ gc->fg_color = RGB( 0,0,0 );
+ gc->bg_color = RGB( 255,255,255 );
+ return gc;
+}
+
+
+static void draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+ int i;
+ HPEN holdpen;
+ HPEN hpen;
+
+ hpen = CreatePen( PS_SOLID, gc->line_width, gc->fg_color );
+ holdpen = SelectObject( hMemDC, hpen );
+
+ SetBkColor( hMemDC, gc->bg_color );
+
+ int first = 1;
+ for ( i = 0; i< count; i++ )
+ {
+ if ( first )
+ {
+ first = 0;
+ MoveToEx( hMemDC, p[0].x, p[0].y, NULL );
+ }
+ else
+ {
+ LineTo( hMemDC, p[i].x, p[i].y );
+ }
+ }
+
+ SelectObject( hMemDC, holdpen );
+ DeleteObject( hpen );
+}
+
+static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
+{
+
+ //if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+ {
+ int i;
+ POINT points[ count ];
+ for ( i=0;i< count; i++ )
+ {
+ points[i].x = p[i].x;
+ points[i].y = p[i].y;
+ }
+ HPEN hpen;
+ HBRUSH holdbrush;
+ HBRUSH hbrush;
+
+ SetBkColor( hMemDC, gc->bg_color );
+
+ hpen = CreatePen( PS_NULL, gc->line_width, gc->fg_color );
+ SelectObject( hMemDC, hpen );
+ hbrush = CreateSolidBrush( gc->fg_color );
+ holdbrush = SelectObject( hMemDC, hbrush );
+
+ Polygon( hMemDC, points,count );
+
+ SelectObject( hMemDC, holdbrush );
+ DeleteObject( hbrush );
+ DeleteObject( hbrush );
+ }
+}
+
+
+static void draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
+{
+// gdk_draw_rectangle(gr->drawable, gc->gc, TRUE, p->x, p->y, w, h);
+}
+
+static void draw_circle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int r)
+{
+ HDC dc = hMemDC;
+
+ HPEN holdpen;
+ HPEN hpen;
+
+ hpen = CreatePen( PS_SOLID, gc->line_width, gc->fg_color );
+ holdpen = SelectObject( dc, hpen );
+
+ SetBkColor( hMemDC, gc->bg_color );
+
+ Ellipse( dc, p->x - r, p->y -r, p->x + r, p->y + r );
+
+ SelectObject( dc, holdpen );
+ DeleteObject( hpen );
+
+// if (gr->mode == draw_mode_begin || gr->mode == draw_mode_end)
+// gdk_draw_arc(gr->drawable, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
+// if (gr->mode == draw_mode_end || gr->mode == draw_mode_cursor)
+// gdk_draw_arc(gr->widget->window, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360);
+}
+
+
+
+static void draw_restore(struct graphics_priv *gr, struct point *p, int w, int h)
+{
+ InvalidateRect( gr->wnd_handle, NULL, FALSE );
+}
+
+static void draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
+{
+ // printf( "set draw_mode to %d\n", (int)mode );
+
+ if ( mode == draw_mode_begin )
+ {
+ if ( gr->wnd_handle == NULL )
+ {
+ CreateGraphicsWindows( gr );
+ }
+ if ( gr->mode != draw_mode_begin )
+ {
+ if ( hMemDC )
+ {
+ RECT rcClient;
+ HBRUSH bgBrush = CreateSolidBrush( gr->bg_color );
+ GetClientRect( gr->wnd_handle, &rcClient );
+ FillRect( hMemDC, &rcClient, bgBrush );
+ DeleteObject( bgBrush );
+ }
+ }
+ }
+
+ // force paint
+ if (mode == draw_mode_end && gr->mode == draw_mode_begin)
+ {
+ InvalidateRect( gr->wnd_handle, NULL, FALSE );
+ }
+
+ gr->mode=mode;
+
+}
+
+
+static void * get_data(struct graphics_priv *this_, char *type)
+{
+ if ( strcmp( "wnd_parent_handle_ptr", type ) == 0 ) {
+ return &( this_->wnd_parent_handle );
+ }
+ if ( strcmp( "START_CLIENT", type ) == 0 ) {
+ CreateGraphicsWindows( this_ );
+ return NULL;
+ }
+ if (!strcmp(type, "window")) {
+#ifdef HAVE_API_WIN32_CE
+ WNDCLASS wc;
+#else
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.hIconSm = NULL;
+#endif
+ HWND hwnd;
+ RECT rcParent;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
+ wc.lpfnWndProc = WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 64;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = g_szClassName;
+
+ GetClientRect( this_->wnd_parent_handle,&rcParent);
+
+#ifdef HAVE_API_WIN32_CE
+ if(!RegisterClass(&wc))
+#else
+ if(!RegisterClassEx(&wc))
+#endif
+ {
+ ErrorExit( TEXT("Window Registration Failed!") );
+ return NULL;
+ }
+
+ callback_list_call_attr_2(this_->cbl, attr_resize, (void *)this_->width, (void *)this_->height);
+
+ g_hwnd = hwnd = CreateWindow(g_szClassName,
+ TEXT(""),
+#ifdef HAVE_API_WIN32_CE
+ WS_VISIBLE,
+#else
+ WS_OVERLAPPEDWINDOW,
+#endif
+ 0,
+ 0,
+ this_->width,
+ this_->height,
+ this_->wnd_parent_handle,
+ NULL,
+ GetModuleHandle(NULL),
+ NULL);
+
+ if(hwnd == NULL)
+ {
+ ErrorExit( TEXT("Window Creation Failed!") );
+ return NULL;
+ }
+ this_->wnd_handle = hwnd;
+
+ SetWindowLongPtr( hwnd , DWLP_USER, this_ );
+
+ ShowWindow( hwnd, TRUE );
+ UpdateWindow( hwnd );
+
+
+ PostMessage( this_->wnd_parent_handle, WM_USER + 1, 0, 0 );
+
+ this_->window.priv=this_;
+ return &this_->window;
+ }
+ return NULL;
+}
+
+
+static void background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
+{
+ RECT rcClient;
+ HBRUSH bgBrush = CreateSolidBrush( gc->bg_color );
+ GetClientRect( gr->wnd_handle, &rcClient );
+ FillRect( hMemDC, &rcClient, bgBrush );
+ DeleteObject( bgBrush );
+ gr->bg_color = gc->bg_color;
+}
+
+struct graphics_font_priv {
+ LOGFONT lf;
+ HFONT hfont;
+ int size;
+};
+
+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)
+{
+ RECT rcClient;
+ GetClientRect( gr->wnd_handle, &rcClient );
+
+ int prevBkMode = SetBkMode( hMemDC, TRANSPARENT );
+
+ if ( NULL == font->hfont )
+ {
+#ifdef WIN_USE_SYSFONT
+ font->hfont = (HFONT) GetStockObject (SYSTEM_FONT);
+ GetObject (font->hfont, sizeof (LOGFONT), &font->lf);
+#else
+ font->hfont = EzCreateFont (hMemDC, TEXT ("Arial"), font->size/2, 0, 0, TRUE);
+ GetObject ( font->hfont, sizeof (LOGFONT), &font->lf) ;
+#endif
+ }
+
+
+ double angle = -atan2( dy, dx ) * 180 / 3.14159 ;
+ if (angle < 0)
+ angle += 360;
+
+ SetTextAlign (hMemDC, TA_BASELINE) ;
+ SetViewportOrgEx (hMemDC, p->x, p->y, NULL) ;
+ font->lf.lfEscapement = font->lf.lfOrientation = ( angle * 10 ) ;
+ DeleteObject (font->hfont) ;
+
+ font->hfont = CreateFontIndirect (&font->lf);
+ HFONT hOldFont = SelectObject(hMemDC, font->hfont );
+
+ {
+ wchar_t utf16[1024];
+ const UTF8 *utf8 = (UTF8 *)text;
+ UTF16 *utf16p = (UTF16 *) utf16;
+ SetBkMode (hMemDC, TRANSPARENT);
+ if (ConvertUTF8toUTF16(&utf8, utf8+strlen(text),
+ &utf16p, utf16p+sizeof(utf16),
+ lenientConversion) == conversionOK) {
+#ifdef _WIN32_WCE
+ ExtTextOut (hMemDC, 0, 0, 0, NULL,
+ utf16, (wchar_t*) utf16p - utf16, NULL);
+#else
+ ExtTextOutW(hMemDC, 0, 0, 0, NULL,
+ utf16, (wchar_t*) utf16p - utf16, NULL);
+#endif
+ }
+ }
+
+
+ SelectObject(hMemDC, hOldFont);
+ DeleteObject (font->hfont) ;
+
+ SetBkMode( hMemDC, prevBkMode );
+
+ SetViewportOrgEx (hMemDC, 0, 0, NULL) ;
+}
+
+static void font_destroy(struct graphics_font_priv *font)
+{
+ if ( font->hfont )
+ {
+ DeleteObject(font->hfont);
+ }
+ g_free(font);
+}
+
+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 *name, int size, int flags)
+{
+ struct graphics_font_priv *font=g_new(struct graphics_font_priv, 1);
+ *meth = font_methods;
+
+ font->hfont = NULL;
+ font->size = size;
+ // FontFamily fontFamily( "Liberation Mono");
+//font( &fontFamily, size, FontStyleRegular, UnitPoint );
+ return font;
+}
+
+static void image_cache_hash_add( const char* key, struct graphics_image_priv* val_ptr)
+{
+ if ( image_cache_hash == NULL ) {
+ image_cache_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ if ( g_hash_table_lookup(image_cache_hash, key ) == NULL )
+ {
+ g_hash_table_insert(image_cache_hash, g_strdup( key ), (gpointer)val_ptr );
+ }
+
+}
+
+static struct graphics_image_priv* image_cache_hash_lookup( const char* key )
+{
+ struct graphics_image_priv* val_ptr = NULL;
+
+ if ( image_cache_hash != NULL )
+ {
+ val_ptr = g_hash_table_lookup(image_cache_hash, key );
+ }
+ return val_ptr;
+}
+
+
+
+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)
+{
+ struct graphics_image_priv* ret;
+
+ if ( NULL == ( ret = image_cache_hash_lookup( name ) ) )
+ {
+ ret = g_new( struct graphics_image_priv, 1 );
+ dbg(2, "loading image '%s'\n", name );
+ ret->pxpm = Xpm2bmp_new();
+ Xpm2bmp_load( ret->pxpm, name );
+ image_cache_hash_add( name, ret );
+ }
+
+ return ret;
+}
+
+static void draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
+{
+ Xpm2bmp_paint( img->pxpm , hMemDC, p->x, p->y );
+}
+
+static struct graphics_methods graphics_methods = {
+ graphics_destroy,
+ draw_mode,
+ draw_lines,
+ draw_polygon,
+ draw_rectangle,
+ draw_circle,
+ draw_text,
+ draw_image,
+#ifdef HAVE_IMLIB2
+ NULL, // draw_image_warp,
+#else
+ NULL,
+#endif
+ draw_restore,
+ NULL, // draw_drag
+ font_new,
+ gc_new,
+ background_gc,
+ NULL, // overlay_new,
+ image_new,
+ get_data,
+};
+
+static struct graphics_priv *
+graphics_win32_new_helper(struct graphics_methods *meth)
+{
+ struct graphics_priv *this_=g_new0(struct graphics_priv,1);
+ *meth=graphics_methods;
+ this_->mode = -1;
+ return this_;
+}
+
+static struct graphics_priv*
+graphics_win32_new( struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
+{
+ struct attr *attr;
+
+ struct graphics_priv* this_;
+ if (!event_request_system("win32","graphics_win32"))
+ return NULL;
+ this_=graphics_win32_new_helper(meth);
+ this_->nav=nav;
+ this_->width=792;
+ if ((attr=attr_search(attrs, NULL, attr_w)))
+ this_->width=attr->u.num;
+ this_->height=547;
+ if ((attr=attr_search(attrs, NULL, attr_h)))
+ this_->height=attr->u.num;
+
+ this_->cbl=cbl;
+ return this_;
+}
+
+static void
+event_win32_main_loop_run(void)
+{
+ MSG msg;
+
+ dbg(0,"enter\n");
+ while (GetMessage(&msg, 0, 0, 0)) {
+ TranslateMessage(&msg); /* Keyboard input. */
+ DispatchMessage(&msg);
+ }
+
+}
+
+static void event_win32_main_loop_quit(void)
+{
+ dbg(0,"enter\n");
+ PostQuitMessage(0);
+}
+
+static struct event_watch *
+event_win32_add_watch(void *h, enum event_watch_cond cond, struct callback *cb)
+{
+ dbg(0,"enter\n");
+ return NULL;
+}
+
+static void
+event_win32_remove_watch(struct event_watch *ev)
+{
+ dbg(0,"enter\n");
+}
+
+static GList *timers;
+struct event_timeout {
+ UINT_PTR timer_id;
+ int multi;
+ struct callback *cb;
+ struct event_timeout *next;
+};
+
+static void run_timer(UINT_PTR idEvent)
+{
+ GList *l;
+ struct event_timeout *t;
+ l = timers;
+ while (l) {
+ t = l->data;
+ if (t->timer_id == idEvent) {
+ dbg(1, "run timer:%d\n", idEvent);
+ callback_call_0(t->cb);
+ if (!t->multi) {
+ KillTimer(NULL, t->timer_id);
+ timers = g_list_remove(timers, t);
+ free(t);
+ }
+ return;
+ }
+ l = g_list_next(l);
+ }
+ dbg(0, "timer %d not found\n", idEvent);
+}
+
+static VOID CALLBACK win32_timer_cb(HWND hwnd, UINT uMsg,
+ UINT_PTR idEvent,
+ DWORD dwTime)
+{
+ run_timer(idEvent);
+}
+
+static struct event_timeout *
+event_win32_add_timeout(int timeout, int multi, struct callback *cb)
+{
+ struct event_timeout *t;
+ t = calloc(1, sizeof(*t));
+ if (!t)
+ return t;
+ t->multi = multi;
+ timers = g_list_prepend(timers, t);
+ t->cb = cb;
+ t->timer_id = SetTimer(NULL, 0, timeout, win32_timer_cb);
+ dbg(1, "Started timer %d for %d\n", t->timer_id, timeout);
+ return t;
+}
+
+static void
+event_win32_remove_timeout(struct event_timeout *to)
+{
+ GList *l;
+ struct event_timeout *t=NULL;
+ dbg(1,"enter:%d\n", t->timer_id);
+ l = timers;
+ while (l) {
+ t = l->data;
+ /* Use the pointer not the ID, IDs are reused */
+ if (t == to) {
+ KillTimer(NULL, t->timer_id);
+ timers = g_list_remove(timers, t);
+ free(t);
+ return;
+ }
+ l = g_list_next(l);
+ }
+ dbg(0, "Timer %d not found\n", to->timer_id);
+ free(to);
+}
+
+static struct event_idle *
+event_win32_add_idle(struct callback *cb)
+{
+ dbg(0,"enter\n");
+ return NULL;
+}
+
+static void
+event_win32_remove_idle(struct event_idle *ev)
+{
+ dbg(0,"enter\n");
+}
+
+static void
+event_win32_call_callback(struct callback_list *cb)
+{
+ PostMessage(g_hwnd, WM_USER+2, (WPARAM)cb , (LPARAM)0);
+}
+
+static struct event_methods event_win32_methods = {
+ event_win32_main_loop_run,
+ event_win32_main_loop_quit,
+ event_win32_add_watch,
+ event_win32_remove_watch,
+ event_win32_add_timeout,
+ event_win32_remove_timeout,
+ event_win32_add_idle,
+ event_win32_remove_idle,
+ event_win32_call_callback,
+};
+
+static struct event_priv *
+event_win32_new(struct event_methods *meth)
+{
+ *meth=event_win32_methods;
+ return NULL;
+}
+
+void
+plugin_init(void)
+{
+ plugin_register_graphics_type("win32", graphics_win32_new);
+ plugin_register_event_type("win32", event_win32_new);
+}
diff --git a/graphics/win32/graphics_win32.h b/graphics/win32/graphics_win32.h
new file mode 100644
index 00000000..9aab62ae
--- /dev/null
+++ b/graphics/win32/graphics_win32.h
@@ -0,0 +1,59 @@
+#ifndef WIN32_GUI_INCLUDED
+#define WIN32_GUI_INCLUDED
+
+#include "resources/resource.h"
+#include "coord.h"
+#include "point.h"
+#include "graphics.h"
+#include "event.h"
+
+#define ID_CHILD_GFX 100
+#define ID_CHILD_TOOLBAR (ID_CHILD_GFX + 1)
+#define ID_CHILD_1 (ID_CHILD_TOOLBAR + 1)
+#define ID_CHILD_2 (ID_CHILD_1 + 1)
+#define ID_CHILD_3 (ID_CHILD_2 + 1)
+#define ID_CHILD_4 (ID_CHILD_4 + 1)
+
+#define ID_DISPLAY_ZOOMIN 200
+#define ID_DISPLAY_ZOOMOUT 201
+#define ID_DISPLAY_REFRESH 202
+#define ID_DISPLAY_CURSOR 203
+#define ID_DISPLAY_ORIENT 204
+
+#define ID_FILE_EXIT 9001
+#define ID_STUFF_GO 9002
+
+//#define _(text) gettext(text)
+
+#define POPUP_MENU_OFFSET 4000
+
+struct statusbar_methods;
+struct menu_methods;
+struct datawindow_methods;
+struct navit;
+struct callback;
+
+
+struct menu_priv {
+ HWND wnd_handle;
+ HMENU hMenu;
+ struct callback* cb;
+};
+
+struct gui_priv {
+ struct navit *nav;
+ HANDLE hwnd;
+};
+
+
+struct graphics_priv;
+
+struct menu_priv *gui_gtk_menubar_new(struct gui_priv *gui, struct menu_methods *meth);
+struct menu_priv *gui_gtk_toolbar_new(struct gui_priv *gui, struct menu_methods *meth);
+struct statusbar_priv *gui_gtk_statusbar_new(struct gui_priv *gui, struct statusbar_methods *meth);
+struct menu_priv *gui_gtk_popup_new(struct gui_priv *gui, struct menu_methods *meth);
+struct datawindow_priv *gui_gtk_datawindow_new(struct gui_priv *gui, char *name, struct callback *click, struct callback *close, struct datawindow_methods *meth);
+
+struct graphics_priv* win32_graphics_new( struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl);
+
+#endif
diff --git a/graphics/win32/resources/resource.h b/graphics/win32/resources/resource.h
new file mode 100644
index 00000000..55bcc2d7
--- /dev/null
+++ b/graphics/win32/resources/resource.h
@@ -0,0 +1,4 @@
+#include <windows.h>
+
+#define IDI_NAVIT 1100
+#define IDB_NAVITTOOLBAR 1101
diff --git a/graphics/win32/xpm2bmp.c b/graphics/win32/xpm2bmp.c
new file mode 100644
index 00000000..95214d9c
--- /dev/null
+++ b/graphics/win32/xpm2bmp.c
@@ -0,0 +1,588 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <wingdi.h>
+#include "xpm2bmp.h"
+
+/* #define _DBG */
+
+// function prototypes
+static int CreateBitmapFromXpm( const char* filename, PXPM2BMP pXpm2bmp );
+
+// typedefs
+static XPMCOLORENTRY theRGBRecords[] =
+{
+ {"ALICEBLUE", 240, 248, 255},
+ {"ANTIQUEWHITE", 250, 235, 215},
+ {"AQUAMARINE", 50, 191, 193},
+ {"AZURE", 240, 255, 255},
+ {"BEIGE", 245, 245, 220},
+ {"BISQUE", 255, 228, 196},
+ {"BLACK", 0, 0, 0},
+ {"BLANCHEDALMOND", 255, 235, 205},
+ {"BLUE", 0, 0, 255},
+ {"BLUEVIOLET", 138, 43, 226},
+ {"BROWN", 165, 42, 42},
+ {"BURLYWOOD", 222, 184, 135},
+ {"CADETBLUE", 95, 146, 158},
+ {"CHARTREUSE", 127, 255, 0},
+ {"CHOCOLATE", 210, 105, 30},
+ {"CORAL", 255, 114, 86},
+ {"CORNFLOWERBLUE", 34, 34, 152},
+ {"CORNSILK", 255, 248, 220},
+ {"CYAN", 0, 255, 255},
+ {"DARKGOLDENROD", 184, 134, 11},
+ {"DARKGREEN", 0, 86, 45},
+ {"DARKKHAKI", 189, 183, 107},
+ {"DARKOLIVEGREEN", 85, 86, 47},
+ {"DARKORANGE", 255, 140, 0},
+ {"DARKORCHID", 139, 32, 139},
+ {"DARKSALMON", 233, 150, 122},
+ {"DARKSEAGREEN", 143, 188, 143},
+ {"DARKSLATEBLUE", 56, 75, 102},
+ {"DARKSLATEGRAY", 47, 79, 79},
+ {"DARKTURQUOISE", 0, 166, 166},
+ {"DARKVIOLET", 148, 0, 211},
+ {"DEEPPINK", 255, 20, 147},
+ {"DEEPSKYBLUE", 0, 191, 255},
+ {"DIMGRAY", 84, 84, 84},
+ {"DODGERBLUE", 30, 144, 255},
+ {"FIREBRICK", 142, 35, 35},
+ {"FLORALWHITE", 255, 250, 240},
+ {"FORESTGREEN", 80, 159, 105},
+ {"GAINSBORO", 220, 220, 220},
+ {"GHOSTWHITE", 248, 248, 255},
+ {"GOLD", 218, 170, 0},
+ {"GOLDENROD", 239, 223, 132},
+ {"GRAY", 126, 126, 126},
+ {"GRAY0", 0, 0, 0},
+ {"GRAY1", 3, 3, 3},
+ {"GRAY10", 26, 26, 26},
+ {"GRAY100", 255, 255, 255},
+ {"GRAY11", 28, 28, 28},
+ {"GRAY12", 31, 31, 31},
+ {"GRAY13", 33, 33, 33},
+ {"GRAY14", 36, 36, 36},
+ {"GRAY15", 38, 38, 38},
+ {"GRAY16", 41, 41, 41},
+ {"GRAY17", 43, 43, 43},
+ {"GRAY18", 46, 46, 46},
+ {"GRAY19", 48, 48, 48},
+ {"GRAY2", 5, 5, 5},
+ {"GRAY20", 51, 51, 51},
+ {"GRAY21", 54, 54, 54},
+ {"GRAY22", 56, 56, 56},
+ {"GRAY23", 59, 59, 59},
+ {"GRAY24", 61, 61, 61},
+ {"GRAY25", 64, 64, 64},
+ {"GRAY26", 66, 66, 66},
+ {"GRAY27", 69, 69, 69},
+ {"GRAY28", 71, 71, 71},
+ {"GRAY29", 74, 74, 74},
+ {"GRAY3", 8, 8, 8},
+ {"GRAY30", 77, 77, 77},
+ {"GRAY31", 79, 79, 79},
+ {"GRAY32", 82, 82, 82},
+ {"GRAY33", 84, 84, 84},
+ {"GRAY34", 87, 87, 87},
+ {"GRAY35", 89, 89, 89},
+ {"GRAY36", 92, 92, 92},
+ {"GRAY37", 94, 94, 94},
+ {"GRAY38", 97, 97, 97},
+ {"GRAY39", 99, 99, 99},
+ {"GRAY4", 10, 10, 10},
+ {"GRAY40", 102, 102, 102},
+ {"GRAY41", 105, 105, 105},
+ {"GRAY42", 107, 107, 107},
+ {"GRAY43", 110, 110, 110},
+ {"GRAY44", 112, 112, 112},
+ {"GRAY45", 115, 115, 115},
+ {"GRAY46", 117, 117, 117},
+ {"GRAY47", 120, 120, 120},
+ {"GRAY48", 122, 122, 122},
+ {"GRAY49", 125, 125, 125},
+ {"GRAY5", 13, 13, 13},
+ {"GRAY50", 127, 127, 127},
+ {"GRAY51", 130, 130, 130},
+ {"GRAY52", 133, 133, 133},
+ {"GRAY53", 135, 135, 135},
+ {"GRAY54", 138, 138, 138},
+ {"GRAY55", 140, 140, 140},
+ {"GRAY56", 143, 143, 143},
+ {"GRAY57", 145, 145, 145},
+ {"GRAY58", 148, 148, 148},
+ {"GRAY59", 150, 150, 150},
+ {"GRAY6", 15, 15, 15},
+ {"GRAY60", 153, 153, 153},
+ {"GRAY61", 156, 156, 156},
+ {"GRAY62", 158, 158, 158},
+ {"GRAY63", 161, 161, 161},
+ {"GRAY64", 163, 163, 163},
+ {"GRAY65", 166, 166, 166},
+ {"GRAY66", 168, 168, 168},
+ {"GRAY67", 171, 171, 171},
+ {"GRAY68", 173, 173, 173},
+ {"GRAY69", 176, 176, 176},
+ {"GRAY7", 18, 18, 18},
+ {"GRAY70", 179, 179, 179},
+ {"GRAY71", 181, 181, 181},
+ {"GRAY72", 184, 184, 184},
+ {"GRAY73", 186, 186, 186},
+ {"GRAY74", 189, 189, 189},
+ {"GRAY75", 191, 191, 191},
+ {"GRAY76", 194, 194, 194},
+ {"GRAY77", 196, 196, 196},
+ {"GRAY78", 199, 199, 199},
+ {"GRAY79", 201, 201, 201},
+ {"GRAY8", 20, 20, 20},
+ {"GRAY80", 204, 204, 204},
+ {"GRAY81", 207, 207, 207},
+ {"GRAY82", 209, 209, 209},
+ {"GRAY83", 212, 212, 212},
+ {"GRAY84", 214, 214, 214},
+ {"GRAY85", 217, 217, 217},
+ {"GRAY86", 219, 219, 219},
+ {"GRAY87", 222, 222, 222},
+ {"GRAY88", 224, 224, 224},
+ {"GRAY89", 227, 227, 227},
+ {"GRAY9", 23, 23, 23},
+ {"GRAY90", 229, 229, 229},
+ {"GRAY91", 232, 232, 232},
+ {"GRAY92", 235, 235, 235},
+ {"GRAY93", 237, 237, 237},
+ {"GRAY94", 240, 240, 240},
+ {"GRAY95", 242, 242, 242},
+ {"GRAY96", 245, 245, 245},
+ {"GRAY97", 247, 247, 247},
+ {"GRAY98", 250, 250, 250},
+ {"GRAY99", 252, 252, 252},
+ {"GREEN", 0, 255, 0},
+ {"GREENYELLOW", 173, 255, 47},
+ {"HONEYDEW", 240, 255, 240},
+ {"HOTPINK", 255, 105, 180},
+ {"INDIANRED", 107, 57, 57},
+ {"IVORY", 255, 255, 240},
+ {"KHAKI", 179, 179, 126},
+ {"LAVENDER", 230, 230, 250},
+ {"LAVENDERBLUSH", 255, 240, 245},
+ {"LAWNGREEN", 124, 252, 0},
+ {"LEMONCHIFFON", 255, 250, 205},
+ {"LIGHTBLUE", 176, 226, 255},
+ {"LIGHTCORAL", 240, 128, 128},
+ {"LIGHTCYAN", 224, 255, 255},
+ {"LIGHTGOLDENROD", 238, 221, 130},
+ {"LIGHTGOLDENRODYELLOW", 250, 250, 210},
+ {"LIGHTGRAY", 168, 168, 168},
+ {"LIGHTPINK", 255, 182, 193},
+ {"LIGHTSALMON", 255, 160, 122},
+ {"LIGHTSEAGREEN", 32, 178, 170},
+ {"LIGHTSKYBLUE", 135, 206, 250},
+ {"LIGHTSLATEBLUE", 132, 112, 255},
+ {"LIGHTSLATEGRAY", 119, 136, 153},
+ {"LIGHTSTEELBLUE", 124, 152, 211},
+ {"LIGHTYELLOW", 255, 255, 224},
+ {"LIMEGREEN", 0, 175, 20},
+ {"LINEN", 250, 240, 230},
+ {"MAGENTA", 255, 0, 255},
+ {"MAROON", 143, 0, 82},
+ {"MEDIUMAQUAMARINE", 0, 147, 143},
+ {"MEDIUMBLUE", 50, 50, 204},
+ {"MEDIUMFORESTGREEN", 50, 129, 75},
+ {"MEDIUMGOLDENROD", 209, 193, 102},
+ {"MEDIUMORCHID", 189, 82, 189},
+ {"MEDIUMPURPLE", 147, 112, 219},
+ {"MEDIUMSEAGREEN", 52, 119, 102},
+ {"MEDIUMSLATEBLUE", 106, 106, 141},
+ {"MEDIUMSPRINGGREEN", 35, 142, 35},
+ {"MEDIUMTURQUOISE", 0, 210, 210},
+ {"MEDIUMVIOLETRED", 213, 32, 121},
+ {"MIDNIGHTBLUE", 47, 47, 100},
+ {"MINTCREAM", 245, 255, 250},
+ {"MISTYROSE", 255, 228, 225},
+ {"MOCCASIN", 255, 228, 181},
+ {"NAVAJOWHITE", 255, 222, 173},
+ {"NAVY", 35, 35, 117},
+ {"NAVYBLUE", 35, 35, 117},
+ {"OLDLACE", 253, 245, 230},
+ {"OLIVEDRAB", 107, 142, 35},
+ {"ORANGE", 255, 135, 0},
+ {"ORANGERED", 255, 69, 0},
+ {"ORCHID", 239, 132, 239},
+ {"PALEGOLDENROD", 238, 232, 170},
+ {"PALEGREEN", 115, 222, 120},
+ {"PALETURQUOISE", 175, 238, 238},
+ {"PALEVIOLETRED", 219, 112, 147},
+ {"PAPAYAWHIP", 255, 239, 213},
+ {"PEACHPUFF", 255, 218, 185},
+ {"PERU", 205, 133, 63},
+ {"PINK", 255, 181, 197},
+ {"PLUM", 197, 72, 155},
+ {"POWDERBLUE", 176, 224, 230},
+ {"PURPLE", 160, 32, 240},
+ {"RED", 255, 0, 0},
+ {"ROSYBROWN", 188, 143, 143},
+ {"ROYALBLUE", 65, 105, 225},
+ {"SADDLEBROWN", 139, 69, 19},
+ {"SALMON", 233, 150, 122},
+ {"SANDYBROWN", 244, 164, 96},
+ {"SEAGREEN", 82, 149, 132},
+ {"SEASHELL", 255, 245, 238},
+ {"SIENNA", 150, 82, 45},
+ {"SKYBLUE", 114, 159, 255},
+ {"SLATEBLUE", 126, 136, 171},
+ {"SLATEGRAY", 112, 128, 144},
+ {"SNOW", 255, 250, 250},
+ {"SPRINGGREEN", 65, 172, 65},
+ {"STEELBLUE", 84, 112, 170},
+ {"TAN", 222, 184, 135},
+ {"THISTLE", 216, 191, 216},
+ {"TOMATO", 255, 99, 71},
+ {"TRANSPARENT", 0, 0, 1},
+ {"TURQUOISE", 25, 204, 223},
+ {"VIOLET", 156, 62, 206},
+ {"VIOLETRED", 243, 62, 150},
+ {"WHEAT", 245, 222, 179},
+ {"WHITE", 255, 255, 255},
+ {"WHITESMOKE", 245, 245, 245},
+ {"YELLOW", 255, 255, 0},
+ {"YELLOWGREEN", 50, 216, 56}
+};
+
+
+PXPM2BMP Xpm2bmp_new()
+{
+ PXPM2BMP preturn = (PXPM2BMP)calloc( sizeof( XPM2BMP ) , 1 );
+ return preturn;
+}
+
+
+int Xpm2bmp_load( PXPM2BMP pXpm2bmp, const char* filename )
+{
+ return CreateBitmapFromXpm( filename, pXpm2bmp );
+}
+
+int Xpm2bmp_paint( PXPM2BMP pXpm2bmp, HDC hdc, int x1,int y1 )
+{
+ StretchDIBits(hdc,
+ x1, y1, pXpm2bmp->size_x, pXpm2bmp->size_y,
+ 0, 0, pXpm2bmp->size_x, pXpm2bmp->size_y,
+ pXpm2bmp->wimage_data_trans,
+ (BITMAPINFO *)pXpm2bmp->bmih_trans,
+ DIB_RGB_COLORS,
+ SRCAND );
+
+ StretchDIBits(hdc,
+ x1, y1, pXpm2bmp->size_x, pXpm2bmp->size_y,
+ 0, 0, pXpm2bmp->size_x, pXpm2bmp->size_y,
+ pXpm2bmp->wimage_data,
+ (BITMAPINFO *)pXpm2bmp->bmih,
+ DIB_RGB_COLORS,
+ SRCPAINT );
+
+ return 0;
+}
+
+static int parse_line_values( const char* line, PXPM2BMP pXpm2bmp )
+{
+ int return_value = 0;
+ char* parse_line = (char*)line;
+ char* tok;
+ int value_pos = 0;
+
+ parse_line = strchr( parse_line, '"' );
+ parse_line++;
+
+ tok = strtok( parse_line, " \t\n" );
+
+ while ( tok != 0 )
+ {
+ int val = atoi( tok );
+ switch ( value_pos )
+ {
+ case 0: pXpm2bmp->size_x = val; break;
+ case 1: pXpm2bmp->size_y = val; break;
+ case 2: pXpm2bmp->colors = val; break;
+ case 3: pXpm2bmp->chars_per_pixel = val; break;
+ case 4: pXpm2bmp->hotspot_x = val; break;
+ case 5: pXpm2bmp->hotspot_y = val; break;
+ }
+ tok = strtok( NULL, " \t" );
+ value_pos ++;
+
+ }
+
+ return return_value;
+}
+
+static int hex2int( char c )
+{
+ if ((c >= '0') && (c <='9' )) return c - '0';
+ if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
+ if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
+ return -1;
+}
+
+static DWORD string2hex16( const char* str )
+{
+ int i1 = hex2int( str[0] );
+ int i2 = hex2int( str[1] );
+ if ( ( i1 >= 0 ) && ( i2 >= 0 ) )
+ return i1*16+i2;
+ return -1;
+}
+
+static int parse_color_values( const char* line, PXPM2BMP pXpm2bmp )
+{
+ int return_value = 0;
+ char* cq = strchr( line, '"' );
+ char* cchar = strchr( cq+pXpm2bmp->chars_per_pixel+1, 'c' );
+ char* chash = strchr( cq+pXpm2bmp->chars_per_pixel+1, '#' );
+ char* qe = strchr( cq+pXpm2bmp->chars_per_pixel+1, '"' );
+
+ cq++;
+
+ if ( cq )
+ {
+ memcpy( pXpm2bmp->color_entires[ pXpm2bmp-> color_entires_size].color_str, cq, pXpm2bmp->chars_per_pixel + 1 );
+ pXpm2bmp->color_entires[ pXpm2bmp-> color_entires_size].color_str[ pXpm2bmp->chars_per_pixel ] = '\0';
+
+
+ if ( cchar && chash && qe)
+ {
+ chash++;
+ *qe = 0;
+ int len = strlen( chash );
+
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].r = string2hex16( &chash[0] );
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].g = string2hex16( &chash[len / 3] );
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].b = string2hex16( &chash[len * 2 / 3] );
+#ifdef _DBG
+printf( "adding color %s => %d RGB %x %x %x to index %d\n",
+ line,
+ pXpm2bmp->color_entires_size,
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].r,
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].g,
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].b,
+ pXpm2bmp->color_entires_size );
+#endif
+ }
+ else
+ {
+ int q;
+ char *start = cchar + 1;
+ char *end = start;
+
+ while ( *start != 0 )
+ {
+ if ( ( *start != '\t' ) && ( *start != ' ' ) )
+ {
+ break;
+ }
+ start++;
+ }
+
+ end = start;
+ while ( *end != 0 )
+ {
+ if ( ( *end == '\t' ) || ( *end == ' ' ) || ( *end == '"' ))
+ {
+ *end = 0;
+ }
+ end++;
+ }
+
+ start = _strupr( start );
+
+ for ( q=0; q < sizeof( theRGBRecords ) / sizeof( theRGBRecords[0] ); q++ )
+ {
+
+ if ( 0 == strcmp( start, theRGBRecords[q].color_str ) )
+ {
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].r = theRGBRecords[q].r;
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].g = theRGBRecords[q].g;
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].b = theRGBRecords[q].b;
+ }
+ }
+ if ( 0 == strcmp( start, "NONE" ) )
+ {
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].r = 255;
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].g = 0;
+ pXpm2bmp->color_entires[ pXpm2bmp->color_entires_size].b = 255;
+ }
+ }
+ }
+ pXpm2bmp->color_entires_size++;
+
+ return return_value;
+}
+
+static int vv = 0;
+
+static int parse_pixel_line_values( const char* line, PXPM2BMP pXpm2bmp, unsigned char* pixel_data, unsigned char* pixel_data_trans )
+{
+ int return_value = 0;
+ int i,j;
+
+
+ char* cq = strchr( line, '"' );
+ int pix_idx = 0;
+ int size_x = pXpm2bmp->size_x;
+ int len = strlen( cq );
+
+ cq++;
+
+ if ( len > pXpm2bmp->chars_per_pixel * size_x )
+ {
+ for ( i=0; i< size_x; i++ )
+ {
+ int found = 0;
+ char* cmp = &cq[ i * pXpm2bmp->chars_per_pixel];
+
+ for ( j=0; j< pXpm2bmp-> color_entires_size; j++ )
+ {
+ if ( strncmp( cmp, pXpm2bmp->color_entires[ j ].color_str, pXpm2bmp->chars_per_pixel ) == 0 )
+ {
+ int r = pXpm2bmp->color_entires[ j ].r;
+ int g = pXpm2bmp->color_entires[ j ].g;
+ int b = pXpm2bmp->color_entires[ j ].b;
+
+ if ( ( r == 255 ) && ( g == 0 ) && ( r == 255 ) )
+ {
+ r=g=b=0;
+ pixel_data_trans[ pix_idx ] = 255;
+ pixel_data_trans[ pix_idx+1 ] = 255;
+ pixel_data_trans[ pix_idx+2 ] = 255;
+ }
+ else
+ {
+ pixel_data_trans[ pix_idx ] = 0;
+ pixel_data_trans[ pix_idx+1 ] = 0;
+ pixel_data_trans[ pix_idx+2 ] = 0;
+ }
+
+ // pixel_data[ pix_idx++ ] = pXpm2bmp->color_entires[ j ].r;
+ // pixel_data[ pix_idx++ ] = pXpm2bmp->color_entires[ j ].g;
+ // pixel_data[ pix_idx++ ] = pXpm2bmp->color_entires[ j ].b;
+ pixel_data[ pix_idx++ ] = b;
+ pixel_data[ pix_idx++ ] = g;
+ pixel_data[ pix_idx++ ] = r;
+ found = 1;
+ vv++;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ fprintf( stderr, "XPMLIB: error color not found\n" );
+ }
+
+ }
+ }
+ else
+ {
+ return_value = -1;
+ fprintf( stderr, "XPMLIB: invalid line length\n" );
+ }
+ return return_value;
+}
+
+
+static int CreateBitmapFromXpm( const char* filename, PXPM2BMP pXpm2bmp )
+{
+ int return_val = 0;
+ unsigned char i, row;
+ char line[ 1024 ];
+ int nbytes ;
+ FILE* file_xpm = fopen( filename, "r" );
+
+ int phase = 0;
+ row = 0;
+
+ if ( file_xpm )
+ {
+ while ( fgets(line, sizeof( line ), file_xpm ) )
+ {
+#ifdef _DBG
+ printf( "PARSING: %s\n", line );
+#endif
+ if ( line[ 0 ] != '"' )
+ continue;
+
+ switch ( phase )
+ {
+ case 0:
+ parse_line_values( line, pXpm2bmp );
+#ifdef _DBG
+ printf( "size_x %d\n", pXpm2bmp->size_x );
+ printf( "size_y %d\n", pXpm2bmp->size_y );
+#endif
+ phase = 1;
+
+ pXpm2bmp->color_entires_size = 0;
+ nbytes = ( pXpm2bmp->chars_per_pixel + 1 ) * pXpm2bmp->colors;
+
+ pXpm2bmp->color_entires = calloc( sizeof( XPMCOLORENTRY ), pXpm2bmp->colors + 100 );
+ pXpm2bmp->color_entires[0].color_str = calloc( nbytes, pXpm2bmp->colors );
+ for ( i = 1; i< pXpm2bmp->colors; i++ )
+ {
+ pXpm2bmp->color_entires[i].color_str = pXpm2bmp->color_entires[0].color_str + ( pXpm2bmp->chars_per_pixel + 1 ) * i;
+ }
+
+ if (!(pXpm2bmp->dib = (unsigned char *)malloc(sizeof(BITMAPINFOHEADER) + pXpm2bmp->size_x * pXpm2bmp->size_y * 3)))
+ {
+ return 4;
+ }
+ if (!(pXpm2bmp->dib_trans = (unsigned char *)calloc(sizeof(BITMAPINFOHEADER) + pXpm2bmp->size_x * pXpm2bmp->size_y * 3,1)))
+ {
+ return 4;
+ }
+
+ memset(pXpm2bmp->dib, 0, sizeof(BITMAPINFOHEADER));
+ pXpm2bmp->bmih = (BITMAPINFOHEADER *)pXpm2bmp->dib;
+ pXpm2bmp->bmih->biSize = sizeof(BITMAPINFOHEADER);
+ pXpm2bmp->bmih->biWidth = pXpm2bmp->size_x;
+ pXpm2bmp->bmih->biHeight = -((long)pXpm2bmp->size_y);
+ pXpm2bmp->bmih->biPlanes = 1;
+ pXpm2bmp->bmih->biBitCount = 24;
+ pXpm2bmp->bmih->biCompression = 0;
+ pXpm2bmp->wimage_data = pXpm2bmp->dib + sizeof(BITMAPINFOHEADER);
+
+
+ pXpm2bmp->bmih_trans = (BITMAPINFOHEADER *)pXpm2bmp->dib_trans;
+ pXpm2bmp->bmih_trans->biSize = sizeof(BITMAPINFOHEADER);
+ pXpm2bmp->bmih_trans->biWidth = pXpm2bmp->size_x;
+ pXpm2bmp->bmih_trans->biHeight = -((long)pXpm2bmp->size_y);
+ pXpm2bmp->bmih_trans->biPlanes = 1;
+ pXpm2bmp->bmih_trans->biBitCount = 24;
+ pXpm2bmp->bmih_trans->biCompression = 0;
+ pXpm2bmp->wimage_data_trans = pXpm2bmp->dib_trans + sizeof(BITMAPINFOHEADER);
+// memset( pXpm2bmp->wimage_data_trans, 255, 5* 22 * 3 );
+
+ break;
+ case 1:
+ parse_color_values( line, pXpm2bmp );
+ if ( pXpm2bmp->color_entires_size >= pXpm2bmp->colors )
+ {
+ phase = 2;
+ }
+
+ break;
+ case 2:
+ parse_pixel_line_values( line, pXpm2bmp,
+ pXpm2bmp->wimage_data + row * pXpm2bmp->size_x * 3,
+ pXpm2bmp->wimage_data_trans + row * pXpm2bmp->size_x * 3 );
+
+ row++;
+ if ( row >= pXpm2bmp->size_y )
+ {
+ phase = 3;
+ }
+ break;
+ }
+
+ }
+
+ fclose( file_xpm );
+ }
+ return return_val;
+}
diff --git a/graphics/win32/xpm2bmp.h b/graphics/win32/xpm2bmp.h
new file mode 100644
index 00000000..2fa028f1
--- /dev/null
+++ b/graphics/win32/xpm2bmp.h
@@ -0,0 +1,44 @@
+#ifndef Xpm2BMP_H_INCLUDED
+#define Xpm2BMP_H_INCLUDED
+
+#include <windows.h>
+#include "wingdi.h"
+
+typedef struct XPMCOLORENTRY_TAG
+{
+ char* color_str;
+ unsigned long r;
+ unsigned long g;
+ unsigned long b;
+} XPMCOLORENTRY, *PXPMCOLORENTRY;
+
+typedef struct XPM2BMP_TAG
+{
+ unsigned short size_x;
+ unsigned short size_y;
+ unsigned short colors;
+ unsigned short pixels;
+ unsigned short chars_per_pixel;
+ unsigned short hotspot_x;
+ unsigned short hotspot_y;
+
+ int color_entires_size;
+ PXPMCOLORENTRY color_entires;
+
+ unsigned char *dib;
+ unsigned char *wimage_data;
+ BITMAPINFOHEADER *bmih;
+
+ unsigned char *dib_trans;
+ unsigned char *wimage_data_trans;
+ BITMAPINFOHEADER *bmih_trans;
+
+} XPM2BMP, *PXPM2BMP;
+
+
+PXPM2BMP Xpm2bmp_new();
+int Xpm2bmp_load( PXPM2BMP pXpm2bmp, const char* filename );
+int Xpm2bmp_paint( PXPM2BMP pXpm2bmp, HDC hdc, int x1,int y1 );
+
+
+#endif // Xpm2BMP_H_INCLUDED