From: Andy Spencer Date: Sun, 15 Nov 2009 00:42:42 +0000 (+0000) Subject: Add support for GisMarker to Gis{Viewer,OpenGL} X-Git-Tag: v0.4~145 X-Git-Url: http://pileus.org/git/?p=grits;a=commitdiff_plain;h=b088e18d9e838064bb264a145ff66e57886ee42a Add support for GisMarker to Gis{Viewer,OpenGL} --- diff --git a/src/Makefile.am b/src/Makefile.am index 81258ff..195c199 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,7 +30,7 @@ libgis_la_SOURCES = \ gis-data.c gis-data.h \ gis-tile.c gis-tile.h \ gis-wms.c gis-wms.h \ - gis-prims.c gis-prims.h \ + gis-object.c gis-object.h \ roam.c roam.h \ gpqueue.c gpqueue.h libgis_la_CPPFLAGS = $(AM_CPPFLAGS) \ diff --git a/src/gis-prims.c b/src/gis-object.c similarity index 85% rename from src/gis-prims.c rename to src/gis-object.c index 23376bb..8c041b7 100644 --- a/src/gis-prims.c +++ b/src/gis-object.c @@ -18,7 +18,7 @@ #include #include -#include "gis-prims.h" +#include "gis-object.h" #include "gis-util.h" /* TODO @@ -78,7 +78,8 @@ void gis_point_unref(GisPoint *self) GisTriangle *gis_triangle_new(GisPoint *a, GisPoint *b, GisPoint *c, guint tex) { GisTriangle *self = g_new0(GisTriangle, 1); - gis_point_set_xyz(&GIS_PRIMITIVE(self)->center, + GIS_OBJECT(self)->type = GIS_TYPE_TRIANGLE; + gis_point_set_xyz(&GIS_OBJECT(self)->center, (a->x + b->x + c->x)/3, (a->y + b->y + c->y)/3, (a->z + b->z + c->z)/3); @@ -102,7 +103,8 @@ void gis_triangle_free(GisTriangle *self) GisQuad *gis_quad_new(GisPoint *a, GisPoint *b, GisPoint *c, GisPoint *d, guint tex) { GisQuad *self = g_new0(GisQuad, 1); - gis_point_set_xyz(&GIS_PRIMITIVE(self)->center, + GIS_OBJECT(self)->type = GIS_TYPE_QUAD; + gis_point_set_xyz(&GIS_OBJECT(self)->center, (a->x + b->x + c->x + d->x)/4, (a->y + b->y + c->y + d->y)/4, (a->z + b->z + c->z + d->z)/4); @@ -128,6 +130,7 @@ void gis_quad_free(GisQuad *self) GisCallback *gis_callback_new(GisCallbackFunc callback, gpointer user_data) { GisCallback *self = g_new0(GisCallback, 1); + GIS_OBJECT(self)->type = GIS_TYPE_CALLBACK; self->callback = callback; self->user_data = user_data; return self; @@ -137,3 +140,19 @@ void gis_callback_free(GisCallback *self) { g_free(self); } + + +/* GisCallback */ +GisMarker *gis_marker_new(const gchar *label) +{ + GisMarker *self = g_new0(GisMarker, 1); + GIS_OBJECT(self)->type = GIS_TYPE_MARKER; + self->label = g_strdup(label);; + return self; +} + +void gis_marker_free(GisMarker *self) +{ + g_free(self->label); + g_free(self); +} diff --git a/src/gis-prims.h b/src/gis-object.h similarity index 68% rename from src/gis-prims.h rename to src/gis-object.h index 1317733..f5ab5a8 100644 --- a/src/gis-prims.h +++ b/src/gis-object.h @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#ifndef __GIS_PRIMITIVES_H__ -#define __GIS_PRIMITIVES_H__ +#ifndef __GIS_OBJECT_H__ +#define __GIS_OBJECT_H__ #include @@ -53,40 +53,59 @@ struct _GisPoint { gint refs; }; -/* Primitives */ -#define GIS_PRIMITIVE(primitive) ((GisPrimitive*)primitive) -#define GIS_TRIANGLE (triangle ) ((GisTriangle *)triangel ) -#define GIS_QUAD (quad ) ((GisQuad *)quad ) -#define GIS_CALLBACK (callback ) ((GisCallback *)callback ) +/* Objects */ +#define GIS_OBJECT(object) ((GisObject *)object) +#define GIS_TRIANGLE(triangle) ((GisTriangle*)triangle) +#define GIS_QUAD(quad) ((GisQuad *)quad) +#define GIS_CALLBACK(callback) ((GisCallback*)callback) +#define GIS_MARKER(marker) ((GisMarker *)marker) -typedef struct _GisPrimitive GisPrimitive; -typedef struct _GisTriangle GisTriangle; -typedef struct _GisQuad GisQuad; -typedef struct _GisCallback GisCallback; +typedef enum { + GIS_TYPE_TRIANGLE, + GIS_TYPE_QUAD, + GIS_TYPE_CALLBACK, + GIS_TYPE_MARKER, + GIS_NUM_TYPES, +} GisObjectType; + +typedef struct _GisObject GisObject; +typedef struct _GisTriangle GisTriangle; +typedef struct _GisQuad GisQuad; +typedef struct _GisCallback GisCallback; +typedef struct _GisMarker GisMarker; typedef gpointer (*GisCallbackFunc)(GisCallback *callback, gpointer user_data); -struct _GisPrimitive { +struct _GisObject { + GisObjectType type; GisPoint center; GisProjection *proj; + gdouble lod; }; struct _GisTriangle { - GisPrimitive parent; - GisPoint *verts[3]; - guint tex; + GisObject parent; + GisPoint *verts[3]; + guint tex; }; struct _GisQuad { - GisPrimitive parent; - GisPoint *verts[4]; - guint tex; + GisObject parent; + GisPoint *verts[4]; + guint tex; }; struct _GisCallback { - GisPrimitive parent; + GisObject parent; GisCallbackFunc callback; gpointer user_data; }; +struct _GisMarker { + GisObject parent; + gchar *label; +}; /* Support functions */ +#define gis_object_center(object) \ + (&GIS_OBJECT(object)->center) + GisPoint *gis_point_new(); void gis_point_set_lle(GisPoint *point, gdouble lat, gdouble lon, gdouble elev); void gis_point_set_xyz(GisPoint *point, gdouble x, gdouble y, gdouble z); @@ -104,4 +123,7 @@ void gis_quad_free(GisQuad *quad); GisCallback *gis_callback_new(GisCallbackFunc callback, gpointer user_data); void gis_callback_free(GisCallback *cb); +GisMarker *gis_marker_new(const gchar *label); +void gis_marker_free(GisMarker *marker); + #endif diff --git a/src/gis-opengl.c b/src/gis-opengl.c index ec70337..6b70f14 100644 --- a/src/gis-opengl.c +++ b/src/gis-opengl.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -29,12 +30,92 @@ #include "gis-opengl.h" #include "gis-util.h" +#include "gis-object.h" #include "roam.h" #define FOV_DIST 2000.0 #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) +{ +} + +static void _gis_opengl_draw_callback(GisOpenGL *self, GisCallback *cb) +{ +} + +static void _gis_opengl_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; + + 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"); + + 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); + + /* 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); + 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); + 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); + glEnd(); + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); +} + /*********** * Helpers * @@ -148,13 +229,34 @@ static gboolean on_configure(GisOpenGL *self, GdkEventConfigure *event, gpointer double width = GTK_WIDGET(self)->allocation.width; double height = GTK_WIDGET(self)->allocation.height; - glViewport(0, 0, width, height); + /* Setup OpenGL Window */ + glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); 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 @@ -163,7 +265,7 @@ static gboolean on_configure(GisOpenGL *self, GdkEventConfigure *event, gpointer return FALSE; } -static void on_expose_plugin(GisPlugin *plugin, gchar *name, GisOpenGL *self) +static void _on_expose_plugin(GisPlugin *plugin, gchar *name, GisOpenGL *self) { _set_visuals(self); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -180,8 +282,9 @@ static gboolean on_expose(GisOpenGL *self, GdkEventExpose *event, gpointer _) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #ifndef ROAM_DEBUG - gis_plugins_foreach(GIS_VIEWER(self)->plugins, G_CALLBACK(on_expose_plugin), self); - + gis_plugins_foreach(GIS_VIEWER(self)->plugins, + G_CALLBACK(_on_expose_plugin), self); + gis_opengl_draw_objects(self); if (self->wireframe) { _set_visuals(self); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -193,7 +296,6 @@ static gboolean on_expose(GisOpenGL *self, GdkEventExpose *event, gpointer _) glDisable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); roam_sphere_draw(self->sphere); - //roam_sphere_draw_normals(self->sphere); #endif @@ -227,8 +329,7 @@ static gboolean on_key_press(GisOpenGL *self, GdkEventKey *event, gpointer _) #else gdk_threads_enter(); #endif - - return TRUE; + return FALSE; } static gboolean _update_errors_cb(gpointer sphere) @@ -450,14 +551,14 @@ static void gis_opengl_init(GisOpenGL *self) self->sm_source[1] = g_timeout_add_full(G_PRIORITY_HIGH_IDLE+10, 500, (GSourceFunc)on_idle, self, NULL); #endif - g_signal_connect(self, "realize", G_CALLBACK(on_realize), NULL); - g_signal_connect(self, "configure-event", G_CALLBACK(on_configure), NULL); - g_signal_connect(self, "expose-event", G_CALLBACK(on_expose), NULL); + g_signal_connect(self, "realize", G_CALLBACK(on_realize), NULL); + g_signal_connect(self, "configure-event", G_CALLBACK(on_configure), NULL); + g_signal_connect(self, "expose-event", G_CALLBACK(on_expose), NULL); - g_signal_connect(self, "key-press-event", G_CALLBACK(on_key_press), NULL); + g_signal_connect(self, "key-press-event", G_CALLBACK(on_key_press), NULL); - g_signal_connect(self, "location-changed", G_CALLBACK(on_view_changed), NULL); - g_signal_connect(self, "rotation-changed", G_CALLBACK(on_view_changed), NULL); + g_signal_connect(self, "location-changed", G_CALLBACK(on_view_changed), NULL); + g_signal_connect(self, "rotation-changed", G_CALLBACK(on_view_changed), NULL); } static void gis_opengl_dispose(GObject *_self) { @@ -477,6 +578,17 @@ static void gis_opengl_dispose(GObject *_self) } G_OBJECT_CLASS(gis_opengl_parent_class)->dispose(_self); } +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) { g_debug("GisOpenGL: class_init"); diff --git a/src/gis-opengl.h b/src/gis-opengl.h index 0ef682d..b1f7b56 100644 --- a/src/gis-opengl.h +++ b/src/gis-opengl.h @@ -40,6 +40,8 @@ struct _GisOpenGL { /* instance members */ RoamSphere *sphere; guint sm_source[2]; + cairo_t *canvas; + guint canvas_tex; /* for testing */ gboolean wireframe; diff --git a/src/gis-plugin.c b/src/gis-plugin.c index 2e0ef1b..8c3ba36 100644 --- a/src/gis-plugin.c +++ b/src/gis-plugin.c @@ -49,13 +49,18 @@ GType gis_plugin_get_type() void gis_plugin_expose(GisPlugin *self) { - g_return_if_fail(GIS_IS_PLUGIN(self)); + if (!GIS_IS_PLUGIN(self)) + return; + GisPluginInterface *iface = GIS_PLUGIN_GET_INTERFACE(self); + if (iface->expose) + return GIS_PLUGIN_GET_INTERFACE(self)->expose(self); } GtkWidget *gis_plugin_get_config(GisPlugin *self) { - g_return_val_if_fail(GIS_IS_PLUGIN(self), NULL); + if (!GIS_IS_PLUGIN(self)) + return NULL; GisPluginInterface *iface = GIS_PLUGIN_GET_INTERFACE(self); return iface->get_config ? iface->get_config (self) : NULL; } diff --git a/src/gis-viewer.c b/src/gis-viewer.c index 79dab10..89812b0 100644 --- a/src/gis-viewer.c +++ b/src/gis-viewer.c @@ -121,7 +121,7 @@ static gboolean on_key_press(GisViewer *self, GdkEventKey *event, gpointer _) else if (kv == GDK_J) gis_viewer_rotate(self, 2, 0, 0); else if (kv == GDK_K) gis_viewer_rotate(self, -2, 0, 0); else if (kv == GDK_L) gis_viewer_rotate(self, 0, 0, 2); - return TRUE; + return FALSE; } static void on_view_changed(GisViewer *self, gdouble _1, gdouble _2, gdouble _3) @@ -254,6 +254,18 @@ 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) diff --git a/src/gis-viewer.h b/src/gis-viewer.h index 999d3d1..d1d8caa 100644 --- a/src/gis-viewer.h +++ b/src/gis-viewer.h @@ -36,12 +36,14 @@ typedef gdouble (*GisHeightFunc)(gdouble lat, gdouble lon, gpointer user_data); #include "gis-tile.h" #include "gis-plugin.h" +#include "gis-object.h" struct _GisViewer { GtkDrawingArea parent_instance; /* instance members */ GisPlugins *plugins; + GList *objects; gchar *time; gchar *site; gdouble location[3]; @@ -98,6 +100,9 @@ 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); diff --git a/src/gis_test.c b/src/gis_test.c index 0cc2f0b..e41fec1 100644 --- a/src/gis_test.c +++ b/src/gis_test.c @@ -57,8 +57,8 @@ 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, "srtm", viewer, prefs); + //gis_plugins_load(plugins, "bmng", viewer, prefs); + //gis_plugins_load(plugins, "srtm", viewer, prefs); gis_plugins_load(plugins, "test", viewer, prefs); gis_viewer_set_site(viewer, "KLSX"); diff --git a/src/plugins/test.c b/src/plugins/test.c index 94995b0..9c3a963 100644 --- a/src/plugins/test.c +++ b/src/plugins/test.c @@ -31,63 +31,12 @@ GisPluginTest *gis_plugin_test_new(GisViewer *viewer) g_debug("GisPluginTest: new"); GisPluginTest *self = g_object_new(GIS_TYPE_PLUGIN_TEST, NULL); self->viewer = viewer; - return self; -} - -static void gis_plugin_test_expose(GisPlugin *_self) -{ - GisPluginTest *self = GIS_PLUGIN_TEST(_self); - g_debug("GisPluginTest: expose"); - - double width = GTK_WIDGET(self->viewer)->allocation.width; - double height = GTK_WIDGET(self->viewer)->allocation.height; - // St. Charles - // lat = 38.841847 - // lon = -90.491982 - gdouble px, py, pz; - gis_viewer_project(self->viewer, - 38.841847, -90.491982, 0, &px, &py, &pz); - py = height-py; + 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)); - //cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - //cairo_t *cairo = cairo_create(surface); - //cairo_set_source_rgba(cairo, 1, 1, 1, 1); - //cairo_arc(cairo, px, py, 4, 0, 2*G_PI); - //cairo_fill(cairo); - //cairo_move_to(cairo, px+4, py-8); - //cairo_set_font_size(cairo, 10); - //cairo_show_text(cairo, "Marker!"); - - //guint tex; - //glEnable(GL_TEXTURE_2D); - //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - //glPixelStorei(GL_PACK_ALIGNMENT, 1); - //glGenTextures(1, &tex); - //glBindTexture(GL_TEXTURE_2D, tex); - //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 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); - - //glMatrixMode(GL_PROJECTION); - //glLoadIdentity(); - //glMatrixMode(GL_MODELVIEW); - //glLoadIdentity(); - - //glDisable(GL_COLOR_MATERIAL); - //glDisable(GL_CULL_FACE); - //glDisable(GL_DEPTH_TEST); - //glDisable(GL_LIGHTING); - //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); - //glEnd(); - //glDeleteTextures(1, &tex); - //cairo_destroy(cairo); - //cairo_surface_destroy(surface); + return self; } @@ -103,7 +52,6 @@ static void gis_plugin_test_plugin_init(GisPluginInterface *iface) { g_debug("GisPluginTest: plugin_init"); /* Add methods to the interface */ - iface->expose = gis_plugin_test_expose; } /* Class/Object init */ static void gis_plugin_test_init(GisPluginTest *self)