X-Git-Url: http://pileus.org/git/?p=grits;a=blobdiff_plain;f=src%2Fobjects%2Fgrits-marker.c;h=40d45f4e57fa8ee2363085f276090f993f3b146a;hp=a5cb9c719e3c6d7753bd04c98b15a3eb7ff7a13c;hb=62ea7c94a5ee8d5e17e8bb3b1ff4315253c61f82;hpb=98eee86d69c0ee2aa198270e55b8b815c1914567 diff --git a/src/objects/grits-marker.c b/src/objects/grits-marker.c index a5cb9c7..40d45f4 100644 --- a/src/objects/grits-marker.c +++ b/src/objects/grits-marker.c @@ -31,9 +31,96 @@ */ #include -#include +#include +#include "gtkgl.h" #include "grits-marker.h" +/* Texture setup functions */ +static void render_point(GritsMarker *marker) +{ + /* Draw outline */ + cairo_set_line_join(marker->cairo, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width(marker->cairo, marker->outline*2); + cairo_set_source_rgba(marker->cairo, 0, 0, 0, 1); + + cairo_arc(marker->cairo, marker->xoff, marker->yoff, marker->radius, + 0, 2*G_PI); + cairo_stroke(marker->cairo); + + /* Draw filler */ + cairo_set_source_rgba(marker->cairo, 1, 1, 1, 1); + + cairo_arc(marker->cairo, marker->xoff, marker->yoff, marker->radius, + 0, 2*G_PI); + cairo_fill(marker->cairo); +} + +static void render_label(GritsMarker *marker) +{ + g_assert(marker->label); + + /* Draw outline */ + cairo_set_line_join(marker->cairo, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width(marker->cairo, marker->outline*2); + cairo_set_source_rgba(marker->cairo, 0, 0, 0, 1); + cairo_select_font_face(marker->cairo, "sans-serif", + CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(marker->cairo, 13); + cairo_move_to(marker->cairo, marker->xoff + (marker->icon_width / 2), + marker->yoff - (marker->icon_height / 2)); + cairo_text_path(marker->cairo, marker->label); + cairo_stroke(marker->cairo); + + /* Draw filler */ + cairo_set_source_rgba(marker->cairo, 1, 1, 1, 1); + cairo_move_to(marker->cairo, marker->xoff + (marker->icon_width / 2), + marker->yoff - (marker->icon_height / 2)); + cairo_show_text(marker->cairo, marker->label); +} + +static void render_icon(GritsMarker *marker) +{ + g_assert(marker->icon_img != NULL); + + /* move to marker location */ + cairo_translate(marker->cairo, marker->xoff, marker->yoff); + + /* center image */ + cairo_translate(marker->cairo, -marker->icon_width/2, + -marker->icon_height/2); + + cairo_set_source_surface(marker->cairo, marker->icon_img, 0, 0); + + cairo_paint(marker->cairo); +} + +static void render_all(GritsMarker *marker) +{ + g_assert(marker); + if (marker->display_mask & GRITS_MARKER_DMASK_ICON) + render_icon(marker); + + if (marker->display_mask & GRITS_MARKER_DMASK_POINT) + render_point(marker); + + if (marker->display_mask & GRITS_MARKER_DMASK_LABEL) + render_label(marker); + + /* Load GL texture */ + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &marker->tex); + glBindTexture(GL_TEXTURE_2D, marker->tex); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, 4, marker->width, marker->height, + 0, GL_BGRA, GL_UNSIGNED_BYTE, + cairo_image_surface_get_data(cairo_get_target(marker->cairo))); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +} + + +/* Constructors */ /** * grits_marker_new: * @label: a short description of the marker @@ -44,84 +131,157 @@ */ GritsMarker *grits_marker_new(const gchar *label) { + GritsMarker *marker = g_object_new(GRITS_TYPE_MARKER, NULL); + + GRITS_OBJECT(marker)->skip = GRITS_SKIP_CENTER; + + marker->display_mask = GRITS_MARKER_DMASK_POINT | + GRITS_MARKER_DMASK_LABEL; + //g_debug("GritsMarker: new - %s", label); - static const gdouble OUTLINE = 2; - static const gdouble RADIUS = 3; - static const gdouble WIDTH = 128; - static const gdouble HEIGHT = 32; + /* specify size of point and size of surface */ + marker->outline = 2; + marker->radius = 3; + marker->width = 128; + marker->height = 32; + marker->icon_width = marker->radius * 2; + marker->icon_height = marker->radius * 3; + + marker->xoff = marker->radius+marker->outline; + marker->yoff = marker->height-(marker->radius+marker->outline); + marker->cairo = cairo_create(cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, marker->width, marker->height)); + + marker->label = g_strdup(label); + + return marker; +} +/** + * grits_marker_icon_new: + * @label: The label to display if GRITS_MARKER_DMASK_LABEL is set + * @filename: The filename of the icon + * @angle: The angle to rotate the icon (0 is north) + * @flip: Whether to flip the image so that it's never upside down. + * Useful for non-symmetric icons which have an "up". + * @display_mask: A bitmask which specifies which items to display. + * + * Create a new marker with a label, point, icon (png), or any + * combination of the above. + * + * Returns: the new #GritsMarker + */ +GritsMarker *grits_marker_icon_new(const gchar *label, const gchar *filename, + guint angle, gboolean flip, guint display_mask) +{ GritsMarker *marker = g_object_new(GRITS_TYPE_MARKER, NULL); - marker->xoff = RADIUS+OUTLINE; - marker->yoff = HEIGHT-(RADIUS+OUTLINE); + marker->label = g_strdup(label); - marker->cairo = cairo_create(cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT)); + marker->angle = angle; + marker->flip = flip; + marker->display_mask = display_mask; - cairo_select_font_face(marker->cairo, "sans-serif", - CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size(marker->cairo, 13); + if (display_mask & GRITS_MARKER_DMASK_ICON) { + g_assert(filename != NULL); + g_debug("GritsMarker: marker_icon_new - marker image %s", + filename); + marker->icon_img = cairo_image_surface_create_from_png(filename); + if (cairo_surface_status(marker->icon_img)) { + g_warning("GritsMarker: marker_icon_new - " + "error reading file %s", filename); + /* convert it to a point, better than nothing */ + marker->display_mask &= ~GRITS_MARKER_DMASK_ICON; + marker->display_mask |= GRITS_MARKER_DMASK_POINT; + marker->icon_width = 4; + marker->icon_height = 8; - /* Draw outline */ - cairo_set_source_rgba(marker->cairo, 0, 0, 0, 1); - cairo_set_line_width(marker->cairo, OUTLINE*2); + } else { + marker->icon_width = + cairo_image_surface_get_width(marker->icon_img); + marker->icon_height = + cairo_image_surface_get_height(marker->icon_img); + } + } else { + marker->icon_img = NULL; + marker->icon_width = 4; /* room for the point if there is one */ + marker->icon_height = 8; + } + g_debug("GritsMarker: marker_icon_new - width = %d, height = %d", + marker->icon_width, marker->icon_height); - cairo_arc(marker->cairo, marker->xoff, marker->yoff, RADIUS, 0, 2*G_PI); - cairo_stroke(marker->cairo); + marker->outline = 2; + marker->radius = 3; - cairo_move_to(marker->cairo, marker->xoff+4, marker->yoff-8); - cairo_text_path(marker->cairo, marker->label); - cairo_stroke(marker->cairo); + /* this is the surface size, a guess really */ + marker->width = marker->icon_width + 128; + marker->height = marker->icon_height + 64; - /* Draw filler */ - cairo_set_source_rgba(marker->cairo, 1, 1, 1, 1); + marker->xoff = marker->width/2; + marker->yoff = marker->height/2; + marker->cairo = cairo_create(cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, marker->width, marker->height)); - cairo_arc(marker->cairo, marker->xoff, marker->yoff, RADIUS, 0, 2*G_PI); - cairo_fill(marker->cairo); + /* clear the surface just in case */ + cairo_set_operator(marker->cairo, CAIRO_OPERATOR_SOURCE); + //cairo_set_source_rgba(marker->cairo, 1.0, 0.0, 0.0, 0.3); // debug + cairo_set_source_rgba(marker->cairo, 1.0, 0.0, 0.0, 0.0); + cairo_paint(marker->cairo); + cairo_set_operator(marker->cairo, CAIRO_OPERATOR_OVER); - cairo_move_to(marker->cairo, marker->xoff+4, marker->yoff-8); - cairo_show_text(marker->cairo, marker->label); + render_all(marker); - /* Load GL texture */ - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &marker->tex); - glBindTexture(GL_TEXTURE_2D, marker->tex); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, 4, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, - cairo_image_surface_get_data(cairo_get_target(marker->cairo))); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (marker->icon_img) + cairo_surface_destroy(marker->icon_img); return marker; } + /* Drawing */ static void grits_marker_draw(GritsObject *_marker, GritsOpenGL *opengl) { GritsMarker *marker = GRITS_MARKER(_marker); GritsPoint *point = grits_object_center(marker); - gdouble px, py, pz; - grits_viewer_project(GRITS_VIEWER(opengl), - point->lat, point->lon, point->elev, - &px, &py, &pz); - - gint win_width = GTK_WIDGET(opengl)->allocation.width; - gint win_height = GTK_WIDGET(opengl)->allocation.height; - py = win_height - py; - if (pz > 1) - return; - - //g_debug("GritsOpenGL: draw_marker - %s pz=%f ", marker->label, pz); cairo_surface_t *surface = cairo_get_target(marker->cairo); gdouble width = cairo_image_surface_get_width(surface); gdouble height = cairo_image_surface_get_height(surface); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glOrtho(0, win_width, win_height, 0, -1, 1); - glTranslated(px - marker->xoff, - py - marker->yoff, 0); + if (!marker->tex) + render_all(marker); + + if (marker->ortho) { + gdouble px, py, pz; + grits_viewer_project(GRITS_VIEWER(opengl), + point->lat, point->lon, point->elev, + &px, &py, &pz); + + if (pz > 1) + return; + + GtkAllocation alloc; + gtk_widget_get_allocation(GTK_WIDGET(opengl), &alloc); + glTranslated(px, alloc.height-py, 0); + glRotatef(marker->angle, 0, 0, -1); + glTranslated(-marker->xoff, -marker->yoff, 0); + } else { + gdouble scale, eye[3], pos[3] = + {point->lat, point->lon, point->elev}; + grits_viewer_get_location(GRITS_VIEWER(opengl), + &eye[0], &eye[1], &eye[2]); + lle2xyz(eye[0], eye[1], eye[2], + &eye[0], &eye[1], &eye[2]); + lle2xyz(pos[0], pos[1], pos[2], + &pos[0], &pos[1], &pos[2]); + scale = MPPX(distd(eye, pos)); + + glRotatef(marker->angle, 0, 0, -1); + glRotatef(180, 1, 0, 0); + glScalef(scale, scale, 1); + glTranslated(-marker->xoff, -marker->yoff, 0); + } + + //g_debug("GritsOpenGL: draw_marker - %s pz=%f ", marker->label, pz); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); @@ -130,29 +290,33 @@ static void grits_marker_draw(GritsObject *_marker, GritsOpenGL *opengl) glBindTexture(GL_TEXTURE_2D, marker->tex); glDisable(GL_CULL_FACE); glBegin(GL_QUADS); - glTexCoord2f(1, 0); glVertex3f(width, 0 , 0); - glTexCoord2f(1, 1); glVertex3f(width, height, 0); - glTexCoord2f(0, 1); glVertex3f(0 , height, 0); - glTexCoord2f(0, 0); glVertex3f(0 , 0 , 0); + glTexCoord2f(1, 0); glVertex3f(width, 0 , 0); // 0 - 3 0 + glTexCoord2f(1, 1); glVertex3f(width, height, 0); // 1 - | | + glTexCoord2f(0, 1); glVertex3f(0 , height, 0); // 2 - | | + glTexCoord2f(0, 0); glVertex3f(0 , 0 , 0); // 3 - 2----1 glEnd(); } + /* GObject code */ G_DEFINE_TYPE(GritsMarker, grits_marker, GRITS_TYPE_OBJECT); static void grits_marker_init(GritsMarker *marker) { + marker->ortho = TRUE; } static void grits_marker_finalize(GObject *_marker) { //g_debug("GritsMarker: finalize - %s", marker->label); GritsMarker *marker = GRITS_MARKER(_marker); - glDeleteTextures(1, &marker->tex); - cairo_surface_t *surface = cairo_get_target(marker->cairo); - cairo_surface_destroy(surface); - cairo_destroy(marker->cairo); + if (marker->tex) + glDeleteTextures(1, &marker->tex); + if (marker->cairo) { + cairo_surface_t *surface = cairo_get_target(marker->cairo); + cairo_surface_destroy(surface); + cairo_destroy(marker->cairo); + } g_free(marker->label); - glDeleteTextures(1, &marker->tex); } static void grits_marker_class_init(GritsMarkerClass *klass)