X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=src%2Fobjects%2Fgrits-marker.c;h=162e4bbdbac445fd7acf2a918dbc634399339c0a;hb=c69956150a63153bc1ed765a265ca46c1da21374;hp=3073b0f61c2532a1db25c949af7169f714e09cbb;hpb=4bef8517366b0195e321add06250e7d659434661;p=grits diff --git a/src/objects/grits-marker.c b/src/objects/grits-marker.c index 3073b0f..162e4bb 100644 --- a/src/objects/grits-marker.c +++ b/src/objects/grits-marker.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Andy Spencer + * Copyright (C) 2009-2011 Andy Spencer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,70 +16,91 @@ */ /** - * SECTION:gis-marker + * SECTION:grits-marker * @short_description: Single point markers * - * Each #GisMarker represents some point on the earth with some form of + * Each #GritsMarker represents some point on the earth with some form of * content. Commonly this is used to mark geographic features such as cities or * states. * * While markers represent a place in three dimensions somewhere on, below, or * above the surface of the earth, they are drawn in 2 dimensions so that they - * look normal and readable by the user. Due to this, GisObjects should almost - * always be added to the GIS_LEVEL_OVERLAY level so they are drawn "above" the + * look normal and readable by the user. Due to this, GritsObjects should almost + * always be added to the GRITS_LEVEL_OVERLAY level so they are drawn "above" the * actual earth. */ #include -#include -#include "gis-marker.h" +#include +#include "gtkgl.h" +#include "grits-marker.h" -/** - * gis_marker_new: - * @label: a short description of the marker - * - * Create a new GisMarker which shows the given label when drawn. - * - * Returns: the new #GisMarker. - */ -GisMarker *gis_marker_new(const gchar *label) +/* Texture setup functions */ +static void render_point(GritsMarker *marker) { - //g_debug("GisMarker: new - %s", label); - static const gdouble OUTLINE = 2; - static const gdouble RADIUS = 3; - static const gdouble WIDTH = 128; - static const gdouble HEIGHT = 32; - - GisMarker *marker = g_object_new(GIS_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)); - - cairo_select_font_face(marker->cairo, "sans-serif", - CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size(marker->cairo, 13); - /* Draw outline */ cairo_set_source_rgba(marker->cairo, 0, 0, 0, 1); - cairo_set_line_width(marker->cairo, OUTLINE*2); + cairo_set_line_width(marker->cairo, marker->outline*2); - cairo_arc(marker->cairo, marker->xoff, marker->yoff, RADIUS, 0, 2*G_PI); + cairo_arc(marker->cairo, marker->xoff, marker->yoff, marker->radius, + 0, 2*G_PI); cairo_stroke(marker->cairo); - cairo_move_to(marker->cairo, marker->xoff+4, marker->yoff-8); + /* 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); + + 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); +} - cairo_arc(marker->cairo, marker->xoff, marker->yoff, RADIUS, 0, 2*G_PI); - cairo_fill(marker->cairo); +static void render_icon(GritsMarker *marker) +{ + g_assert(marker->icon_img != NULL); - cairo_move_to(marker->cairo, marker->xoff+4, marker->yoff-8); - cairo_show_text(marker->cairo, marker->label); + /* 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); @@ -87,41 +108,174 @@ GisMarker *gis_marker_new(const gchar *label) 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); + 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 + * + * Create a new GritsMarker which shows the given label when drawn. + * + * Returns: the new #GritsMarker. + */ +GritsMarker *grits_marker_new(const gchar *label) +{ + GritsMarker *marker = g_object_new(GRITS_TYPE_MARKER, NULL); + + marker->display_mask = GRITS_MARKER_DMASK_POINT | + GRITS_MARKER_DMASK_LABEL; + + //g_debug("GritsMarker: new - %s", label); + /* 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); + + render_all(marker); return marker; } -/* Drawing */ -static void gis_marker_draw(GisObject *_marker, GisOpenGL *opengl) +/** + * 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) { - GisMarker *marker = GIS_MARKER(_marker); - GisPoint *point = gis_object_center(marker); - gdouble px, py, pz; - gis_viewer_project(GIS_VIEWER(opengl), - point->lat, point->lon, point->elev, - &px, &py, &pz); + GritsMarker *marker = g_object_new(GRITS_TYPE_MARKER, NULL); - gint win_width = GTK_WIDGET(opengl)->allocation.width; - gint win_height = GTK_WIDGET(opengl)->allocation.height; - py = win_height - py; - if (pz > 1) - return; + marker->label = g_strdup(label); + marker->angle = angle; + marker->flip = flip; + marker->display_mask = display_mask; - //g_debug("GisOpenGL: draw_marker - %s pz=%f ", marker->label, pz); + 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; + + } 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); + + marker->outline = 2; + marker->radius = 3; + /* this is the surface size, a guess really */ + marker->width = marker->icon_width + 128; + marker->height = marker->icon_height + 64; + + 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)); + /* 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); + + render_all(marker); + + 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); 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->ortho) { + 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; + if (pz > 1) + return; + + glMatrixMode(GL_PROJECTION); glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + glOrtho(0, win_width, win_height, 0, 1, -1); + glTranslated(px, win_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,36 +284,39 @@ static void gis_marker_draw(GisObject *_marker, GisOpenGL *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(GisMarker, gis_marker, GIS_TYPE_OBJECT); -static void gis_marker_init(GisMarker *marker) +G_DEFINE_TYPE(GritsMarker, grits_marker, GRITS_TYPE_OBJECT); +static void grits_marker_init(GritsMarker *marker) { + marker->ortho = TRUE; } -static void gis_marker_finalize(GObject *_marker) +static void grits_marker_finalize(GObject *_marker) { - //g_debug("GisMarker: finalize - %s", marker->label); - GisMarker *marker = GIS_MARKER(_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); g_free(marker->label); + glDeleteTextures(1, &marker->tex); } -static void gis_marker_class_init(GisMarkerClass *klass) +static void grits_marker_class_init(GritsMarkerClass *klass) { - g_debug("GisMarker: class_init"); + g_debug("GritsMarker: class_init"); GObjectClass *gobject_class = G_OBJECT_CLASS(klass); - gobject_class->finalize = gis_marker_finalize; + gobject_class->finalize = grits_marker_finalize; - GisObjectClass *object_class = GIS_OBJECT_CLASS(klass); - object_class->draw = gis_marker_draw; + GritsObjectClass *object_class = GRITS_OBJECT_CLASS(klass); + object_class->draw = grits_marker_draw; }