]> Pileus Git - grits/commitdiff
Move OpenGL code from GisOpenGL to objects
authorAndy Spencer <andy753421@gmail.com>
Sun, 24 Oct 2010 11:57:09 +0000 (11:57 +0000)
committerAndy Spencer <andy753421@gmail.com>
Mon, 25 Oct 2010 05:01:32 +0000 (05:01 +0000)
Add draw functions to GisObjectClass which should be set by subclasses.
This allows outside object types to be written in the normal way
(instead of always using GisCallback).

This also moves a lot of drawing code out of GisOpenGL which should
prevent it from becoming too big.

Unfortunately, there are some pesky dependency problems between
GisObject/GisViewer/GisOpenGL/GTK now. For example, Wms pulls in
GisTile, which pulls in GisViewer/GisViewer, which pulls in all of GTK.

12 files changed:
examples/plugin/teapot.c
src/data/Makefile.am
src/gis-opengl.c
src/gis-viewer.h
src/objects/Makefile.am
src/objects/gis-callback.c
src/objects/gis-callback.h
src/objects/gis-marker.c
src/objects/gis-object.c
src/objects/gis-object.h
src/objects/gis-tile.c
src/plugins/env.c

index 7916edeb9cf5c9a1332f2a7f33597403f79fd31a..bafcae3fdaea42e845ea81bdadae7ba462f61f8c 100644 (file)
@@ -35,7 +35,7 @@ static gboolean rotate(gpointer _teapot)
        return TRUE;
 }
 
-static void expose(GisCallback *callback, gpointer _teapot)
+static void expose(GisCallback *callback, GisOpenGL *opengl, gpointer _teapot)
 {
        GisPluginTeapot *teapot = GIS_PLUGIN_TEAPOT(_teapot);
        g_debug("GisPluginTeapot: expose");
index e6109eed67b3f874c4fb6687f17dcbd9a415fc01..cee179474a56e2c810cbdad7223cda415eab1496 100644 (file)
@@ -1,5 +1,5 @@
 AM_CFLAGS  = -Wall --std=gnu99 -I$(top_srcdir)/src
-AM_CFLAGS += $(GLIB_CFLAGS) $(SOUP_CFLAGS)
+AM_CFLAGS += $(GLIB_CFLAGS) $(GTK_CFLAGS) $(SOUP_CFLAGS)
 if NOTWIN32
 AM_CFLAGS += -fPIC
 endif
index 8b711426e123c7e76c60bc0b8d4c01af0de3662d..970984208e32d85f47dae5948e6833ec14fb5d4b 100644 (file)
 #include "gis-util.h"
 #include "roam.h"
 
-#include "objects/gis-object.h"
-#include "objects/gis-tile.h"
-#include "objects/gis-marker.h"
-#include "objects/gis-callback.h"
-
 // #define ROAM_DEBUG
 
 /* Tessellation, "finding intersecting triangles" */
@@ -122,251 +117,6 @@ static void _set_visuals(GisOpenGL *opengl)
 }
 
 
-/********************
- * Object handleing *
- ********************/
-static void _draw_tile(GisOpenGL *opengl, GisTile *tile, GList *triangles)
-{
-       if (!tile || !tile->data)
-               return;
-       if (!triangles)
-               g_warning("GisOpenGL: _draw_tiles - No triangles to draw: edges=%f,%f,%f,%f",
-                       tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
-       //g_message("drawing %4d triangles for tile edges=%7.2f,%7.2f,%7.2f,%7.2f",
-       //              g_list_length(triangles), tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
-       gdouble n = tile->edge.n;
-       gdouble s = tile->edge.s;
-       gdouble e = tile->edge.e;
-       gdouble w = tile->edge.w;
-
-       gdouble londist = e - w;
-       gdouble latdist = n - s;
-
-       gdouble xscale = tile->coords.e - tile->coords.w;
-       gdouble yscale = tile->coords.s - tile->coords.n;
-
-       for (GList *cur = triangles; cur; cur = cur->next) {
-               RoamTriangle *tri = cur->data;
-
-               gdouble lat[3] = {tri->p.r->lat, tri->p.m->lat, tri->p.l->lat};
-               gdouble lon[3] = {tri->p.r->lon, tri->p.m->lon, tri->p.l->lon};
-
-               if (lon[0] < -90 || lon[1] < -90 || lon[2] < -90) {
-                       if (lon[0] > 90) lon[0] -= 360;
-                       if (lon[1] > 90) lon[1] -= 360;
-                       if (lon[2] > 90) lon[2] -= 360;
-               }
-
-               gdouble xy[3][2] = {
-                       {(lon[0]-w)/londist, 1-(lat[0]-s)/latdist},
-                       {(lon[1]-w)/londist, 1-(lat[1]-s)/latdist},
-                       {(lon[2]-w)/londist, 1-(lat[2]-s)/latdist},
-               };
-
-               //if ((lat[0] == 90 && (xy[0][0] < 0 || xy[0][0] > 1)) ||
-               //    (lat[1] == 90 && (xy[1][0] < 0 || xy[1][0] > 1)) ||
-               //    (lat[2] == 90 && (xy[2][0] < 0 || xy[2][0] > 1)))
-               //      g_message("w,e=%4.f,%4.f   "
-               //                "lat,lon,x,y="
-               //                "%4.1f,%4.0f,%4.2f,%4.2f   "
-               //                "%4.1f,%4.0f,%4.2f,%4.2f   "
-               //                "%4.1f,%4.0f,%4.2f,%4.2f   ",
-               //              w,e,
-               //              lat[0], lon[0], xy[0][0], xy[0][1],
-               //              lat[1], lon[1], xy[1][0], xy[1][1],
-               //              lat[2], lon[2], xy[2][0], xy[2][1]);
-
-               /* Fix poles */
-               if (lat[0] == 90 || lat[0] == -90) xy[0][0] = 0.5;
-               if (lat[1] == 90 || lat[1] == -90) xy[1][0] = 0.5;
-               if (lat[2] == 90 || lat[2] == -90) xy[2][0] = 0.5;
-
-               /* Scale to tile coords */
-               for (int i = 0; i < 3; i++) {
-                       xy[i][0] = tile->coords.w + xy[i][0]*xscale;
-                       xy[i][1] = tile->coords.n + xy[i][1]*yscale;
-               }
-
-               glEnable(GL_TEXTURE_2D);
-               glEnable(GL_POLYGON_OFFSET_FILL);
-               glBindTexture(GL_TEXTURE_2D, *(guint*)tile->data);
-               glPolygonOffset(0, -tile->zindex);
-               glBegin(GL_TRIANGLES);
-               glNormal3dv(tri->p.r->norm); glTexCoord2dv(xy[0]); glVertex3dv((double*)tri->p.r);
-               glNormal3dv(tri->p.m->norm); glTexCoord2dv(xy[1]); glVertex3dv((double*)tri->p.m);
-               glNormal3dv(tri->p.l->norm); glTexCoord2dv(xy[2]); glVertex3dv((double*)tri->p.l);
-               glEnd();
-       }
-}
-
-static void _draw_tiles(GisOpenGL *opengl, GisTile *tile)
-{
-       /* Only draw children if possible */
-       gboolean has_children = FALSE;
-       GisTile *child;
-       gis_tile_foreach(tile, child)
-               if (child && child->data)
-                       has_children = TRUE;
-
-       GList *triangles = NULL;
-       if (has_children) {
-               /* TODO: simplify this */
-               const gdouble rows = G_N_ELEMENTS(tile->children);
-               const gdouble cols = G_N_ELEMENTS(tile->children[0]);
-               const gdouble lat_dist = tile->edge.n - tile->edge.s;
-               const gdouble lon_dist = tile->edge.e - tile->edge.w;
-               const gdouble lat_step = lat_dist / rows;
-               const gdouble lon_step = lon_dist / cols;
-               int row, col;
-               gis_tile_foreach_index(tile, row, col) {
-                       GisTile *child = tile->children[row][col];
-                       if (child && child->data) {
-                               _draw_tiles(opengl, child);
-                       } else {
-                               const gdouble n = tile->edge.n-(lat_step*(row+0));
-                               const gdouble s = tile->edge.n-(lat_step*(row+1));
-                               const gdouble e = tile->edge.w+(lon_step*(col+1));
-                               const gdouble w = tile->edge.w+(lon_step*(col+0));
-                               GList *these = roam_sphere_get_intersect(opengl->sphere,
-                                               FALSE, n, s, e, w);
-                               triangles = g_list_concat(triangles, these);
-                       }
-               }
-       } else {
-               triangles = roam_sphere_get_intersect(opengl->sphere, FALSE,
-                               tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
-       }
-       if (triangles)
-               _draw_tile(opengl, tile, triangles);
-       g_list_free(triangles);
-}
-
-static void _draw_marker(GisOpenGL *opengl, GisMarker *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);
-
-       gint win_width  = GTK_WIDGET(opengl)->allocation.width;
-       gint win_height = GTK_WIDGET(opengl)->allocation.height;
-       py = win_height - py;
-       if (pz > 1)
-               return;
-
-       //g_debug("GisOpenGL: draw_marker - %s pz=%f ", marker->label, pz);
-
-       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);
-
-       glDisable(GL_LIGHTING);
-       glDisable(GL_COLOR_MATERIAL);
-       glDisable(GL_DEPTH_TEST);
-       glEnable(GL_TEXTURE_2D);
-       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);
-       glEnd();
-}
-
-static void _draw_callback(GisOpenGL *opengl, GisCallback *callback)
-{
-       callback->callback(callback, callback->user_data);
-}
-
-static void _draw_object(GisOpenGL *opengl, GisObject *object)
-{
-       //g_debug("GisOpenGL: draw_object");
-       /* Skip hidden objects */
-       if (object->hidden)
-               return;
-
-       /* Skip out of range objects */
-       if (object->lod > 0) {
-               /* LOD test */
-               gdouble eye[3], obj[3];
-               gis_viewer_get_location(GIS_VIEWER(opengl), &eye[0], &eye[1], &eye[2]);
-               gdouble elev = 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;
-
-               /* Horizon testing */
-               gdouble c = EARTH_R+elev;
-               gdouble a = EARTH_R;
-               gdouble horizon = sqrt(c*c - a*a);
-               if (dist > horizon)
-                       return;
-       }
-
-       /* Draw */
-       glMatrixMode(GL_PROJECTION); glPushMatrix();
-       glMatrixMode(GL_MODELVIEW);  glPushMatrix();
-       glPushAttrib(GL_ALL_ATTRIB_BITS);
-       if (GIS_IS_MARKER(object)) {
-               _draw_marker(opengl, GIS_MARKER(object));
-       } else if (GIS_IS_CALLBACK(object)) {
-               _draw_callback(opengl, GIS_CALLBACK(object));
-       } else if (GIS_IS_TILE(object)) {
-               glEnable(GL_DEPTH_TEST);
-               glDepthFunc(GL_LESS);
-               g_mutex_lock(opengl->sphere_lock);
-               _draw_tiles(opengl, GIS_TILE(object));
-               g_mutex_unlock(opengl->sphere_lock);
-       }
-       glPopAttrib();
-       glMatrixMode(GL_PROJECTION); glPopMatrix();
-       glMatrixMode(GL_MODELVIEW);  glPopMatrix();
-}
-
-static void _load_object(GisOpenGL *opengl, GisObject *object)
-{
-       //g_debug("GisOpenGL: load_object");
-       if (GIS_IS_MARKER(object)) {
-               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);
-
-               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);
-       }
-}
-
-static void _unload_object(GisOpenGL *opengl, GisObject *object)
-{
-       //g_debug("GisOpenGL: unload_object");
-       if (GIS_IS_MARKER(object)) {
-               GisMarker *marker = GIS_MARKER(object);
-               glDeleteTextures(1, &marker->tex);
-       }
-}
-
-
 /*************
  * Callbacks *
  *************/
@@ -426,14 +176,14 @@ static gboolean _draw_level(gpointer key, gpointer value, gpointer user_data)
        glDepthMask(TRUE);
        glClear(GL_DEPTH_BUFFER_BIT);
        for (cur = level->unsorted.next; cur; cur = cur->next, nunsorted++)
-               _draw_object(opengl, GIS_OBJECT(cur->data));
+               gis_object_draw( GIS_OBJECT(cur->data), opengl);
 
        /* Freeze depth buffer and draw transparent objects sorted */
        /* TODO: sorting */
        //glDepthMask(FALSE);
        glAlphaFunc(GL_GREATER, 0.1);
        for (cur = level->sorted.next; cur; cur = cur->next, nsorted++)
-               _draw_object(opengl, GIS_OBJECT(cur->data));
+               gis_object_draw(GIS_OBJECT(cur->data), opengl);
 
        /* TODO: Prune empty levels */
 
@@ -619,7 +369,6 @@ static gpointer gis_opengl_add(GisViewer *_opengl, GisObject *object,
        g_assert(GIS_IS_OPENGL(_opengl));
        GisOpenGL *opengl = GIS_OPENGL(_opengl);
        g_mutex_lock(opengl->objects_lock);
-       _load_object(opengl, object);
        struct RenderLevel *level = g_tree_lookup(opengl->objects, (gpointer)key);
        if (!level) {
                level = g_new0(struct RenderLevel, 1);
@@ -645,7 +394,6 @@ static GisObject *gis_opengl_remove(GisViewer *_opengl, gpointer _link)
        g_mutex_lock(opengl->objects_lock);
        GList *link = _link;
        GisObject *object = link->data;
-       _unload_object(opengl, object);
        /* Just unlink and free it, link->prev is assured */
        link->prev->next = link->next;
        if (link->next)
index 848206866687ee661549531d8f9f41eb81fcca6a..a4da4fc6a591fa2172699a23626e0724ccef9324 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/**
+ * Hack alert: gis-opengl.h needs to be included before gis-viewer
+ *   - GisViewer depends on GisObject for add/remove functions
+ *   - GisObject depends on GisOpenGL for load/unload functions
+ *   - GisOpenGL depends on GisViewer for inheritance
+ *
+ * The problem here is that GisOpenGL needs the GisViewer definition
+ * but GisViewer only needs the typedefs (through GisObject),
+ * so GisViewer needs to be included after the GisOpenGL typedefs but
+ * before the GisOpenGL definition. This is handled internally by
+ * gis-opengl.h
+ *
+ * This should probably be fixed, but making a GisGLObject interface
+ * seems like too much work. Merging GisViewer and GisOpenGL would also work,
+ * but I like the separate that that's provided by having two.
+ */
+#include "gis-opengl.h"
+
 #ifndef __GIS_VIEWER_H__
 #define __GIS_VIEWER_H__
 
index 5f7c256ce67e6e9a1025add992cbf6788b3ebd14..844352ff202c8ae93d48a6dcc3badd70311704a3 100644 (file)
@@ -1,5 +1,5 @@
 AM_CFLAGS  = -Wall --std=gnu99 -I$(top_srcdir)/src
-AM_CFLAGS += $(GLIB_CFLAGS) $(CAIRO_CFLAGS)
+AM_CFLAGS += $(GLIB_CFLAGS) $(GTK_CFLAGS) $(CAIRO_CFLAGS)
 if NOTWIN32
 AM_CFLAGS += -fPIC
 endif
index 9e6373757166c17bd46c8dbe2c36dba4e537d480..89dada46427be40eadbc3bef7e8e3297e02215bb 100644 (file)
  * #GisCallback objects are used for custom drawing functions. A common example
  * of this would be to render something which does not easily fit into a normal
  * object. For instance, a Heads-Up-Display overlay.
+ *
+ * Callbacks are an alternate to extending GisObject with a new class and
+ * should be used when only once instance of the object will be needed.
  */
 
 #include <config.h>
 #include "gis-callback.h"
 
-/* GisCallback */
-G_DEFINE_TYPE(GisCallback, gis_callback, GIS_TYPE_OBJECT);
-static void gis_callback_init(GisCallback *cb)
-{
-}
-
-static void gis_callback_class_init(GisCallbackClass *klass)
-{
-}
-
 /**
  * gis_callback_new:
  * @callback:  the function to call to draw the object
@@ -46,10 +39,30 @@ static void gis_callback_class_init(GisCallbackClass *klass)
  *
  * Returns: the new #GisCallback
  */
-GisCallback *gis_callback_new(GisCallbackFunc callback, gpointer user_data)
+GisCallback *gis_callback_new(GisCallbackFunc draw_cb, gpointer user_data)
 {
        GisCallback *cb = g_object_new(GIS_TYPE_CALLBACK, NULL);
-       cb->callback  = callback;
+       cb->draw      = draw_cb;
        cb->user_data = user_data;
        return cb;
 }
+
+/* Proxy class methods to per-object methods */
+static void proxy_draw(GisObject *_cb, GisOpenGL *opengl)
+{
+       GisCallback *cb = GIS_CALLBACK(_cb);
+       if (cb->draw)
+               cb->draw(cb, opengl, cb->user_data);
+}
+
+/* GisCallback */
+G_DEFINE_TYPE(GisCallback, gis_callback, GIS_TYPE_OBJECT);
+static void gis_callback_init(GisCallback *cb)
+{
+}
+
+static void gis_callback_class_init(GisCallbackClass *klass)
+{
+       GisObjectClass *object_class = GIS_OBJECT_CLASS(klass);
+       object_class->draw = proxy_draw;
+}
index b9c77da8a8fbefb9d96e2b56610ca4431e5434e3..db82739ce80328518e70342126f7083dd315f9d5 100644 (file)
@@ -40,11 +40,11 @@ typedef struct _GisCallbackClass GisCallbackClass;
  *
  * A function to be called when the callback object is being rendered
  */
-typedef void (*GisCallbackFunc)(GisCallback *callback, gpointer user_data);
+typedef void (*GisCallbackFunc)(GisCallback *callback, GisOpenGL *opengl, gpointer user_data);
 
 struct _GisCallback {
        GisObject       parent;
-       GisCallbackFunc callback;
+       GisCallbackFunc draw;
        gpointer        user_data;
 };
 
@@ -54,6 +54,6 @@ struct _GisCallbackClass {
 
 GType gis_callback_get_type(void);
 
-GisCallback *gis_callback_new(GisCallbackFunc callback, gpointer user_data);
+GisCallback *gis_callback_new(GisCallbackFunc draw_cb, gpointer user_data);
 
 #endif
index f02da47d7a9f2e8e8194d2a2bf5a0eb7a75124a9..3073b0f61c2532a1db25c949af7169f714e09cbb 100644 (file)
  */
 
 #include <config.h>
+#include <GL/gl.h>
 #include "gis-marker.h"
 
-/*************
- * GisMarker *
- *************/
 /**
  * gis_marker_new:
  * @label: a short description of the marker
@@ -57,7 +55,7 @@ GisMarker *gis_marker_new(const gchar *label)
        marker->yoff  = HEIGHT-(RADIUS+OUTLINE);
        marker->label = g_strdup(label);
        marker->cairo = cairo_create(cairo_image_surface_create(
-                               CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT));
+                       CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT));
 
        cairo_select_font_face(marker->cairo, "sans-serif",
                        CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
@@ -82,9 +80,64 @@ GisMarker *gis_marker_new(const gchar *label)
 
        cairo_move_to(marker->cairo, marker->xoff+4, marker->yoff-8);
        cairo_show_text(marker->cairo, marker->label);
+
+       /* Load GL texture */
+       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(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);
+
        return marker;
 }
 
+/* Drawing */
+static void gis_marker_draw(GisObject *_marker, GisOpenGL *opengl)
+{
+       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);
+
+       gint win_width  = GTK_WIDGET(opengl)->allocation.width;
+       gint win_height = GTK_WIDGET(opengl)->allocation.height;
+       py = win_height - py;
+       if (pz > 1)
+               return;
+
+       //g_debug("GisOpenGL: draw_marker - %s pz=%f ", marker->label, pz);
+
+       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);
+
+       glDisable(GL_LIGHTING);
+       glDisable(GL_COLOR_MATERIAL);
+       glDisable(GL_DEPTH_TEST);
+       glEnable(GL_TEXTURE_2D);
+       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);
+       glEnd();
+}
+
+/* GObject code */
 G_DEFINE_TYPE(GisMarker, gis_marker, GIS_TYPE_OBJECT);
 static void gis_marker_init(GisMarker *marker)
 {
@@ -92,8 +145,9 @@ static void gis_marker_init(GisMarker *marker)
 
 static void gis_marker_finalize(GObject *_marker)
 {
-       GisMarker *marker = GIS_MARKER(_marker);
        //g_debug("GisMarker: finalize - %s", marker->label);
+       GisMarker *marker = GIS_MARKER(_marker);
+       glDeleteTextures(1, &marker->tex);
        cairo_surface_t *surface = cairo_get_target(marker->cairo);
        cairo_surface_destroy(surface);
        cairo_destroy(marker->cairo);
@@ -102,5 +156,10 @@ static void gis_marker_finalize(GObject *_marker)
 
 static void gis_marker_class_init(GisMarkerClass *klass)
 {
-       G_OBJECT_CLASS(klass)->finalize = gis_marker_finalize;
+       g_debug("GisMarker: class_init");
+       GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+       gobject_class->finalize = gis_marker_finalize;
+
+       GisObjectClass *object_class = GIS_OBJECT_CLASS(klass);
+       object_class->draw = gis_marker_draw;
 }
index 9eff935f2efae3f0df77622f3fc7e029299faa46..735e62e2cb78ff5d8e0b9c964258d0115ce1f100 100644 (file)
  */
 
 #include <config.h>
+#include <math.h>
+#include <GL/gl.h>
+
 #include "gis-object.h"
 
 
 /*************
  * GisObject *
  *************/
+/**
+ * gis_object_draw:
+ * @object: the object
+ * @opengl: the viewer the object is being displayed in
+ *
+ * Perform any OpenGL commands necessasairy to draw the object.
+ *
+ * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be
+ * restored to the default state after the call to draw.
+ */
+void gis_object_draw(GisObject *object, GisOpenGL *opengl)
+{
+       GisObjectClass *klass = GIS_OBJECT_GET_CLASS(object);
+       if (!klass->draw) {
+               g_warning("GisObject: draw - Unimplemented");
+               return;
+       }
+
+       /* Skip hidden objects */
+       if (object->hidden)
+               return;
+
+       /* Skip out of range objects */
+       if (object->lod > 0) {
+               /* LOD test */
+               gdouble eye[3], obj[3];
+               gis_viewer_get_location(GIS_VIEWER(opengl), &eye[0], &eye[1], &eye[2]);
+               gdouble elev = 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;
+
+               /* Horizon testing */
+               gdouble c = EARTH_R+elev;
+               gdouble a = EARTH_R;
+               gdouble horizon = sqrt(c*c - a*a);
+               if (dist > horizon)
+                       return;
+       }
+
+       /* Save state, draw, restore state */
+       g_mutex_lock(opengl->sphere_lock);
+       glPushAttrib(GL_ALL_ATTRIB_BITS);
+       glMatrixMode(GL_PROJECTION); glPushMatrix();
+       glMatrixMode(GL_MODELVIEW);  glPushMatrix();
+
+       klass->draw(object, opengl);
+
+       glPopAttrib();
+       glMatrixMode(GL_PROJECTION); glPopMatrix();
+       glMatrixMode(GL_MODELVIEW);  glPopMatrix();
+       g_mutex_unlock(opengl->sphere_lock);
+}
+
 /* GObject stuff */
 G_DEFINE_ABSTRACT_TYPE(GisObject, gis_object, G_TYPE_OBJECT);
 static void gis_object_init(GisObject *object)
index 6763a5fd18a4425763712b27028fa7089cc27585..3060c64332a2d55366502859a9c598d0c0b10194 100644 (file)
@@ -40,12 +40,19 @@ struct _GisObject {
        gdouble  lod;
 };
 
+#include "gis-opengl.h"
 struct _GisObjectClass {
        GObjectClass parent_class;
+
+       /* Move some of these to GObject? */
+       void (*draw) (GisObject *object, GisOpenGL *opengl);
 };
 
 GType gis_object_get_type(void);
 
+/* Implemented by sub-classes */
+void gis_object_draw(GisObject *object, GisOpenGL *opengl);
+
 /**
  * gis_object_center:
  * @object: The #GisObject to get the center of
index 9ee747bc0666aafbf01c6dd54632b83fd059dfdc..14e699d270a00531f6ba79e3250922f559d1732e 100644 (file)
@@ -33,6 +33,7 @@
  */
 
 #include <config.h>
+#include <GL/gl.h>
 #include "gis-tile.h"
 
 gchar *gis_tile_path_table[2][2] = {
@@ -280,6 +281,132 @@ void gis_tile_free(GisTile *root, GisTileFreeFunc free_func, gpointer user_data)
        g_object_unref(root);
 }
 
+/* Draw a single tile */
+static void gis_tile_draw_one(GisTile *tile, GisOpenGL *opengl, GList *triangles)
+{
+       if (!tile || !tile->data)
+               return;
+       if (!triangles)
+               g_warning("GisOpenGL: _draw_tiles - No triangles to draw: edges=%f,%f,%f,%f",
+                       tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       //g_message("drawing %4d triangles for tile edges=%7.2f,%7.2f,%7.2f,%7.2f",
+       //              g_list_length(triangles), tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       gdouble n = tile->edge.n;
+       gdouble s = tile->edge.s;
+       gdouble e = tile->edge.e;
+       gdouble w = tile->edge.w;
+
+       gdouble londist = e - w;
+       gdouble latdist = n - s;
+
+       gdouble xscale = tile->coords.e - tile->coords.w;
+       gdouble yscale = tile->coords.s - tile->coords.n;
+
+       for (GList *cur = triangles; cur; cur = cur->next) {
+               RoamTriangle *tri = cur->data;
+
+               gdouble lat[3] = {tri->p.r->lat, tri->p.m->lat, tri->p.l->lat};
+               gdouble lon[3] = {tri->p.r->lon, tri->p.m->lon, tri->p.l->lon};
+
+               if (lon[0] < -90 || lon[1] < -90 || lon[2] < -90) {
+                       if (lon[0] > 90) lon[0] -= 360;
+                       if (lon[1] > 90) lon[1] -= 360;
+                       if (lon[2] > 90) lon[2] -= 360;
+               }
+
+               gdouble xy[3][2] = {
+                       {(lon[0]-w)/londist, 1-(lat[0]-s)/latdist},
+                       {(lon[1]-w)/londist, 1-(lat[1]-s)/latdist},
+                       {(lon[2]-w)/londist, 1-(lat[2]-s)/latdist},
+               };
+
+               //if ((lat[0] == 90 && (xy[0][0] < 0 || xy[0][0] > 1)) ||
+               //    (lat[1] == 90 && (xy[1][0] < 0 || xy[1][0] > 1)) ||
+               //    (lat[2] == 90 && (xy[2][0] < 0 || xy[2][0] > 1)))
+               //      g_message("w,e=%4.f,%4.f   "
+               //                "lat,lon,x,y="
+               //                "%4.1f,%4.0f,%4.2f,%4.2f   "
+               //                "%4.1f,%4.0f,%4.2f,%4.2f   "
+               //                "%4.1f,%4.0f,%4.2f,%4.2f   ",
+               //              w,e,
+               //              lat[0], lon[0], xy[0][0], xy[0][1],
+               //              lat[1], lon[1], xy[1][0], xy[1][1],
+               //              lat[2], lon[2], xy[2][0], xy[2][1]);
+
+               /* Fix poles */
+               if (lat[0] == 90 || lat[0] == -90) xy[0][0] = 0.5;
+               if (lat[1] == 90 || lat[1] == -90) xy[1][0] = 0.5;
+               if (lat[2] == 90 || lat[2] == -90) xy[2][0] = 0.5;
+
+               /* Scale to tile coords */
+               for (int i = 0; i < 3; i++) {
+                       xy[i][0] = tile->coords.w + xy[i][0]*xscale;
+                       xy[i][1] = tile->coords.n + xy[i][1]*yscale;
+               }
+
+               glEnable(GL_TEXTURE_2D);
+               glEnable(GL_POLYGON_OFFSET_FILL);
+               glBindTexture(GL_TEXTURE_2D, *(guint*)tile->data);
+               glPolygonOffset(0, -tile->zindex);
+               glBegin(GL_TRIANGLES);
+               glNormal3dv(tri->p.r->norm); glTexCoord2dv(xy[0]); glVertex3dv((double*)tri->p.r);
+               glNormal3dv(tri->p.m->norm); glTexCoord2dv(xy[1]); glVertex3dv((double*)tri->p.m);
+               glNormal3dv(tri->p.l->norm); glTexCoord2dv(xy[2]); glVertex3dv((double*)tri->p.l);
+               glEnd();
+       }
+}
+
+/* Draw the tile */
+static void gis_tile_draw_rec(GisTile *tile, GisOpenGL *opengl)
+{
+       /* Only draw children if possible */
+       gboolean has_children = FALSE;
+       GisTile *child;
+       gis_tile_foreach(tile, child)
+               if (child && child->data)
+                       has_children = TRUE;
+
+       GList *triangles = NULL;
+       if (has_children) {
+               /* TODO: simplify this */
+               const gdouble rows = G_N_ELEMENTS(tile->children);
+               const gdouble cols = G_N_ELEMENTS(tile->children[0]);
+               const gdouble lat_dist = tile->edge.n - tile->edge.s;
+               const gdouble lon_dist = tile->edge.e - tile->edge.w;
+               const gdouble lat_step = lat_dist / rows;
+               const gdouble lon_step = lon_dist / cols;
+               int row, col;
+               gis_tile_foreach_index(tile, row, col) {
+                       GisTile *child = tile->children[row][col];
+                       if (child && child->data) {
+                               gis_tile_draw_rec(child, opengl);
+                       } else {
+                               const gdouble n = tile->edge.n-(lat_step*(row+0));
+                               const gdouble s = tile->edge.n-(lat_step*(row+1));
+                               const gdouble e = tile->edge.w+(lon_step*(col+1));
+                               const gdouble w = tile->edge.w+(lon_step*(col+0));
+                               GList *these = roam_sphere_get_intersect(opengl->sphere,
+                                               FALSE, n, s, e, w);
+                               triangles = g_list_concat(triangles, these);
+                       }
+               }
+       } else {
+               triangles = roam_sphere_get_intersect(opengl->sphere, FALSE,
+                               tile->edge.n, tile->edge.s, tile->edge.e, tile->edge.w);
+       }
+       if (triangles)
+               gis_tile_draw_one(tile, opengl, triangles);
+       g_list_free(triangles);
+}
+
+static void gis_tile_draw(GisObject *tile, GisOpenGL *opengl)
+{
+       glEnable(GL_DEPTH_TEST);
+       glDepthFunc(GL_LESS);
+       gis_tile_draw_rec(GIS_TILE(tile), opengl);
+}
+
+
 /* GObject code */
 G_DEFINE_TYPE(GisTile, gis_tile, GIS_TYPE_OBJECT);
 static void gis_tile_init(GisTile *tile)
@@ -288,4 +415,7 @@ static void gis_tile_init(GisTile *tile)
 
 static void gis_tile_class_init(GisTileClass *klass)
 {
+       g_debug("GisTile: class_init");
+       GisObjectClass *object_class = GIS_OBJECT_CLASS(klass);
+       object_class->draw = gis_tile_draw;
 }
index 75ba5701cf3f897b0920b81457ea0cae099be434..1a0110c49a24def9c56d040d6daa937fda2b7ca9 100644 (file)
@@ -35,7 +35,7 @@
 /***********
  * Helpers *
  ***********/
-static void expose(GisCallback *callback, gpointer _env)
+static void expose(GisCallback *callback, GisOpenGL *opengl, gpointer _env)
 {
        GisPluginEnv *env = GIS_PLUGIN_ENV(_env);
        g_debug("GisPluginEnv: expose");