From 3ebe95528320be9e3821fe23e39d41fd89b10fdd Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Mon, 25 Jan 2010 08:03:37 +0000 Subject: [PATCH] Convert for expose callback to callback objects Objects are now added using a level and a sorting parameter - Levels are rendered in order - Semi-transparent objects should be added with sort=TRUE (note: this is currently broken) --- src/gis-opengl.c | 131 +++++++++++++++++++++++++++++++++------------ src/gis-opengl.h | 2 +- src/gis-plugin.c | 10 ---- src/gis-plugin.h | 1 - src/gis-viewer.c | 9 ++-- src/gis-viewer.h | 15 ++++-- src/plugins/bmng.c | 22 ++++---- src/plugins/srtm.c | 24 +++++---- src/plugins/test.c | 3 +- 9 files changed, 142 insertions(+), 75 deletions(-) diff --git a/src/gis-opengl.c b/src/gis-opengl.c index b1886c2..34c55a5 100644 --- a/src/gis-opengl.c +++ b/src/gis-opengl.c @@ -98,25 +98,43 @@ static void _draw_marker(GisOpenGL *self, GisMarker *marker) glEnd(); } +static void _draw_callback(GisOpenGL *self, GisCallback *callback) +{ + callback->callback(callback, callback->user_data); +} -static void _draw_objects(GisOpenGL *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(); +static void _draw_object(GisOpenGL *self, GisObject *object) +{ + //g_debug("GisOpenGL: draw_object"); + /* Skip out of range objects */ + if (object->lod > 0) { + gdouble eye[3], obj[3]; + gis_viewer_get_location(GIS_VIEWER(self), &eye[0], &eye[1], &eye[2]); + lle2xyz(eye[0], eye[1], eye[2], &eye[0], &eye[1], &eye[2]); + lle2xyz(object->center.lat, object->center.lon, object->center.elev, + &obj[0], &obj[1], &obj[2]); + gdouble dist = distd(obj, eye); + if (object->lod < dist) + return; + } + + /* Draw */ + glMatrixMode(GL_PROJECTION); glPushMatrix(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); + glPushAttrib(GL_ALL_ATTRIB_BITS); + switch (object->type) { + case GIS_TYPE_MARKER: + _draw_marker(self, GIS_MARKER(object)); + break; + case GIS_TYPE_CALLBACK: + _draw_callback(self, GIS_CALLBACK(object)); + break; + default: + break; } + glPopAttrib(); + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); } static void _load_object(GisOpenGL *self, GisObject *object) @@ -149,9 +167,9 @@ static void _load_object(GisOpenGL *self, GisObject *object) } } -static void _free_object(GisOpenGL *self, GisObject *object) +static void _unload_object(GisOpenGL *self, GisObject *object) { - g_debug("GisOpenGL: free_object"); + g_debug("GisOpenGL: unload_object"); switch (object->type) { case GIS_TYPE_MARKER: { GisMarker *marker = GIS_MARKER(object); @@ -242,6 +260,14 @@ static void _set_visuals(GisOpenGL *self) /************* * Callbacks * *************/ +/* The unsorted/sroted GLists are blank head nodes, + * This way us we can remove objects from the level just by fixing up links + * I.e. we don't need to do a lookup to remove an object if we have its GList */ +struct RenderLevel { + GList unsorted; + GList sorted; +}; + static void on_realize(GisOpenGL *self, gpointer _) { g_debug("GisOpenGL: on_realize"); @@ -271,26 +297,42 @@ static gboolean on_configure(GisOpenGL *self, GdkEventConfigure *event, gpointer return FALSE; } -static void _on_expose_plugin(GisPlugin *plugin, gchar *name, GisOpenGL *self) +static gboolean _draw_level(gpointer key, gpointer value, gpointer user_data) { - _set_visuals(self); - glMatrixMode(GL_PROJECTION); glPushMatrix(); - glMatrixMode(GL_MODELVIEW); glPushMatrix(); - gis_plugin_expose(plugin); - glMatrixMode(GL_PROJECTION); glPopMatrix(); - glMatrixMode(GL_MODELVIEW); glPopMatrix(); + g_debug("GisOpenGL: _draw_level - level=%-4d", (int)key); + GisOpenGL *self = user_data; + struct RenderLevel *level = value; + int nsorted = 0, nunsorted = 0; + GList *cur = NULL; + + /* Draw opaque objects without sorting */ + glDepthMask(TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + for (cur = level->unsorted.next; cur; cur = cur->next, nunsorted++) + _draw_object(self, GIS_OBJECT(cur->data)); + + /* Freeze depth buffer and draw transparent objects sorted */ + /* TODO: sorting */ + glDepthMask(FALSE); + for (cur = level->sorted.next; cur; cur = cur->next, nsorted++) + _draw_object(self, GIS_OBJECT(cur->data)); + + /* TODO: Prune empty levels */ + + g_debug("GisOpenGL: _draw_level - drew %d,%d objects", + nunsorted, nsorted); + return FALSE; } + static gboolean on_expose(GisOpenGL *self, GdkEventExpose *event, gpointer _) { g_debug("GisOpenGL: on_expose - begin"); _gis_opengl_begin(self); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); #ifndef ROAM_DEBUG - gis_plugins_foreach(GIS_VIEWER(self)->plugins, - G_CALLBACK(_on_expose_plugin), self); - _draw_objects(self); + g_tree_foreach(self->objects, _draw_level, self); if (self->wireframe) { _set_visuals(self); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -525,25 +567,42 @@ static void gis_opengl_end(GisViewer *_self) _gis_opengl_end(GIS_OPENGL(_self)); } -static void gis_opengl_add(GisViewer *_self, GisObject *object) +static gpointer gis_opengl_add(GisViewer *_self, GisObject *object, + gint key, gboolean sort) { g_assert(GIS_IS_OPENGL(_self)); GisOpenGL *self = GIS_OPENGL(_self); _load_object(self, object); - self->objects = g_list_prepend(self->objects, object); + struct RenderLevel *level = g_tree_lookup(self->objects, (gpointer)key); + if (!level) { + level = g_new0(struct RenderLevel, 1); + g_tree_insert(self->objects, (gpointer)key, level); + } + GList *list = sort ? &level->sorted : &level->unsorted; + list->next = g_list_prepend(list->next, object); + return list->next; } -static void gis_opengl_remove(GisViewer *_self, GisObject *object) +static void gis_opengl_remove(GisViewer *_self, gpointer _link) { g_assert(GIS_IS_OPENGL(_self)); + GList *link = _link; GisOpenGL *self = GIS_OPENGL(_self); - _free_object(self, object); - self->objects = g_list_remove(self->objects, object); + _unload_object(self, link->data); + /* Just unlink and free it (blowup link to avoid warnings) */ + link = g_list_delete_link(NULL, link); } /**************** * GObject code * ****************/ +static int _objects_cmp(gconstpointer _a, gconstpointer _b) +{ + gint a = (int)_a, b = (int)_b; + return a < b ? -1 : + a > b ? 1 : 0; +} + G_DEFINE_TYPE(GisOpenGL, gis_opengl, GIS_TYPE_VIEWER); static void gis_opengl_init(GisOpenGL *self) { @@ -566,6 +625,7 @@ static void gis_opengl_init(GisOpenGL *self) GDK_KEY_PRESS_MASK); g_object_set(self, "can-focus", TRUE, NULL); + self->objects = g_tree_new(_objects_cmp); self->sphere = roam_sphere_new(self); #ifndef ROAM_DEBUG @@ -598,6 +658,7 @@ static void gis_opengl_dispose(GObject *_self) roam_sphere_free(self->sphere); self->sphere = NULL; } + /* TODO: Cleanup/free objects tree */ G_OBJECT_CLASS(gis_opengl_parent_class)->dispose(_self); } static void gis_opengl_finalize(GObject *_self) diff --git a/src/gis-opengl.h b/src/gis-opengl.h index c6aa506..ce65cbc 100644 --- a/src/gis-opengl.h +++ b/src/gis-opengl.h @@ -38,7 +38,7 @@ struct _GisOpenGL { GisViewer parent_instance; /* instance members */ - GList *objects; + GTree *objects; RoamSphere *sphere; guint sm_source[2]; diff --git a/src/gis-plugin.c b/src/gis-plugin.c index 8c3ba36..66c3d1f 100644 --- a/src/gis-plugin.c +++ b/src/gis-plugin.c @@ -47,16 +47,6 @@ GType gis_plugin_get_type() return type; } -void gis_plugin_expose(GisPlugin *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) { if (!GIS_IS_PLUGIN(self)) diff --git a/src/gis-plugin.h b/src/gis-plugin.h index 2feb874..7ba3ae8 100644 --- a/src/gis-plugin.h +++ b/src/gis-plugin.h @@ -35,7 +35,6 @@ struct _GisPluginInterface GTypeInterface parent_iface; /* Virtual functions */ - void (*expose )(GisPlugin *self); GtkWidget *(*get_config)(GisPlugin *self); }; diff --git a/src/gis-viewer.c b/src/gis-viewer.c index 18ec589..a9284d5 100644 --- a/src/gis-viewer.c +++ b/src/gis-viewer.c @@ -318,20 +318,21 @@ void gis_viewer_end(GisViewer *self) klass->end(self); } -void gis_viewer_add(GisViewer *self, GisObject *object) +gpointer gis_viewer_add(GisViewer *self, GisObject *object, + gint level, gboolean sort) { GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self); if (!klass->add) g_warning("GisViewer: add - Unimplemented"); - klass->add(self, object); + return klass->add(self, object, level, sort); } -void gis_viewer_remove(GisViewer *self, GisObject *object) +void gis_viewer_remove(GisViewer *self, gpointer ref) { GisViewerClass *klass = GIS_VIEWER_GET_CLASS(self); if (!klass->remove) g_warning("GisViewer: remove - Unimplemented"); - klass->remove(self, object); + klass->remove(self, ref); } /**************** diff --git a/src/gis-viewer.h b/src/gis-viewer.h index 214ce93..6b95e1a 100644 --- a/src/gis-viewer.h +++ b/src/gis-viewer.h @@ -21,6 +21,11 @@ #include #include +#define GIS_LEVEL_BACKGROUND -100 +#define GIS_LEVEL_WORLD 0 +#define GIS_LEVEL_OVERLAY 100 +#define GIS_LEVEL_HUD 200 + /* Type macros */ #define GIS_TYPE_VIEWER (gis_viewer_get_type()) #define GIS_VIEWER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GIS_TYPE_VIEWER, GisViewer)) @@ -72,8 +77,9 @@ struct _GisViewerClass { void (*begin) (GisViewer *viewer); void (*end) (GisViewer *viewer); - void (*add) (GisViewer *viewer, GisObject *object); - void (*remove) (GisViewer *viewer, GisObject *object); + gpointer (*add) (GisViewer *viewer, GisObject *object, + gint level, gboolean sort); + void (*remove) (GisViewer *viewer, gpointer ref); }; GType gis_viewer_get_type(void); @@ -121,7 +127,8 @@ 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); +gpointer gis_viewer_add(GisViewer *self, GisObject *object, + gint level, gboolean sort); +void gis_viewer_remove(GisViewer *self, gpointer ref); #endif diff --git a/src/plugins/bmng.c b/src/plugins/bmng.c index 2d463c3..c7b65fe 100644 --- a/src/plugins/bmng.c +++ b/src/plugins/bmng.c @@ -123,6 +123,15 @@ static void _on_location_changed(GisViewer *viewer, g_thread_create(_update_tiles, self, FALSE, NULL); } +static gpointer _expose(GisCallback *callback, gpointer _self) +{ + GisPluginBmng *self = GIS_PLUGIN_BMNG(_self); + g_debug("GisPluginBmng: expose viewer=%p tiles=%p,%p", + self->viewer, self->tiles, self->tiles->data); + gis_viewer_render_tiles(self->viewer, self->tiles); + return NULL; +} + /*********** * Methods * ***********/ @@ -140,15 +149,11 @@ GisPluginBmng *gis_plugin_bmng_new(GisViewer *viewer) self->sigid = g_signal_connect(self->viewer, "location-changed", G_CALLBACK(_on_location_changed), self); - return self; -} + /* Add renderers */ + GisCallback *callback = gis_callback_new(_expose, self); + gis_viewer_add(viewer, GIS_OBJECT(callback), GIS_LEVEL_WORLD, 0); -static void gis_plugin_bmng_expose(GisPlugin *_self) -{ - GisPluginBmng *self = GIS_PLUGIN_BMNG(_self); - g_debug("GisPluginBmng: expose viewer=%p tiles=%p,%p", - self->viewer, self->tiles, self->tiles->data); - gis_viewer_render_tiles(self->viewer, self->tiles); + return self; } @@ -164,7 +169,6 @@ static void gis_plugin_bmng_plugin_init(GisPluginInterface *iface) { g_debug("GisPluginBmng: plugin_init"); /* Add methods to the interface */ - iface->expose = gis_plugin_bmng_expose; } /* Class/Object init */ static void gis_plugin_bmng_init(GisPluginBmng *self) diff --git a/src/plugins/srtm.c b/src/plugins/srtm.c index d0e4740..15e5b37 100644 --- a/src/plugins/srtm.c +++ b/src/plugins/srtm.c @@ -234,6 +234,16 @@ static void _on_location_changed(GisViewer *viewer, g_thread_create(_update_tiles, self, FALSE, NULL); } +static gpointer _expose(GisCallback *callback, gpointer _self) +{ + GisPluginSrtm *self = GIS_PLUGIN_SRTM(_self); + g_debug("GisPluginSrtm: expose tiles=%p data=%p", + self->tiles, self->tiles->data); + if (LOAD_OPENGL) + gis_viewer_render_tiles(self->viewer, self->tiles); + return NULL; +} + /*********** * Methods * ***********/ @@ -251,16 +261,11 @@ GisPluginSrtm *gis_plugin_srtm_new(GisViewer *viewer) self->sigid = g_signal_connect(self->viewer, "location-changed", G_CALLBACK(_on_location_changed), self); - return self; -} + /* Add renderers */ + GisCallback *callback = gis_callback_new(_expose, self); + gis_viewer_add(viewer, GIS_OBJECT(callback), GIS_LEVEL_WORLD, 0); -static void gis_plugin_srtm_expose(GisPlugin *_self) -{ - GisPluginSrtm *self = GIS_PLUGIN_SRTM(_self); - g_debug("GisPluginSrtm: expose tiles=%p data=%p", - self->tiles, self->tiles->data); - if (LOAD_OPENGL) - gis_viewer_render_tiles(self->viewer, self->tiles); + return self; } @@ -276,7 +281,6 @@ static void gis_plugin_srtm_plugin_init(GisPluginInterface *iface) { g_debug("GisPluginSrtm: plugin_init"); /* Add methods to the interface */ - iface->expose = gis_plugin_srtm_expose; } /* Class/Object init */ static void gis_plugin_srtm_init(GisPluginSrtm *self) diff --git a/src/plugins/test.c b/src/plugins/test.c index 5094758..edb9bc4 100644 --- a/src/plugins/test.c +++ b/src/plugins/test.c @@ -34,7 +34,8 @@ GisPluginTest *gis_plugin_test_new(GisViewer *viewer) GisMarker *marker = gis_marker_new("St. Charles"); gis_point_set_lle(gis_object_center(GIS_OBJECT(marker)), 38.841847, -90.491982, 0); - gis_viewer_add(self->viewer, GIS_OBJECT(marker)); + GIS_OBJECT(marker)->lod = EARTH_R/4; + gis_viewer_add(self->viewer, GIS_OBJECT(marker), GIS_LEVEL_OVERLAY, 0); return self; } -- 2.43.2