From 1ccb2426332856ef04f0bfb35716520a94e0d32c Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 15 Nov 2009 08:10:49 +0000 Subject: [PATCH] Markers as individual textures --- src/gis-object.c | 18 +++- src/gis-object.h | 4 + src/gis-opengl.c | 209 ++++++++++++++++++++++++--------------------- src/gis-opengl.h | 3 +- src/gis-viewer.c | 28 +++--- src/gis-viewer.h | 10 ++- src/gis_test.c | 2 +- src/plugins/test.c | 2 +- 8 files changed, 159 insertions(+), 117 deletions(-) diff --git a/src/gis-object.c b/src/gis-object.c index 8c041b7..cfd1870 100644 --- a/src/gis-object.c +++ b/src/gis-object.c @@ -145,14 +145,30 @@ void gis_callback_free(GisCallback *self) /* GisCallback */ GisMarker *gis_marker_new(const gchar *label) { + static const int RADIUS = 4; + static const int WIDTH = 100; + static const int HEIGHT = 20; + GisMarker *self = g_new0(GisMarker, 1); GIS_OBJECT(self)->type = GIS_TYPE_MARKER; - self->label = g_strdup(label);; + self->xoff = RADIUS; + self->yoff = HEIGHT-RADIUS; + self->label = g_strdup(label); + self->cairo = cairo_create(cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT)); + cairo_set_source_rgba(self->cairo, 1, 1, 1, 1); + cairo_arc(self->cairo, self->xoff, self->yoff, RADIUS, 0, 2*G_PI); + cairo_fill(self->cairo); + cairo_move_to(self->cairo, self->xoff+4, self->yoff-8); + cairo_set_font_size(self->cairo, 10); + cairo_show_text(self->cairo, self->label); return self; } void gis_marker_free(GisMarker *self) { + cairo_surface_destroy(cairo_get_target(self->cairo)); + cairo_destroy(self->cairo); g_free(self->label); g_free(self); } diff --git a/src/gis-object.h b/src/gis-object.h index f5ab5a8..a58b815 100644 --- a/src/gis-object.h +++ b/src/gis-object.h @@ -19,6 +19,7 @@ #define __GIS_OBJECT_H__ #include +#include /* Base types */ typedef struct _GisProjection GisProjection; @@ -99,7 +100,10 @@ struct _GisCallback { }; struct _GisMarker { GisObject parent; + gint xoff, yoff; gchar *label; + cairo_t *cairo; + guint tex; }; /* Support functions */ diff --git a/src/gis-opengl.c b/src/gis-opengl.c index 6b70f14..0bcde3d 100644 --- a/src/gis-opengl.c +++ b/src/gis-opengl.c @@ -37,105 +37,129 @@ #define MPPX(dist) (4*dist/FOV_DIST) // #define ROAM_DEBUG -/****************** - * Object drawing * - ******************/ -static void _gis_opengl_draw_triangle(GisOpenGL *self, GisTriangle *tri) -{ -} -static void _gis_opengl_draw_quad(GisOpenGL *self, GisQuad *quad) +/*********** + * Helpers * + ***********/ +static void _gis_opengl_begin(GisOpenGL *self) { + g_assert(GIS_IS_OPENGL(self)); + + GdkGLContext *glcontext = gtk_widget_get_gl_context(GTK_WIDGET(self)); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(self)); + + if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) + g_assert_not_reached(); } -static void _gis_opengl_draw_callback(GisOpenGL *self, GisCallback *cb) +static void _gis_opengl_end(GisOpenGL *self) { + g_assert(GIS_IS_OPENGL(self)); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(self)); + gdk_gl_drawable_gl_end(gldrawable); } -static void _gis_opengl_draw_marker(GisOpenGL *self, GisMarker *marker) + +/******************** + * Object handleing * + ********************/ +static void _draw_marker(GisOpenGL *self, GisMarker *marker) { GisProjection *proj = (GisProjection*)self->sphere->view; GisPoint *point = gis_object_center(marker); gis_point_project(point, proj); - double width = GTK_WIDGET(self)->allocation.width; - double height = GTK_WIDGET(self)->allocation.height; + g_debug("GisOpenGL: draw_marker - texture=%d", marker->tex); - cairo_set_source_rgba(self->canvas, 1, 1, 1, 1); - cairo_arc(self->canvas, point->px, height-point->py, 4, 0, 2*G_PI); - cairo_fill(self->canvas); - cairo_move_to(self->canvas, point->px+4, height-point->py-8); - cairo_set_font_size(self->canvas, 10); - cairo_show_text(self->canvas, marker->label); -} - -static void gis_opengl_draw_object(GisOpenGL *self, GisObject *object) -{ - g_debug("GisOpenGL: draw_object - Drawing object of type %d", object->type); - switch (object->type) { - case GIS_TYPE_TRIANGLE: _gis_opengl_draw_triangle(self, GIS_TRIANGLE(object)); break; - case GIS_TYPE_QUAD : _gis_opengl_draw_quad (self, GIS_QUAD (object)); break; - case GIS_TYPE_CALLBACK: _gis_opengl_draw_callback(self, GIS_CALLBACK(object)); break; - case GIS_TYPE_MARKER : _gis_opengl_draw_marker (self, GIS_MARKER (object)); break; - default: g_warning("GisOpenGL: draw_object - invalid type %d", object->type); - } -} -static void gis_opengl_draw_objects(GisOpenGL *self) -{ - g_debug("GisOpenGL: draw_objects"); + 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); - double width = GTK_WIDGET(self)->allocation.width; - double height = GTK_WIDGET(self)->allocation.height; - cairo_surface_t *surface = cairo_get_target(self->canvas); - int stride = cairo_image_surface_get_stride(surface); - guchar *data = cairo_image_surface_get_data(surface); - memset(data, 0, height*stride); + glMatrixMode(GL_PROJECTION); glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + glOrtho(0, GTK_WIDGET(self)->allocation.width, + 0, GTK_WIDGET(self)->allocation.height, -1, 1); + glTranslated(gis_object_center(marker)->px - marker->xoff, + gis_object_center(marker)->py - marker->yoff, 0); - /* Draw objects */ - for (GList *cur = GIS_VIEWER(self)->objects; cur; cur = cur->next) - gis_opengl_draw_object(self, cur->data); - - /* Copy canvas to opengl */ - glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); + glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, self->canvas_tex); - //glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, width,height, - // GL_RGBA, GL_UNSIGNED_BYTE, data); + glBindTexture(GL_TEXTURE_2D, marker->tex); + g_debug("bind_texture: %d", marker->tex); glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex3f(-1, 1, 1); - glTexCoord2d(1, 0); glVertex3f( 1, 1, 1); - glTexCoord2d(1, 1); glVertex3f( 1, -1, 1); - glTexCoord2d(0, 1); glVertex3f(-1, -1, 1); + glTexCoord2f(1, 1); glVertex3f(width, 0 , 0); + glTexCoord2f(1, 0); glVertex3f(width, height, 0); + glTexCoord2f(0, 0); glVertex3f(0 , height, 0); + glTexCoord2f(0, 1); glVertex3f(0 , 0 , 0); glEnd(); - glMatrixMode(GL_PROJECTION); glPopMatrix(); - glMatrixMode(GL_MODELVIEW); glPopMatrix(); } -/*********** - * Helpers * - ***********/ -static void _gis_opengl_begin(GisOpenGL *self) +static void _draw_objects(GisOpenGL *self) { - g_assert(GIS_IS_OPENGL(self)); + g_debug("GisOpenGL: draw_objects"); + /* Draw objects */ + for (GList *cur = self->objects; cur; cur = cur->next) { + glMatrixMode(GL_PROJECTION); glPushMatrix(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); + GisObject *object = cur->data; + switch (object->type) { + case GIS_TYPE_MARKER: + _draw_marker(self, GIS_MARKER(object)); + break; + default: + break; + } + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); + } +} - GdkGLContext *glcontext = gtk_widget_get_gl_context(GTK_WIDGET(self)); - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(self)); +static void _load_object(GisOpenGL *self, GisObject *object) +{ + g_debug("GisOpenGL: load_object"); + switch (object->type) { + case GIS_TYPE_MARKER: { + GisMarker *marker = GIS_MARKER(object); + 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); - if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) - g_assert_not_reached(); + _gis_opengl_begin(self); + 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(surface)); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + g_debug("load_texture: %d", marker->tex); + _gis_opengl_end(self); + break; + } + default: + break; + } } -static void _gis_opengl_end(GisOpenGL *self) +static void _free_object(GisOpenGL *self, GisObject *object) { - g_assert(GIS_IS_OPENGL(self)); - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(self)); - gdk_gl_drawable_gl_end(gldrawable); + g_debug("GisOpenGL: free_object"); + switch (object->type) { + case GIS_TYPE_MARKER: { + GisMarker *marker = GIS_MARKER(object); + g_debug("delete_texture: %d", marker->tex); + glDeleteTextures(1, &marker->tex); + break; + } + default: + break; + } } /************* @@ -237,26 +261,6 @@ static gboolean on_configure(GisOpenGL *self, GdkEventConfigure *event, gpointer double ang = atan(height/FOV_DIST); gluPerspective(rad2deg(ang)*2, width/height, 1, 20*EARTH_R); - /* Recreate the canvas */ - if (self->canvas) { - cairo_surface_destroy(cairo_get_target(self->canvas)); - cairo_destroy(self->canvas); - glDeleteTextures(1, &self->canvas_tex); - } - g_message("creating %fx%f canvas", width, height); - cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - self->canvas = cairo_create(surface); - glEnable(GL_TEXTURE_2D); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glGenTextures(1, &self->canvas_tex); - glBindTexture(GL_TEXTURE_2D, self->canvas_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, - cairo_image_surface_get_data(cairo_get_target(self->canvas))); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - #ifndef ROAM_DEBUG roam_sphere_update_errors(self->sphere); #endif @@ -284,7 +288,7 @@ static gboolean on_expose(GisOpenGL *self, GdkEventExpose *event, gpointer _) #ifndef ROAM_DEBUG gis_plugins_foreach(GIS_VIEWER(self)->plugins, G_CALLBACK(_on_expose_plugin), self); - gis_opengl_draw_objects(self); + _draw_objects(self); if (self->wireframe) { _set_visuals(self); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -519,6 +523,22 @@ static void gis_opengl_end(GisViewer *_self) _gis_opengl_end(GIS_OPENGL(_self)); } +static void gis_opengl_add(GisViewer *_self, GisObject *object) +{ + g_assert(GIS_IS_OPENGL(_self)); + GisOpenGL *self = GIS_OPENGL(_self); + _load_object(self, object); + self->objects = g_list_prepend(self->objects, object); +} + +static void gis_opengl_remove(GisViewer *_self, GisObject *object) +{ + g_assert(GIS_IS_OPENGL(_self)); + GisOpenGL *self = GIS_OPENGL(_self); + _free_object(self, object); + self->objects = g_list_remove(self->objects, object); +} + /**************** * GObject code * ****************/ @@ -582,11 +602,6 @@ static void gis_opengl_finalize(GObject *_self) { g_debug("GisViewer: finalize"); GisOpenGL *self = GIS_OPENGL(_self); - if (self->canvas) { - cairo_surface_destroy(cairo_get_target(self->canvas)); - cairo_destroy(self->canvas); - self->canvas = NULL; - } G_OBJECT_CLASS(gis_opengl_parent_class)->finalize(_self); } static void gis_opengl_class_init(GisOpenGLClass *klass) @@ -604,4 +619,6 @@ static void gis_opengl_class_init(GisOpenGLClass *klass) viewer_class->render_tiles = gis_opengl_render_tiles; viewer_class->begin = gis_opengl_begin; viewer_class->end = gis_opengl_end; + viewer_class->add = gis_opengl_add; + viewer_class->remove = gis_opengl_remove; } diff --git a/src/gis-opengl.h b/src/gis-opengl.h index b1f7b56..c6aa506 100644 --- a/src/gis-opengl.h +++ b/src/gis-opengl.h @@ -38,10 +38,9 @@ struct _GisOpenGL { GisViewer parent_instance; /* instance members */ + GList *objects; RoamSphere *sphere; guint sm_source[2]; - cairo_t *canvas; - guint canvas_tex; /* for testing */ gboolean wireframe; diff --git a/src/gis-viewer.c b/src/gis-viewer.c index 89812b0..e00d951 100644 --- a/src/gis-viewer.c +++ b/src/gis-viewer.c @@ -254,18 +254,6 @@ gboolean gis_viewer_get_offline(GisViewer *self) return self->offline; } -void gis_viewer_add_object(GisViewer *self, GisObject *object) -{ - g_debug("GisViewer: add_object - %d, %p", object->type, object); - self->objects = g_list_prepend(self->objects, object); -} - -void gis_viewer_remove_object(GisViewer *self, GisObject *object) -{ - g_debug("GisViewer: remove_object - %d, %p", object->type, object); - self->objects = g_list_remove(self->objects, object); -} - /* To be implemented by subclasses */ void gis_viewer_center_position(GisViewer *self, gdouble lat, gdouble lon, gdouble elev) @@ -336,6 +324,22 @@ void gis_viewer_end(GisViewer *self) klass->end(self); } +void gis_viewer_add(GisViewer *self, GisObject *object) +{ + GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self); + if (!klass->add) + g_warning("GisViewer: add - Unimplemented"); + klass->add(self, object); +} + +void gis_viewer_remove(GisViewer *self, GisObject *object) +{ + GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self); + if (!klass->remove) + g_warning("GisViewer: remove - Unimplemented"); + klass->remove(self, object); +} + /**************** * GObject code * ****************/ diff --git a/src/gis-viewer.h b/src/gis-viewer.h index d1d8caa..214ce93 100644 --- a/src/gis-viewer.h +++ b/src/gis-viewer.h @@ -43,7 +43,6 @@ struct _GisViewer { /* instance members */ GisPlugins *plugins; - GList *objects; gchar *time; gchar *site; gdouble location[3]; @@ -72,6 +71,9 @@ struct _GisViewerClass { void (*begin) (GisViewer *viewer); void (*end) (GisViewer *viewer); + + void (*add) (GisViewer *viewer, GisObject *object); + void (*remove) (GisViewer *viewer, GisObject *object); }; GType gis_viewer_get_type(void); @@ -100,9 +102,6 @@ void gis_viewer_refresh(GisViewer *viewer); void gis_viewer_set_offline(GisViewer *viewer, gboolean offline); gboolean gis_viewer_get_offline(GisViewer *viewer); -void gis_viewer_add_object(GisViewer *self, GisObject *object); -void gis_viewer_remove_object(GisViewer *self, GisObject *object); - /* To be implemented by subclasses */ void gis_viewer_center_position(GisViewer *viewer, gdouble lat, gdouble lon, gdouble elev); @@ -122,4 +121,7 @@ void gis_viewer_render_tiles(GisViewer *viewer, GisTile *root); void gis_viewer_begin(GisViewer *viewer); void gis_viewer_end (GisViewer *viewer); +void gis_viewer_add(GisViewer *self, GisObject *object); +void gis_viewer_remove(GisViewer *self, GisObject *object); + #endif diff --git a/src/gis_test.c b/src/gis_test.c index e41fec1..746c058 100644 --- a/src/gis_test.c +++ b/src/gis_test.c @@ -57,7 +57,7 @@ int main(int argc, char **argv) gtk_widget_show_all(window); gdk_threads_leave(); - //gis_plugins_load(plugins, "bmng", viewer, prefs); + gis_plugins_load(plugins, "bmng", viewer, prefs); //gis_plugins_load(plugins, "srtm", viewer, prefs); gis_plugins_load(plugins, "test", viewer, prefs); diff --git a/src/plugins/test.c b/src/plugins/test.c index 9c3a963..5be0fd7 100644 --- a/src/plugins/test.c +++ b/src/plugins/test.c @@ -34,7 +34,7 @@ GisPluginTest *gis_plugin_test_new(GisViewer *viewer) GisMarker *marker = gis_marker_new("St. Charles"); gis_point_set_lle(gis_object_center(marker), 38.841847, -90.491982, 0); - gis_viewer_add_object(self->viewer, GIS_OBJECT(marker)); + gis_viewer_add(self->viewer, GIS_OBJECT(marker)); return self; } -- 2.43.2