[grits] Support pixmap icons in GritsMarker



commit 7cadfa1814f09c99cbd3f2555b0717792a124513
Author: Adam Boggs <boggs-git aircrafter org>
Date:   Thu Feb 9 07:07:38 2012 +0000

    Support pixmap icons in GritsMarker
    
    This adds a second marker constructor that loads a pixmap from a file
    and uses that as the marker.
    
    Rotation angles are also supported so that the marker can be made to
    point in a certain direction.

 src/objects/grits-marker.c |  236 +++++++++++++++++++++++++++++++++++++-------
 src/objects/grits-marker.h |   26 +++++-
 2 files changed, 226 insertions(+), 36 deletions(-)
---
diff --git a/src/objects/grits-marker.c b/src/objects/grits-marker.c
index 3946775..148289c 100644
--- a/src/objects/grits-marker.c
+++ b/src/objects/grits-marker.c
@@ -31,55 +31,105 @@
  */
 
 #include <config.h>
+#include <math.h>
 #include "gtkgl.h"
 #include "grits-marker.h"
 
-/**
- * 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)
+/* Texture setup functions */
+static void render_point(GritsMarker *marker)
 {
-	//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;
-
-	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));
-
-	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);
+	/* This code assumes the icon is an image pointing toward 0 degrees
+	* (ie. north/up).  If marker->flip is set, then it will rotate the
+	* icon appropriately then reflect it across the vertical axis so
+	* it's never upside down. */
+	gdouble flip = 1.0;
+	gdouble angle = marker->angle % 360;
+	if (marker->flip && (angle < 360 && angle > 180)) {
+		/* if icon rotates to the left half it will be upside down */
+		flip = -1.0; /* flip horizontally */
+	}
+
+	cairo_save(marker->cairo);
+
+	/* move to marker location */
+	cairo_translate(marker->cairo, marker->xoff, marker->yoff);
+
+	/* perform rotation and flip in one transformation */
+	gdouble C = cos(angle*(M_PI/180.0));
+	gdouble S = sin(angle*(M_PI/180.0));
+	gdouble fx = flip; 
+	gdouble fy = 1.0;
+	gdouble tx = 0.0;
+	gdouble ty = 0.0;
+	cairo_matrix_t matrix;
+	cairo_matrix_init(&matrix,
+	        fx*C, fx*S,
+	        -S*fy, C*fy,
+	        C*tx*(1-fx)-S*ty*(fy-1)+tx-C*tx+S*ty,
+	        S*tx*(1-fx)+C*ty*(fy-1)+ty-S*tx-C*ty);
+	cairo_transform(marker->cairo, &matrix);
+
+	/* 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);
+	cairo_restore(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,14 +137,129 @@ GritsMarker *grits_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)));
+	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_NEAREST);
 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+}
+
+
+/* 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;
+}
+
+/**
+ * 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->label = g_strdup(label);
+	marker->angle = angle;
+	marker->flip = flip;
+	marker->display_mask = display_mask;
+
+	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)
 {
@@ -137,6 +302,7 @@ static void grits_marker_draw(GritsObject *_marker, GritsOpenGL *opengl)
 	glEnd();
 }
 
+
 /* GObject code */
 G_DEFINE_TYPE(GritsMarker, grits_marker, GRITS_TYPE_OBJECT);
 static void grits_marker_init(GritsMarker *marker)
diff --git a/src/objects/grits-marker.h b/src/objects/grits-marker.h
index 5fdedc7..41a2f39 100644
--- a/src/objects/grits-marker.h
+++ b/src/objects/grits-marker.h
@@ -34,12 +34,34 @@
 typedef struct _GritsMarker      GritsMarker;
 typedef struct _GritsMarkerClass GritsMarkerClass;
 
+#define GRITS_MARKER_DMASK_NONE         (0x0001)
+#define GRITS_MARKER_DMASK_LABEL        (0x0002)
+#define GRITS_MARKER_DMASK_POINT        (0x0004)
+#define GRITS_MARKER_DMASK_ICON         (0x0008)
+#define GRITS_MARKER_DMASK_DIRECTIONAL  (0x0010)
+#define GRITS_MARKER_DMASK_ALL          (0xffff)
+
 struct _GritsMarker {
 	GritsObject  parent_instance;
-	gint       xoff, yoff;
+	gint       xoff, yoff;		    /* center point offset */
+	gint       icon_width, icon_height; /* size of icon for offsets */
 	gchar     *label;
 	cairo_t   *cairo;
 	guint      tex;
+
+	cairo_surface_t *icon_img;
+
+	/* What object to display */
+	guint      display_mask;
+
+	/* icon data */
+	gint     angle;         /* rotation angle */
+	gboolean flip;	        /* keep icon "rightside-up" after rotating? */
+
+	gdouble outline;
+	gdouble radius;
+	gdouble width;
+	gdouble height;
 };
 
 struct _GritsMarkerClass {
@@ -49,5 +71,7 @@ struct _GritsMarkerClass {
 GType grits_marker_get_type(void);
 
 GritsMarker *grits_marker_new(const gchar *label);
+GritsMarker *grits_marker_icon_new(const gchar *label, const gchar *filename,
+    guint angle, gboolean flip, guint display_mask);
 
 #endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]