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.
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");
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
#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" */
}
-/********************
- * 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 *
*************/
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 */
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);
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)
* 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__
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
* #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
*
* 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;
+}
*
* 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;
};
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
*/
#include <config.h>
+#include <GL/gl.h>
#include "gis-marker.h"
-/*************
- * GisMarker *
- *************/
/**
* gis_marker_new:
* @label: a short description of the marker
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);
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)
{
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);
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;
}
*/
#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)
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
*/
#include <config.h>
+#include <GL/gl.h>
#include "gis-tile.h"
gchar *gis_tile_path_table[2][2] = {
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)
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;
}
/***********
* 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");