summaryrefslogtreecommitdiff
path: root/navit/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'navit/graphics')
-rw-r--r--navit/graphics/android/graphics_android.c67
-rw-r--r--navit/graphics/qt5/graphics_qt5.cpp28
-rw-r--r--navit/graphics/sdl/graphics_sdl.c60
-rw-r--r--navit/graphics/sdl/raster.c199
-rw-r--r--navit/graphics/sdl/raster.h6
-rw-r--r--navit/graphics/win32/graphics_win32.c175
6 files changed, 447 insertions, 88 deletions
diff --git a/navit/graphics/android/graphics_android.c b/navit/graphics/android/graphics_android.c
index e119cf3cc..c6fd37488 100644
--- a/navit/graphics/android/graphics_android.c
+++ b/navit/graphics/android/graphics_android.c
@@ -483,8 +483,9 @@ static void resize_callback(struct graphics_priv *gra, int w, int h) {
callback_list_call_attr_2(gra->cbl, attr_resize, (void *)w, (void *)h);
}
-static void padding_callback(struct graphics_priv *gra, int left, int top, int right, int bottom) {
- dbg(lvl_debug, "win.padding left=%d top=%d right=%d bottom=%d ok", left, top, right, bottom);
+static void padding_changed_callback(struct graphics_priv *gra, int left, int top, int right,
+ int bottom) {
+ dbg(lvl_error, "win.padding left=%d top=%d right=%d bottom=%d", left, top, right, bottom);
gra->padding->left = left;
gra->padding->top = top;
gra->padding->right = right;
@@ -627,45 +628,45 @@ static int graphics_android_init(struct graphics_priv *ret, struct graphics_priv
if (ret->Paint)
ret->Paint = (*jnienv)->NewGlobalRef(jnienv, ret->Paint);
- cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setSizeChangedCallback", "(I)V");
+ cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setSizeChangedCallback", "(J)V");
if (cid == NULL) {
- dbg(lvl_error,"no SetResizeCallback method found");
+ dbg(lvl_error,"no setResizeCallback method found");
return 0; /* exception thrown */
}
cb=callback_new_1(callback_cast(resize_callback), ret);
- (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+ (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (jlong)cb);
- cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setPaddingChangedCallback", "(I)V");
+ cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setPaddingChangedCallback", "(J)V");
if (cid == NULL) {
- dbg(lvl_error,"no SetPaddingCallback method found");
+ dbg(lvl_error,"no setPaddingCallback method found");
return 0; /* exception thrown */
}
- cb=callback_new_1(callback_cast(padding_callback), ret);
- (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+ cb=callback_new_1(callback_cast(padding_changed_callback), ret);
+ (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (jlong)cb);
- cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setButtonCallback", "(I)V");
+ cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setButtonCallback", "(J)V");
if (cid == NULL) {
- dbg(lvl_error,"no SetButtonCallback method found");
+ dbg(lvl_error,"no setButtonCallback method found");
return 0; /* exception thrown */
}
cb=callback_new_1(callback_cast(button_callback), ret);
- (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+ (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (jlong)cb);
- cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setMotionCallback", "(I)V");
+ cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setMotionCallback", "(J)V");
if (cid == NULL) {
- dbg(lvl_error,"no SetMotionCallback method found");
+ dbg(lvl_error,"no setMotionCallback method found");
return 0; /* exception thrown */
}
cb=callback_new_1(callback_cast(motion_callback), ret);
- (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+ (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (jlong)cb);
- cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setKeypressCallback", "(I)V");
+ cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setKeypressCallback", "(J)V");
if (cid == NULL) {
- dbg(lvl_error,"no SetKeypressCallback method found");
+ dbg(lvl_error,"no setKeypressCallback method found");
return 0; /* exception thrown */
}
cb=callback_new_1(callback_cast(keypress_callback), ret);
- (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+ (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (jlong)cb);
if (!find_method(ret->NavitGraphicsClass, "draw_polyline", "(Landroid/graphics/Paint;[I)V",
&ret->NavitGraphics_draw_polyline))
@@ -696,7 +697,7 @@ static int graphics_android_init(struct graphics_priv *ret, struct graphics_priv
return 0;
if (!find_method(ret->NavitGraphicsClass, "overlay_resize", "(IIIII)V", &ret->NavitGraphics_overlay_resize))
return 0;
- if (!find_method(ret->NavitGraphicsClass, "SetCamera", "(I)V", &ret->NavitGraphics_SetCamera))
+ if (!find_method(ret->NavitGraphicsClass, "setCamera", "(I)V", &ret->NavitGraphics_SetCamera))
return 0;
#if 0
set_activity(ret->NavitGraphics);
@@ -732,7 +733,7 @@ static void graphics_android_disable_suspend(struct window *win) {
static void graphics_android_cmd_runMenuItem(struct graphics_priv *this, char *function, struct attr **in,
struct attr ***out, int *valid) {
int ncmd=0;
- dbg(0,"Running %s",function);
+ dbg(lvl_debug,"Running %s",function);
if(!strcmp(function,"map_download_dialog")) {
ncmd=3;
} else if(!strcmp(function,"backup_restore_dialog")) {
@@ -911,7 +912,7 @@ static jmethodID NavitWatch_remove;
static void do_poll(JNIEnv *env, int fd, int cond) {
struct pollfd pfd;
pfd.fd=fd;
- dbg(lvl_debug,"%p poll called for %d %d", fd, cond);
+ dbg(lvl_debug,"poll called for %d %d", fd, cond);
switch ((enum event_watch_cond)cond) {
case event_watch_cond_read:
pfd.events=POLLIN;
@@ -931,8 +932,8 @@ static void do_poll(JNIEnv *env, int fd, int cond) {
static struct event_watch *event_android_add_watch(int h, enum event_watch_cond cond, struct callback *cb) {
jobject ret;
- ret=(*jnienv)->NewObject(jnienv, NavitWatchClass, NavitWatch_init, (int)do_poll, h, (int) cond, (int)cb);
- dbg(lvl_debug,"result for %d,%d,%p=%p",h,cond,cb,ret);
+ ret=(*jnienv)->NewObject(jnienv, NavitWatchClass, NavitWatch_init, (jlong)do_poll, h, (jint) cond, (jlong)cb);
+ dbg(lvl_debug,"result for %d,%d,%p = %p",h,cond,cb,ret);
if (ret)
ret = (*jnienv)->NewGlobalRef(jnienv, ret);
return (struct event_watch *)ret;
@@ -973,7 +974,8 @@ static struct event_timeout *event_android_add_timeout(int timeout, int multi, s
ret->cb = cb;
ret->multi = multi;
ret->handle_timeout = event_android_handle_timeout;
- ret->jni_timeout = (*jnienv)->NewObject(jnienv, NavitTimeoutClass, NavitTimeout_init, timeout, multi, (int)ret);
+ ret->jni_timeout = (*jnienv)->NewObject(jnienv, NavitTimeoutClass, NavitTimeout_init, timeout, multi, (jlong)(ret));
+ dbg(lvl_debug,"result for %d,%d,%p = %p",timeout,multi,cb,ret);
if (ret->jni_timeout)
ret->jni_timeout = (*jnienv)->NewGlobalRef(jnienv, ret->jni_timeout);
return ret;
@@ -1025,7 +1027,7 @@ static struct event_priv *event_android_new(struct event_methods *meth) {
dbg(lvl_debug,"enter");
if (!find_class_global("org/navitproject/navit/NavitTimeout", &NavitTimeoutClass))
return NULL;
- NavitTimeout_init = (*jnienv)->GetMethodID(jnienv, NavitTimeoutClass, "<init>", "(IZI)V");
+ NavitTimeout_init = (*jnienv)->GetMethodID(jnienv, NavitTimeoutClass, "<init>", "(IZJ)V");
if (NavitTimeout_init == NULL)
return NULL;
NavitTimeout_remove = (*jnienv)->GetMethodID(jnienv, NavitTimeoutClass, "remove", "()V");
@@ -1044,7 +1046,7 @@ static struct event_priv *event_android_new(struct event_methods *meth) {
if (!find_class_global("org/navitproject/navit/NavitWatch", &NavitWatchClass))
return NULL;
- NavitWatch_init = (*jnienv)->GetMethodID(jnienv, NavitWatchClass, "<init>", "(IIII)V");
+ NavitWatch_init = (*jnienv)->GetMethodID(jnienv, NavitWatchClass, "<init>", "(JIIJ)V");
if (NavitWatch_init == NULL)
return NULL;
NavitWatch_remove = (*jnienv)->GetMethodID(jnienv, NavitWatchClass, "remove", "()V");
@@ -1056,7 +1058,7 @@ static struct event_priv *event_android_new(struct event_methods *meth) {
Navit_disableSuspend = (*jnienv)->GetMethodID(jnienv, NavitClass, "disableSuspend", "()V");
if (Navit_disableSuspend == NULL)
return NULL;
- Navit_exit = (*jnienv)->GetMethodID(jnienv, NavitClass, "exit", "()V");
+ Navit_exit = (*jnienv)->GetMethodID(jnienv, NavitClass, "onDestroy", "()V");
if (Navit_exit == NULL)
return NULL;
Navit_fullscreen = (*jnienv)->GetMethodID(jnienv, NavitClass, "fullscreen", "(I)V");
@@ -1076,7 +1078,12 @@ static struct event_priv *event_android_new(struct event_methods *meth) {
return NULL;
}
-
+/* below needs review, android resizes the view and the actual height of the keyboard is not
+ * passed down here and is irrelevant, only wether it is onscreen matters, so
+ * android returns a height of 1 px in the case of an onscreen keyboard just
+ * to keep the logic to remove the keyboard from the screen afterwards working untill
+ * the logic in native code is reviewed.
+ * /
/**
* @brief Displays the native input method.
*
@@ -1096,14 +1103,12 @@ static struct event_priv *event_android_new(struct event_methods *meth) {
* @return True if the input method is going to be displayed, false if not.
*/
int show_native_keyboard (struct graphics_keyboard *kbd) {
- kbd->w = -1;
if (Navit_showNativeKeyboard == NULL) {
dbg(lvl_error, "method Navit.showNativeKeyboard() not found, cannot display keyboard");
return 0;
}
kbd->h = (*jnienv)->CallIntMethod(jnienv, android_activity, Navit_showNativeKeyboard);
- dbg(lvl_error, "keyboard size is %d x %d px", kbd->w, kbd->h);
- dbg(lvl_error, "return");
+ dbg(lvl_error, "keyboard height is %d px is a lie", kbd->h);
/* zero height means we're not showing a keyboard, therefore normalize height to boolean */
return !!(kbd->h);
}
diff --git a/navit/graphics/qt5/graphics_qt5.cpp b/navit/graphics/qt5/graphics_qt5.cpp
index 10784d6b3..cb9b4c456 100644
--- a/navit/graphics/qt5/graphics_qt5.cpp
+++ b/navit/graphics/qt5/graphics_qt5.cpp
@@ -408,13 +408,7 @@ static void draw_polygon(struct graphics_priv* gr, struct graphics_gc_priv* gc,
polygon.putPoints(i, 1, p[i].x, p[i].y);
gr->painter->setPen(*gc->pen);
gr->painter->setBrush(*gc->brush);
- /* if the polygon is transparent, we need to clear it first */
- if (!gc->brush->isOpaque()) {
- QPainter::CompositionMode mode = gr->painter->compositionMode();
- gr->painter->setCompositionMode(QPainter::CompositionMode_Clear);
- gr->painter->drawPolygon(polygon);
- gr->painter->setCompositionMode(mode);
- }
+
gr->painter->drawPolygon(polygon);
}
@@ -446,13 +440,6 @@ static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_g
if(hole_count > 0)
path = path.subtracted(inner);
- /* if the polygon is transparent, we need to clear it first */
- if (!gc->brush->isOpaque()) {
- QPainter::CompositionMode mode = gr->painter->compositionMode();
- gr->painter->setCompositionMode(QPainter::CompositionMode_Clear);
- gr->painter->drawPath(path);
- gr->painter->setCompositionMode(mode);
- }
gr->painter->drawPath(path);
}
@@ -460,13 +447,6 @@ static void draw_rectangle(struct graphics_priv* gr, struct graphics_gc_priv* gc
// dbg(lvl_debug,"gr=%p gc=%p %d,%d,%d,%d", gr, gc, p->x, p->y, w, h);
if (gr->painter == NULL)
return;
- /* if the rectangle is transparent, we need to clear it first */
- if (!gc->brush->isOpaque()) {
- QPainter::CompositionMode mode = gr->painter->compositionMode();
- gr->painter->setCompositionMode(QPainter::CompositionMode_Clear);
- gr->painter->fillRect(p->x, p->y, w, h, *gc->brush);
- gr->painter->setCompositionMode(mode);
- }
gr->painter->fillRect(p->x, p->y, w, h, *gc->brush);
}
@@ -647,9 +627,11 @@ static void draw_mode(struct graphics_priv* gr, enum draw_mode_num mode) {
case draw_mode_begin:
dbg(lvl_debug, "Begin drawing on context %p (use == %d)", gr, gr->use_count);
gr->use_count++;
- if (gr->painter == NULL)
+ if (gr->painter == NULL) {
+ if(gr->parent != NULL)
+ gr->pixmap->fill(QColor(0,0,0,0));
gr->painter = new QPainter(gr->pixmap);
- else
+ } else
dbg(lvl_debug, "drawing on %p already active", gr);
break;
case draw_mode_end:
diff --git a/navit/graphics/sdl/graphics_sdl.c b/navit/graphics/sdl/graphics_sdl.c
index 4187d4ed6..d92699307 100644
--- a/navit/graphics/sdl/graphics_sdl.c
+++ b/navit/graphics/sdl/graphics_sdl.c
@@ -284,45 +284,47 @@ static void image_free(struct graphics_priv *gr, struct graphics_image_priv * gi
g_free(gi);
}
-static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count) {
+static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
+ int hole_count, int* ccount, struct point **holes) {
+
+ dbg(lvl_debug, "draw_polygon_with_holes: %p ", gc);
if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent
&& gr->overlay_parent->overlay_enable && !gr->overlay_enable) ) {
return;
}
- 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;
- vx[i] = x;
- vy[i] = y;
-
- dbg(lvl_debug, "draw_polygon: %p %i %d,%d", gc, i, p[i].x, p[i].y);
- }
+ /* SDL library (SDL_gfx) uses array of X and array of Y instead of array of points
+ * as the rest of navit does. This requires translating the coordinates from one struct
+ * into another. As we have our own version of SDL_gfx anyway, I step aside from this
+ * mechanic and continue using points. This breaks (pseudo= compatibility with stock
+ * sdl_graphics. Since we need to raytrace the polygons anyway, we can prepare the
+ * coordinates for SDL primitives there.
+ */
if(gr->aa) {
- raster_aapolygon(gr->screen, count, vx, vy,
- SDL_MapRGBA(gr->screen->format,
- gc->fore_r,
- gc->fore_g,
- gc->fore_b,
- gc->fore_a));
+ raster_aapolygon_with_holes(gr->screen, p, count, hole_count, ccount, holes,
+ SDL_MapRGBA(gr->screen->format,
+ gc->fore_r,
+ gc->fore_g,
+ gc->fore_b,
+ gc->fore_a));
} else {
- raster_polygon(gr->screen, count, vx, vy,
- SDL_MapRGBA(gr->screen->format,
- gc->fore_r,
- gc->fore_g,
- gc->fore_b,
- gc->fore_a));
+ raster_polygon_with_holes(gr->screen, p, count, hole_count, ccount, holes,
+ SDL_MapRGBA(gr->screen->format,
+ gc->fore_r,
+ gc->fore_g,
+ gc->fore_b,
+ gc->fore_a));
}
}
+static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count) {
+ dbg(lvl_debug, "draw_polygon: %p ", gc);
+ /* Use polygon with holes primitive as this seems to be better performing than the
+ * traditional SDL_gfx like ones */
+ draw_polygon_with_holes(gr, gc, p, count, 0, NULL, NULL);
+}
+
static void draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h) {
if ((gr->overlay_parent && !gr->overlay_parent->overlay_enable) || (gr->overlay_parent
&& gr->overlay_parent->overlay_enable && !gr->overlay_enable) ) {
@@ -819,6 +821,8 @@ static struct graphics_methods graphics_methods = {
NULL, /* set_attr */
NULL, /* show_native_keyboard */
NULL, /* hide_native_keyboard */
+ NULL, /* get_dpi */
+ draw_polygon_with_holes
};
static struct graphics_priv *overlay_new(struct graphics_priv *gr, struct graphics_methods *meth, struct point *p,
diff --git a/navit/graphics/sdl/raster.c b/navit/graphics/sdl/raster.c
index 6c713844b..8da7cd9a1 100644
--- a/navit/graphics/sdl/raster.c
+++ b/navit/graphics/sdl/raster.c
@@ -16,6 +16,7 @@
#include <math.h>
+#include <glib.h>
#include "raster.h"
@@ -1953,8 +1954,8 @@ void raster_aapolygon(SDL_Surface *dst, int16_t n, int16_t *vx, int16_t *vy, uin
o = p = -1;
}
#else
-
raster_hline(dst, xa+1, xb, y, color);
+
#endif
// raster_rect_inline(dst, xa, y, xb - xa, 1, color);
@@ -1962,3 +1963,199 @@ void raster_aapolygon(SDL_Surface *dst, int16_t n, int16_t *vx, int16_t *vy, uin
}
}
+/**
+ * @brief render filled polygon with holes by raycasting along the y axis
+ *
+ * This function renders a filled polygon that can have holes by SDL primitive
+ * graphic functions by raycasting along the y axis. This works basically the same
+ * as for complex polygons. Only difference is the "holes" are individual
+ * polygon loops not connected to the outer loop.
+ * FIXME: This draws well as long as the "hole" does not intersect with the
+ * outer polygon. However such multipolygons are seen a mapping error in OSM
+ * and therefore the rendering err may even help in detecting them.
+ * But this could be fixed by never starting a line on a vertex that came from a
+ * hole intersection.
+ *
+ * @param s SDL surface to draw on
+ * @param p Array of points containing the outer polygon
+ * @param count Number of points in outer polygon
+ * @param hole_count Number of hole polygons
+ * @param ccount number of points per hole polygon
+ * @oaram holes array of point arrays. One for each "hole"
+ * @param col Color to draw this.
+ */
+void raster_aapolygon_with_holes (SDL_Surface *s, struct point *p, int count, int hole_count, int* ccount,
+ struct point **holes, uint32_t col) {
+ int i;
+ struct point * p1;
+ struct point * p2;
+ /* Check visibility of clipping rectangle */
+ if ((s->clip_rect.w==0) || (s->clip_rect.h==0)) {
+ return;
+ }
+
+ /* Sanity check number of edges */
+ if (count < 3) {
+ return;
+ }
+ /*
+ * Draw antialiased outline
+ */
+ p1 = p2 = p;
+ p2++;
+ for (i = 1; i < count; i++) {
+ raster_aalineColorInt(s, p1->x, p1->y, p2->x, p2->y, col, 0);
+ p1 = p2;
+ p2++;
+ }
+ raster_aalineColorInt(s, p1->x, p1->y, p->x, p->y, col, 0);
+ raster_polygon_with_holes(s, p, count, hole_count, ccount, holes, col);
+}
+
+/**
+ * @brief render filled polygon with holes by raycasting along the y axis
+ *
+ * This function renders a filled polygon that can have holes by SDL primitive
+ * graphic functions by raycasting along the y axis. This works basically the same
+ * as for complex polygons. Only difference is the "holes" are individual
+ * polygon loops not connected to the outer loop.
+ * FIXME: This draws well as long as the "hole" does not intersect with the
+ * outer polygon. However such multipolygons are seen a mapping error in OSM
+ * and therefore the rendering err may even help in detecting them.
+ * But this could be fixed by never starting a line on a vertex that came from a
+ * hole intersection.
+ *
+ * @param s SDL surface to draw on
+ * @param p Array of points containing the outer polygon
+ * @param count Number of points in outer polygon
+ * @param hole_count Number of hole polygons
+ * @param ccount number of points per hole polygon
+ * @oaram holes array of point arrays. One for each "hole"
+ * @param col Color to draw this.
+ */
+void raster_polygon_with_holes (SDL_Surface *s, struct point *p, int count, int hole_count, int* ccount,
+ struct point **holes, uint32_t col) {
+ int vertex_max;
+ int vertex_count;
+ int * vertexes;
+ int miny, maxy;
+ int i;
+ int y;
+
+ /* Check visibility of clipping rectangle */
+ if ((s->clip_rect.w==0) || (s->clip_rect.h==0)) {
+ return;
+ }
+
+ /* Sanity check number of edges */
+ if (count < 3) {
+ return;
+ }
+
+ /*
+ * Prepare a buffer for vertexes. Maximum number of vertexes is the number of points
+ * of polygon and holes
+ */
+ vertex_max = count;
+ for(i =0; i < hole_count; i ++) {
+ vertex_max += ccount[i];
+ }
+ vertexes = g_malloc(sizeof(int) * vertex_max);
+ if(vertexes == NULL) {
+ return;
+ }
+
+ /* calculate y min and max coordinate. We can ignore the holes, as we won't render hole
+ * parts "bigger" than the surrounding polygon.*/
+ miny = p[0].y;
+ maxy = p[0].y;
+ for (i = 1; (i < count); i++) {
+ if (p[i].y < miny) {
+ miny = p[i].y;
+ } else if (p[i].y > maxy) {
+ maxy = p[i].y;
+ }
+ }
+
+ /* scan y coordinates from miny to maxy */
+ for(y = miny; y <= maxy ; y ++) {
+ int h;
+ vertex_count=0;
+ /* calculate the intersecting points of the polygon with current y and add to vertexes array*/
+ for (i = 0; (i < count); i++) {
+ int ind1;
+ int ind2;
+ struct point p1;
+ struct point p2;
+
+ if (!i) {
+ ind1 = count - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ p1.y = p[ind1].y;
+ p2.y = p[ind2].y;
+ if (p1.y < p2.y) {
+ p1.x = p[ind1].x;
+ p2.x = p[ind2].x;
+ } else if (p1.y > p2.y) {
+ p2.y = p[ind1].y;
+ p1.y = p[ind2].y;
+ p2.x = p[ind1].x;
+ p1.x = p[ind2].x;
+ } else {
+ continue;
+ }
+ if ( ((y >= p1.y) && (y < p2.y)) || ((y == maxy) && (y > p1.y) && (y <= p2.y)) ) {
+ vertexes[vertex_count++] = ((65536 * (y - p1.y)) / (p2.y - p1.y)) * (p2.x - p1.x) + (65536 * p1.x);
+ }
+ }
+ for(h= 0; h < hole_count; h ++) {
+ /* add the intersecting points from the holes as well */
+ for (i = 0; (i < ccount[h]); i++) {
+ int ind1;
+ int ind2;
+ struct point p1;
+ struct point p2;
+
+ if (!i) {
+ ind1 = ccount[h] - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ p1.y = holes[h][ind1].y;
+ p2.y = holes[h][ind2].y;
+ if (p1.y < p2.y) {
+ p1.x = holes[h][ind1].x;
+ p2.x = holes[h][ind2].x;
+ } else if (p1.y > p2.y) {
+ p2.y = holes[h][ind1].y;
+ p1.y = holes[h][ind2].y;
+ p2.x = holes[h][ind1].x;
+ p1.x = holes[h][ind2].x;
+ } else {
+ continue;
+ }
+ if ( ((y >= p1.y) && (y < p2.y)) || ((y == maxy) && (y > p1.y) && (y <= p2.y)) ) {
+ vertexes[vertex_count++] = ((65536 * (y - p1.y)) / (p2.y - p1.y)) * (p2.x - p1.x) + (65536 * p1.x);
+ }
+ }
+ }
+
+ /* sort the vertexes */
+ qsort(vertexes, vertex_count, sizeof(int), gfxPrimitivesCompareInt);
+ /* draw the lines between every second vertex */
+ for (i = 0; (i < vertex_count); i +=2) {
+ Sint16 xa;
+ Sint16 xb;
+ xa = (vertexes[i] >> 16);
+ xb = (vertexes[i+1] >> 16);
+ raster_hline(s, xa+1, xb, y, col);
+ }
+ }
+ g_free(vertexes);
+}
diff --git a/navit/graphics/sdl/raster.h b/navit/graphics/sdl/raster.h
index 2e68ea05f..e295f23fb 100644
--- a/navit/graphics/sdl/raster.h
+++ b/navit/graphics/sdl/raster.h
@@ -10,15 +10,21 @@
#include <stdint.h>
#include "SDL.h"
+#include "point.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_polygon_with_holes (SDL_Surface *s, struct point *p, int count, int hole_count, int* ccount,
+ struct point **holes, 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);
+void raster_aapolygon_with_holes (SDL_Surface *s, struct point *p, int count, int hole_count, int* ccount,
+ struct point **holes, uint32_t col);
+
#endif /* __RASTER_H */
diff --git a/navit/graphics/win32/graphics_win32.c b/navit/graphics/win32/graphics_win32.c
index 6bcad3be6..6346e59f7 100644
--- a/navit/graphics/win32/graphics_win32.c
+++ b/navit/graphics/win32/graphics_win32.c
@@ -829,8 +829,177 @@ static void draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc,
#if HAVE_API_WIN32_CE
/*
- * Windows CE doesn't support PaintPath used for other versions. No polygon with holes support for CE yet.
+ * Windows CE doesn't feature GraphicsPath, so in order to draw filled polygons
+ * with holes, we need to resort on manual raycasting. The following functions
+ * have been inspired from SDL backend that does need to raycast all polygons.
*/
+
+/* Helper qsort callback for polygon drawing */
+static int gfxPrimitivesCompareInt(const void *a, const void *b) {
+ return (*(const int *) a) - (*(const int *) b);
+}
+
+/**
+ * @brief render filled polygon with holes by raycasting along the y axis
+ *
+ * This function renders a filled polygon that can have holes by SDL primitive
+ * graphic functions by raycasting along the y axis. This works basically the same
+ * as for complex polygons. Only difference is the "holes" are individual
+ * polygon loops not connected to the outer loop.
+ * FIXME: This draws well as long as the "hole" does not intersect with the
+ * outer polygon. However such multipolygons are seen a mapping error in OSM
+ * and therefore the rendering err may even help in detecting them.
+ * But this could be fixed by never starting a line on a vertex that came from a
+ * hole intersection.
+ *
+ * @param gr graphics instance
+ * @param gc graphics context
+ * @param p Array of points for the outer polygon
+ * @param count Number of points in outer polygon
+ * @param hole_count Number of hole polygons
+ * @param ccount number of points per hole polygon
+ * @oaram holes array of point arrays. One for each "hole"
+ */
+static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
+ int hole_count, int* ccount, struct point **holes) {
+ int vertex_max;
+ int vertex_count;
+ int * vertexes;
+ int miny, maxy;
+ int i;
+ int y;
+ HPEN holdpen;
+ HBRUSH holdbrush;
+ HPEN linepen;
+
+ /* Sanity check number of edges */
+ if (count < 3) {
+ return;
+ }
+
+ /*
+ * Prepare a buffer for vertexes. Maximum number of vertexes is the number of points
+ * of polygon and holes
+ */
+ vertex_max = count;
+ for(i =0; i < hole_count; i ++) {
+ vertex_max += ccount[i];
+ }
+ vertexes = g_malloc(sizeof(int) * vertex_max);
+ if(vertexes == NULL) {
+ return;
+ }
+
+ /* create pen to draw the lines */
+ linepen = CreatePen( PS_SOLID, 1, gc->fg_color );
+
+ /* remeber pen and brush */
+ holdpen = SelectObject( gr->hMemDC, linepen );
+ holdbrush = SelectObject( gr->hMemDC, gc->hbrush );
+
+ /* calculate y min and max coordinate. We can ignore the holes, as we won't render hole
+ * parts "bigger" than the surrounding polygon.*/
+ miny = p[0].y;
+ maxy = p[0].y;
+ for (i = 1; (i < count); i++) {
+ if (p[i].y < miny) {
+ miny = p[i].y;
+ } else if (p[i].y > maxy) {
+ maxy = p[i].y;
+ }
+ }
+
+ /* scan y coordinates from miny to maxy */
+ for(y = miny; y <= maxy ; y ++) {
+ int h;
+ vertex_count=0;
+ /* calculate the intersecting points of the polygon with current y and add to vertexes array*/
+ for (i = 0; (i < count); i++) {
+ int ind1;
+ int ind2;
+ struct point p1;
+ struct point p2;
+
+ if (!i) {
+ ind1 = count - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ p1.y = p[ind1].y;
+ p2.y = p[ind2].y;
+ if (p1.y < p2.y) {
+ p1.x = p[ind1].x;
+ p2.x = p[ind2].x;
+ } else if (p1.y > p2.y) {
+ p2.y = p[ind1].y;
+ p1.y = p[ind2].y;
+ p2.x = p[ind1].x;
+ p1.x = p[ind2].x;
+ } else {
+ continue;
+ }
+ if ( ((y >= p1.y) && (y < p2.y)) || ((y == maxy) && (y > p1.y) && (y <= p2.y)) ) {
+ vertexes[vertex_count++] = ((65536 * (y - p1.y)) / (p2.y - p1.y)) * (p2.x - p1.x) + (65536 * p1.x);
+ }
+ }
+ for(h= 0; h < hole_count; h ++) {
+ /* add the intersecting points from the holes as well */
+ for (i = 0; (i < ccount[h]); i++) {
+ int ind1;
+ int ind2;
+ struct point p1;
+ struct point p2;
+
+ if (!i) {
+ ind1 = ccount[h] - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ p1.y = holes[h][ind1].y;
+ p2.y = holes[h][ind2].y;
+ if (p1.y < p2.y) {
+ p1.x = holes[h][ind1].x;
+ p2.x = holes[h][ind2].x;
+ } else if (p1.y > p2.y) {
+ p2.y = holes[h][ind1].y;
+ p1.y = holes[h][ind2].y;
+ p2.x = holes[h][ind1].x;
+ p1.x = holes[h][ind2].x;
+ } else {
+ continue;
+ }
+ if ( ((y >= p1.y) && (y < p2.y)) || ((y == maxy) && (y > p1.y) && (y <= p2.y)) ) {
+ vertexes[vertex_count++] = ((65536 * (y - p1.y)) / (p2.y - p1.y)) * (p2.x - p1.x) + (65536 * p1.x);
+ }
+ }
+ }
+
+ /* sort the vertexes */
+ qsort(vertexes, vertex_count, sizeof(int), gfxPrimitivesCompareInt);
+ /* draw the lines between every second vertex */
+ for (i = 0; (i < vertex_count); i +=2) {
+ int xa;
+ int xb;
+ xa = (vertexes[i] >> 16);
+ xb = (vertexes[i+1] >> 16);
+ MoveToEx( gr->hMemDC, xa+1, y, NULL );
+ LineTo( gr->hMemDC, xb, y );
+ }
+ }
+ /* free vertex buffer */
+ g_free(vertexes);
+
+ /* restore pen and brush */
+ SelectObject( gr->hMemDC, holdbrush);
+ SelectObject( gr->hMemDC, holdpen);
+
+ /* delete linepen */
+ DeleteObject(linepen);
+}
#else
static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
int hole_count, int* ccount, struct point **holes) {
@@ -1522,11 +1691,7 @@ static struct graphics_methods graphics_methods = {
NULL, /* show_native_keyboard */
NULL, /* hide_native_keyboard */
NULL, /* get dpi */
-#if HAVE_API_WIN32_CE
- NULL, /* draw_polygon_with_holes */
-#else
draw_polygon_with_holes
-#endif
};