diff options
Diffstat (limited to 'navit/graphics.c')
-rw-r--r-- | navit/graphics.c | 404 |
1 files changed, 306 insertions, 98 deletions
diff --git a/navit/graphics.c b/navit/graphics.c index 40e04bb06..172315488 100644 --- a/navit/graphics.c +++ b/navit/graphics.c @@ -1099,6 +1099,47 @@ static void graphics_draw_polygon(struct graphics *gra, struct graphics_gc *gc, } } +/** + * @brief Draw a plain polygon with holes on the display + * + * @param gra The graphics instance on which to draw + * @param gc The graphics context + * @param[in] pin An array of points forming the polygon + * @param count_in The number of elements inside @p pin + * @param hole_count The number of hole polygons to cut out + * @param pcount array of [hole_count] integers giving the number of + * points per hole + * @param holes array of point arrays for the hole polygons + */ +static void graphics_draw_polygon_with_holes(struct graphics *gra, struct graphics_gc *gc, struct point *pin, + int count_in, int hole_count, int* ccount, struct point **holes) { + if (! gra->meth.draw_polygon_with_holes) { + /* TODO: add attr to configure if polygons with holes should be drawn without + * the holes if no graphics support for this is present. + */ + graphics_draw_polygon(gra, gc, pin, count_in); + return; + } else { + struct point * pin_scaled = g_alloca(sizeof (struct point)*count_in); + struct point ** holes_scaled = g_alloca(sizeof (struct point *)*hole_count); + int a; + int b; + /* scale the outline */ + for(a=0; a < count_in; a ++) + pin_scaled[a] = graphics_dpi_scale_point(gra,&(pin[a])); + /*scale the holes */ + for(b=0; b < hole_count; b ++) { + holes_scaled[b] = g_malloc(sizeof(*(holes_scaled[b])) * ccount[b]); + for(a=0; a < ccount[b]; a ++) + holes_scaled[b][a] = graphics_dpi_scale_point(gra,&(holes[b][a])); + } + gra->meth.draw_polygon_with_holes(gra->priv, gc->priv, pin_scaled, count_in, hole_count, ccount, holes_scaled); + /* free the hole arrays */ + for(b=0; b < hole_count; b ++) + g_free(holes_scaled[b]); + } +} + void graphics_draw_rectangle_rounded(struct graphics *this_, struct graphics_gc *gc, struct point *plu, int w, int h, int r, int fill) { struct point *p=g_alloca(sizeof(struct point)*(r*4+32)); @@ -1304,16 +1345,26 @@ int graphics_hide_native_keyboard (struct graphics *this_, struct graphics_keybo #include "popup.h" #include <stdio.h> +struct displayitem_poly_holes { + int count; + int *ccount; + struct coord ** coords; +}; + /** - * FIXME - * @param <> - * @returns <> - * @author Martin Schaller (04/2008) + * @brief graphics display item structure + * + * The graphics item passes the ap items and other items with this structure + * to the graphics drawing routines. The struct is only a stub. It is allocated + * including "count -1" struct coord's following c[0], if "holes" not NULL, by a + * polygon hole structure, and if label != NULL, a series of zero terminated + * strings followed by another zero for label. */ struct displayitem { struct displayitem *next; struct item item; char *label; + struct displayitem_poly_holes * holes; int z_order; int count; struct coord c[0]; @@ -1339,6 +1390,35 @@ static void xdisplay_free(struct displaylist *dl) { } /** + * @brief add the holes structure into preallocated area after displayitem + * + * @param item to extract holes from + * @param hole_count precounted number of holes + * @param p changeable pointer to buffer. Advanced by the size used + * @returns pointer to newly created holes structure + */ +static inline struct displayitem_poly_holes * display_add_holes(struct item *item,int hole_count, char ** p) { + struct attr attr; + struct displayitem_poly_holes* holes; + holes=(struct displayitem_poly_holes *) *p; + *p+=sizeof(*holes); + holes->count=0; + holes->ccount = (int *) *p; + *p+=hole_count * sizeof(int); + holes->coords = (struct coord **)*p; + *p+=hole_count * sizeof(struct coord *); + item_attr_rewind(item); + while(item_attr_get(item, attr_poly_hole, &attr)) { + holes->coords[holes->count] = (struct coord *)*p; + holes->ccount[holes->count] = attr.u.poly_hole->coord_count; + memcpy(holes->coords[holes->count], attr.u.poly_hole->coord, holes->ccount[holes->count] * sizeof(struct coord)); + *p += holes->ccount[holes->count] * sizeof(struct coord); + holes->count ++; + } + return holes; +} + +/** * FIXME * @param <> * @returns <> @@ -1349,8 +1429,15 @@ static void display_add(struct hash_entry *entry, struct item *item, int count, struct displayitem *di; int len,i; char *p; + struct attr attr; + int hole_count=0; + int hole_total_coords=0; + int holes_length; + /* calculate number of bytes required */ + /* own length */ len=sizeof(*di)+count*sizeof(*c); + /* add length of lables including closing zero */ if (label && label_count) { for (i = 0 ; i < label_count ; i++) { if (label[i]) @@ -1359,12 +1446,28 @@ static void display_add(struct hash_entry *entry, struct item *item, int count, len++; } } + /* add length for holes */ + item_attr_rewind(item); + while(item_attr_get(item, attr_poly_hole, &attr)) { + hole_count ++; + hole_total_coords += attr.u.poly_hole->coord_count; + } + holes_length = sizeof(struct displayitem_poly_holes) + hole_count * sizeof(int) + hole_count * sizeof( + struct coord *) + hole_total_coords * sizeof(struct coord); + if(hole_count > 0) + dbg(lvl_debug,"got %d holes with %d coords total", hole_count, hole_total_coords); + len += holes_length; + p=g_malloc(len); di=(struct displayitem *)p; p+=sizeof(*di)+count*sizeof(*c); di->item=*item; di->z_order=0; + di->holes=NULL; + if(hole_count > 0) { + di->holes = display_add_holes(item, hole_count, &p); + } if (label && label_count) { di->label=p; for (i = 0 ; i < label_count ; i++) { @@ -2230,6 +2333,180 @@ static void multiline_label_draw(struct graphics *gra, struct graphics_gc *fg, s g_free(input_label); } +/** + * @brief coordnate transfor hole coordinates + * + * This function transform a whole set of polygon holes. It therefore allocates memory + * attached to a displayitem_poly_holes structure and call transform + * + * @param trans transformation to be used + * @param pro projection to be used + * @param in filled holes structure to transform + * @param out structure to place result in. Remember to deallocate! + * @param mindist minimal distance between points + */ +static inline void displayitem_transform_holes(struct transformation *trans, enum projection pro, + struct displayitem_poly_holes * in, struct displayitem_poly_holes * out, int mindist) { + if(out == NULL) + return; + out->count = 0; + out->ccount=NULL; + out->coords=NULL; + if((in != NULL) && (in->count > 0)) { + int a; + /* alloc space for hole conversion. To be freed with displayitem_free_holes later*/ + out->count = in->count; + out->ccount = g_malloc0(sizeof(*(out->ccount)) * in->count); + out->coords = g_malloc0(sizeof(*(out->coords)) * in->count); + for(a = 0; a < in->count; a ++) { + in->ccount[a]=limit_count(in->coords[a], in->ccount[a]); + out->coords[a]=g_malloc0(sizeof(*(out->coords[a])) * in->ccount[a]); + out->ccount[a]=transform(trans, pro, in->coords[a], (struct point *)(out->coords[a]), in->ccount[a], mindist, 0, NULL); + } + } +} + +/** + * @brief free hole structure allocated by displayitem_transform_holes + * + * @param holes structure to deallocate + */ +static void displayitem_free_holes(struct displayitem_poly_holes * holes) { + if(holes == NULL) + return; + if(holes->count > 0) { + int a; + for(a=0; a < holes->count; a ++) { + g_free(holes->coords[a]); + } + g_free(holes->ccount); + g_free(holes->coords); + } +} + + +static inline void displayitem_draw_polygon (struct display_context * dc, struct graphics * gra, struct point * pa, + int count, struct displayitem_poly_holes * holes) { + /*TODO: implement a "clipped" version of graphics_draw_polygon_with_holes*/ + if((holes != NULL) && (holes->count > 0)) + graphics_draw_polygon_with_holes(gra, dc->gc, pa, count, holes->count, holes->ccount, (struct point **)holes->coords); + else + graphics_draw_polygon_clipped(gra, dc->gc, pa, count); +} + +static inline void displayitem_draw_polyline(struct display_context * dc, struct element * e, struct graphics * gra, + struct point * pa, int count, int *width) { + int i; + graphics_gc_set_linewidth(dc->gc, 1); + if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0) + graphics_gc_set_dashes(dc->gc, e->u.polyline.width, e->u.polyline.offset, e->u.polyline.dash_table, + e->u.polyline.dash_num); + for (i = 0 ; i < count ; i++) { + if (width[i] < 2) + width[i]=2; + } + graphics_draw_polyline_clipped(gra, dc->gc, pa, count, width, e->u.polyline.width > 1); +} + +static inline void displayitem_draw_circle(struct displayitem *di,struct display_context *dc, struct element * e, + struct graphics * gra, struct point * pa, int count) { + if (count) { + if (e->u.circle.width > 1) + graphics_gc_set_linewidth(dc->gc, e->u.polyline.width); + graphics_draw_circle(gra, dc->gc, pa, e->u.circle.radius); + if (di->label && e->text_size) { + struct graphics_font *font=get_font(gra, e->text_size); + struct graphics_gc *gc_background=dc->gc_background; + if (! gc_background && e->u.circle.background_color.a) { + gc_background=graphics_gc_new(gra); + graphics_gc_set_foreground(gc_background, &e->u.circle.background_color); + dc->gc_background=gc_background; + } + if (font) { + struct point p; + /* Set p to the center of the circle */ + p.x=pa[0].x+(e->u.circle.radius/2); + p.y=pa[0].y+(e->u.circle.radius/2); + multiline_label_draw(gra, dc->gc, gc_background, font, p, di->label, e->text_size+1); + } else + dbg(lvl_error,"Failed to get font with size %d",e->text_size); + } + } +} + +static inline void displayitem_draw_text(struct displayitem *di,struct display_context *dc, struct element * e, + struct graphics * gra, struct point * pa, int count, struct displayitem_poly_holes * holes) { + if (count && di->label) { + struct graphics_font *font=get_font(gra, e->text_size); + struct graphics_gc *gc_background=dc->gc_background; + if (! gc_background && e->u.text.background_color.a) { + gc_background=graphics_gc_new(gra); + graphics_gc_set_foreground(gc_background, &e->u.text.background_color); + dc->gc_background=gc_background; + } + if (font) { + int a; + label_line(gra, dc->gc, gc_background, font, pa, count, di->label); + if(holes != NULL) { + for(a = 0; a < holes->count; a ++) + label_line(gra, dc->gc, gc_background, font, (struct point *)holes->coords[a], holes->ccount[a], di->label); + } + } else + dbg(lvl_error,"Failed to get font with size %d",e->text_size); + } +} + +static inline void displayitem_draw_icon(struct displayitem *di,struct display_context *dc, struct element * e, + struct graphics * gra, struct point * pa, int count) { + if (count) { + struct graphics_image *img=dc->img; + if (!img || item_is_custom_poi(di->item)) { + char *path; + if (item_is_custom_poi(di->item)) { + char *icon; + char *src; + if (img) + graphics_image_free(dc->gra, img); + src=e->u.icon.src; + if (!src || !src[0]) + src="%s"; + icon=g_strdup_printf(src,di->label+strlen(di->label)+1); + path=graphics_icon_path(icon); + g_free(icon); + } else + path=graphics_icon_path(e->u.icon.src); + img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation); + if (img) + dc->img=img; + else + dbg(lvl_debug,"failed to load icon '%s'", path); + g_free(path); + } + if (img) { + struct point p; + if (e->u.icon.x != -1 || e->u.icon.y != -1) { + p.x=pa[0].x - e->u.icon.x; + p.y=pa[0].y - e->u.icon.y; + } else { + p.x=pa[0].x - img->hot.x; + p.y=pa[0].y - img->hot.y; + } + graphics_draw_image(gra, gra->gc[0], &p, img); + } + } +} + +static inline void displayitem_draw_image (struct displayitem *di, struct display_context *dc, struct graphics * gra, + struct point * pa, int count) { + dbg(lvl_debug,"image: '%s'", di->label); + struct graphics_image *img=dc->img; + if (gra->meth.draw_image_warp) { + img=graphics_image_new_scaled_rotated(gra, di->label, IMAGE_W_H_UNSET, IMAGE_W_H_UNSET, 0); + if (img) + graphics_draw_image_warp(gra, gra->gc[0], pa, count, img); + } else + dbg(lvl_error,"draw_image_warp not supported by graphics driver drawing '%s'", di->label); +} /** * @brief Draw a displayitem element @@ -2242,25 +2519,30 @@ static void multiline_label_draw(struct graphics *gra, struct graphics_gc *fg, s */ static void displayitem_draw(struct displayitem *di, void *dummy, struct display_context *dc) { int *width=g_alloca(sizeof(int)*dc->maxlen); + int limit=0; struct point *pa=g_alloca(sizeof(struct point)*dc->maxlen); struct graphics *gra=dc->gra; - struct graphics_gc *gc=dc->gc; struct element *e=dc->e; - struct graphics_image *img=dc->img; - struct point p; - char *path; while (di) { - int i,count=di->count,mindist=dc->mindist; + int count=di->count,mindist=dc->mindist; + struct displayitem_poly_holes t_holes; + t_holes.count=0; di->z_order=++(gra->current_z_order); - if (! gc) { - gc=graphics_gc_new(gra); + if (! dc->gc) { + struct graphics_gc * gc=graphics_gc_new(gra); graphics_gc_set_foreground(gc, &e->color); dc->gc=gc; } + if (item_type_is_area(dc->type) && (dc->e->type == element_polyline || dc->e->type == element_text)) + limit = 0; + + displayitem_transform_holes(dc->trans, dc->pro, di->holes, &t_holes, mindist); + + if (limit) count=limit_count(di->c, count); if (dc->type == type_poly_water_tiled) mindist=0; @@ -2270,108 +2552,33 @@ static void displayitem_draw(struct displayitem *di, void *dummy, struct display count=transform(dc->trans, dc->pro, di->c, pa, count, mindist, 0, NULL); switch (e->type) { case element_polygon: - graphics_draw_polygon_clipped(gra, gc, pa, count); + displayitem_draw_polygon(dc, gra, pa, count, &t_holes); + break; + case element_polyline: + displayitem_draw_polyline(dc, e, gra, pa, count, width); break; - case element_polyline: { - graphics_gc_set_linewidth(gc, 1); - if (e->u.polyline.width > 0 && e->u.polyline.dash_num > 0) - graphics_gc_set_dashes(gc, e->u.polyline.width, e->u.polyline.offset, e->u.polyline.dash_table, e->u.polyline.dash_num); - for (i = 0 ; i < count ; i++) { - if (width[i] < 2) - width[i]=2; - } - graphics_draw_polyline_clipped(gra, gc, pa, count, width, e->u.polyline.width > 1); - } - break; case element_circle: - if (count) { - if (e->u.circle.width > 1) - graphics_gc_set_linewidth(gc, e->u.polyline.width); - graphics_draw_circle(gra, gc, pa, e->u.circle.radius); - if (di->label && e->text_size) { - struct graphics_font *font=get_font(gra, e->text_size); - struct graphics_gc *gc_background=dc->gc_background; - if (! gc_background && e->u.circle.background_color.a) { - gc_background=graphics_gc_new(gra); - graphics_gc_set_foreground(gc_background, &e->u.circle.background_color); - dc->gc_background=gc_background; - } - if (font) { - /* Set p to the center of the circle */ - p.x=pa[0].x+(e->u.circle.radius/2); - p.y=pa[0].y+(e->u.circle.radius/2); - multiline_label_draw(gra, gc, gc_background, font, p, di->label, e->text_size+1); - } else - dbg(lvl_error,"Failed to get font with size %d",e->text_size); - } - } + displayitem_draw_circle(di, dc, e, gra, pa, count); break; case element_text: - if (count && di->label) { - struct graphics_font *font=get_font(gra, e->text_size); - struct graphics_gc *gc_background=dc->gc_background; - if (! gc_background && e->u.text.background_color.a) { - gc_background=graphics_gc_new(gra); - graphics_gc_set_foreground(gc_background, &e->u.text.background_color); - dc->gc_background=gc_background; - } - if (font) - label_line(gra, gc, gc_background, font, pa, count, di->label); - else - dbg(lvl_error,"Failed to get font with size %d",e->text_size); - } + displayitem_draw_text(di, dc, e, gra, pa, count, &t_holes); break; case element_icon: - if (count) { - if (!img || item_is_custom_poi(di->item)) { - if (item_is_custom_poi(di->item)) { - char *icon; - char *src; - if (img) - graphics_image_free(dc->gra, img); - src=e->u.icon.src; - if (!src || !src[0]) - src="%s"; - icon=g_strdup_printf(src,di->label+strlen(di->label)+1); - path=graphics_icon_path(icon); - g_free(icon); - } else - path=graphics_icon_path(e->u.icon.src); - img=graphics_image_new_scaled_rotated(gra, path, e->u.icon.width, e->u.icon.height, e->u.icon.rotation); - if (img) - dc->img=img; - else - dbg(lvl_debug,"failed to load icon '%s'", path); - g_free(path); - } - if (img) { - if (e->u.icon.x != -1 || e->u.icon.y != -1) { - p.x=pa[0].x - e->u.icon.x; - p.y=pa[0].y - e->u.icon.y; - } else { - p.x=pa[0].x - img->hot.x; - p.y=pa[0].y - img->hot.y; - } - graphics_draw_image(gra, gra->gc[0], &p, img); - } - } + displayitem_draw_icon(di, dc, e, gra, pa, count); break; case element_image: - dbg(lvl_debug,"image: '%s'", di->label); - if (gra->meth.draw_image_warp) { - img=graphics_image_new_scaled_rotated(gra, di->label, IMAGE_W_H_UNSET, IMAGE_W_H_UNSET, 0); - if (img) - graphics_draw_image_warp(gra, gra->gc[0], pa, count, img); - } else - dbg(lvl_error,"draw_image_warp not supported by graphics driver drawing '%s'", di->label); + displayitem_draw_image (di, dc, gra, pa, count); break; case element_arrows: - display_draw_arrows(gra,gc,pa,count); + display_draw_arrows(gra,dc->gc,pa,count); break; default: dbg(lvl_error, "Unhandled element type %d", e->type); } + /* free space allocated for holes */ + displayitem_free_holes(&t_holes); + di=di->next; } } @@ -2418,6 +2625,7 @@ void graphics_draw_itemgra(struct graphics *gra, struct itemgra *itm, struct tra di->item.map=NULL; di->z_order=0; di->label=label; + di->holes=NULL; dc.gra=gra; dc.gc=NULL; dc.gc_background=NULL; |