/*
- * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
+ * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
viewer->location[2] = ABS(viewer->location[2]);
}
+static void _grits_viewer_fix_rotation(GritsViewer *viewer)
+{
+ while (viewer->rotation[0] < -180) viewer->rotation[0] += 360;
+ while (viewer->rotation[0] > 180) viewer->rotation[0] -= 360;
+ while (viewer->rotation[1] < -180) viewer->rotation[1] += 360;
+ while (viewer->rotation[1] > 180) viewer->rotation[1] -= 360;
+ while (viewer->rotation[2] < -180) viewer->rotation[2] += 360;
+ while (viewer->rotation[2] > 180) viewer->rotation[2] -= 360;
+}
+
+static gboolean _grits_viewer_queue_draw_cb(gpointer _viewer)
+{
+ GritsViewer *viewer = _viewer;
+ g_mutex_lock(&viewer->draw_lock);
+ gtk_widget_queue_draw(GTK_WIDGET(viewer));
+ viewer->draw_source = 0;
+ g_mutex_unlock(&viewer->draw_lock);
+ return FALSE;
+}
+
/* Signal helpers */
static void _grits_viewer_emit_location_changed(GritsViewer *viewer)
{
static gboolean on_key_press(GritsViewer *viewer, GdkEventKey *event, gpointer _)
{
g_debug("GritsViewer: on_key_press - key=%x, state=%x, plus=%x",
- event->keyval, event->state, GDK_plus);
+ event->keyval, event->state, GDK_KEY_plus);
double lat, lon, elev, pan;
grits_viewer_get_location(viewer, &lat, &lon, &elev);
pan = MIN(elev/(EARTH_R/2), 30);
switch (event->keyval) {
- case GDK_Left: case GDK_h: grits_viewer_pan(viewer, 0, -pan, 0); break;
- case GDK_Down: case GDK_j: grits_viewer_pan(viewer, -pan, 0, 0); break;
- case GDK_Up: case GDK_k: grits_viewer_pan(viewer, pan, 0, 0); break;
- case GDK_Right: case GDK_l: grits_viewer_pan(viewer, 0, pan, 0); break;
- case GDK_minus: case GDK_o: grits_viewer_zoom(viewer, 10./9); break;
- case GDK_plus: case GDK_i: grits_viewer_zoom(viewer, 9./10); break;
- case GDK_H: grits_viewer_rotate(viewer, 0, 0, -2); break;
- case GDK_J: grits_viewer_rotate(viewer, 2, 0, 0); break;
- case GDK_K: grits_viewer_rotate(viewer, -2, 0, 0); break;
- case GDK_L: grits_viewer_rotate(viewer, 0, 0, 2); break;
+ case GDK_KEY_Left: case GDK_KEY_h: grits_viewer_pan(viewer, 0, -pan, 0); break;
+ case GDK_KEY_Down: case GDK_KEY_j: grits_viewer_pan(viewer, -pan, 0, 0); break;
+ case GDK_KEY_Up: case GDK_KEY_k: grits_viewer_pan(viewer, pan, 0, 0); break;
+ case GDK_KEY_Right: case GDK_KEY_l: grits_viewer_pan(viewer, 0, pan, 0); break;
+ case GDK_KEY_minus: case GDK_KEY_o: grits_viewer_zoom(viewer, 10./9); break;
+ case GDK_KEY_plus: case GDK_KEY_i: grits_viewer_zoom(viewer, 9./10); break;
+ case GDK_KEY_H: grits_viewer_rotate(viewer, 0, 0, -2); break;
+ case GDK_KEY_J: grits_viewer_rotate(viewer, 2, 0, 0); break;
+ case GDK_KEY_K: grits_viewer_rotate(viewer, -2, 0, 0); break;
+ case GDK_KEY_L: grits_viewer_rotate(viewer, 0, 0, 2); break;
}
return FALSE;
}
{
gdouble x = viewer->drag_x - event->x;
gdouble y = viewer->drag_y - event->y;
- gdouble lat, lon, elev, scale;
+ gdouble lat, lon, elev, scale, rx, ry, rz;
grits_viewer_get_location(GRITS_VIEWER(viewer), &lat, &lon, &elev);
- scale = elev/EARTH_R/15;
+ grits_viewer_get_rotation(GRITS_VIEWER(viewer), &rx, &ry, &rz);
+ scale = (elev/EARTH_R/14.1) * (sin(deg2rad(ABS(rx)))*4+1);
switch (viewer->drag_mode) {
- case GRITS_DRAG_PAN: grits_viewer_pan(viewer, -y*scale, x*scale, 0); break;
+ case GRITS_DRAG_PAN: grits_viewer_pan(viewer, -y*scale*0.782, x*scale, 0); break;
case GRITS_DRAG_ZOOM: grits_viewer_zoom(viewer, pow(2, -y/500)); break;
case GRITS_DRAG_TILT: grits_viewer_rotate(viewer, y/10, 0, x/10); break;
}
static void on_view_changed(GritsViewer *viewer,
gdouble _1, gdouble _2, gdouble _3)
{
- gtk_widget_queue_draw(GTK_WIDGET(viewer));
-}
-
-static void on_realize(GritsViewer *viewer)
-{
- GdkCursor *cursor = gdk_cursor_new(GDK_FLEUR);
- GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(viewer));
- gdk_window_set_cursor(window, cursor);
+ grits_viewer_queue_draw(viewer);
}
/***********
viewer->rotation[0] = x;
viewer->rotation[1] = y;
viewer->rotation[2] = z;
+ _grits_viewer_fix_rotation(viewer);
_grits_viewer_emit_rotation_changed(viewer);
}
void grits_viewer_get_rotation(GritsViewer *viewer, gdouble *x, gdouble *y, gdouble *z)
{
g_assert(GRITS_IS_VIEWER(viewer));
- g_debug("GritsViewer: get_rotation");
+ //g_debug("GritsViewer: get_rotation");
*x = viewer->rotation[0];
*y = viewer->rotation[1];
*z = viewer->rotation[2];
viewer->rotation[0] += x;
viewer->rotation[1] += y;
viewer->rotation[2] += z;
+ _grits_viewer_fix_rotation(viewer);
_grits_viewer_emit_rotation_changed(viewer);
}
return viewer->offline;
}
+/**
+ * grits_viewer_queue_draw:
+ * @viewer: the viewer
+ *
+ * Causes the viewer to redraw the screen. This has the safe effect as
+ * gtk_widget_queue_draw, but is thread safe, and probably faster.
+ */
+void grits_viewer_queue_draw(GritsViewer *viewer)
+{
+ g_mutex_lock(&viewer->draw_lock);
+ if (!viewer->draw_source)
+ viewer->draw_source = g_idle_add_full(G_PRIORITY_HIGH,
+ _grits_viewer_queue_draw_cb, viewer, NULL);
+ g_mutex_unlock(&viewer->draw_lock);
+}
+
/***********************************
* To be implemented by subclasses *
***********************************/
* grits_viewer_project:
* @viewer: the viewer
* @lat: the latitude
- * @lon: the latitude
- * @elev: the latitude
+ * @lon: the longitude
+ * @elev: the elevation
* @px: the project x coordinate
* @py: the project y coordinate
* @pz: the project z coordinate
klass->project(viewer, lat, lon, elev, px, py, pz);
}
+/**
+ * grits_viewer_unproject:
+ * @viewer: the viewer
+ * @x: x coordinate in screen space
+ * @y: y coordinate in screen space
+ * @z: z coordinate in screen space, or -1 to use the value
+ * from the depth buffer at x and y as the z value
+ * @lat: the latitude
+ * @lon: the longitude
+ * @elev: the elevation
+ *
+ * Project a x, y point in screen space to a latitude, longitude, and elevation
+ * point. Useful for finding the position of the cursor or another on-screen
+ * object in world coordinates.
+ */
+void grits_viewer_unproject(GritsViewer *viewer,
+ gdouble px, gdouble py, gdouble pz,
+ gdouble *lat, gdouble *lon, gdouble *elev)
+{
+ GritsViewerClass *klass = GRITS_VIEWER_GET_CLASS(viewer);
+ if (!klass->unproject)
+ g_warning("GritsViewer: unproject - Unimplemented");
+ klass->unproject(viewer, px, py, pz, lat, lon, elev);
+}
+
/**
* grits_viewer_clear_height_func:
* @viewer: the viewer
*
* The viewer steals the objects reference. Call g_object_ref if you plan on
* holding a reference as well.
- *
- * Returns: a handle to be pass to grits_viewer_remove()
*/
-gpointer grits_viewer_add(GritsViewer *viewer, GritsObject *object,
+void grits_viewer_add(GritsViewer *viewer, GritsObject *object,
gint level, gboolean sort)
{
GritsViewerClass *klass = GRITS_VIEWER_GET_CLASS(viewer);
if (!klass->add)
g_warning("GritsViewer: add - Unimplemented");
- object->ref = klass->add(viewer, object, level, sort);
object->viewer = viewer;
- return object;
+ klass->add(viewer, object, level, sort);
}
/**
* grits_viewer_remove:
* @viewer: the viewer
- * @ref: the handle obtained from grits_viewer_add()
- *
- * Remove an object from the viewer. The objects reference count is decremented
- * prior to being removed.
+ * @object: the object to remove
*
- * Returns: the #GritsObject referenced by the handle
+ * Remove an object from the viewer.
*/
-GritsObject *grits_viewer_remove(GritsViewer *viewer, gpointer _object)
+void grits_viewer_remove(GritsViewer *viewer, GritsObject *object)
{
- GritsObject *object = _object;
GritsViewerClass *klass = GRITS_VIEWER_GET_CLASS(viewer);
+ if (!object->viewer)
+ return;
if (!klass->remove)
g_warning("GritsViewer: remove - Unimplemented");
- klass->remove(viewer, object->ref);
- object->ref = NULL;
object->viewer = NULL;
- return object;
+ klass->remove(viewer, object);
}
/****************
viewer->time = time(NULL);
viewer->location[0] = 40;
viewer->location[1] = -100;
- viewer->location[2] = 1.5*EARTH_R;
+ viewer->location[2] = EARTH_R;
viewer->rotation[0] = 0;
viewer->rotation[1] = 0;
viewer->rotation[2] = 0;
+ g_mutex_init(&viewer->draw_lock);
+
g_object_set(viewer, "can-focus", TRUE, NULL);
gtk_widget_add_events(GTK_WIDGET(viewer),
GDK_BUTTON_PRESS_MASK |
g_signal_connect(viewer, "location-changed", G_CALLBACK(on_view_changed), NULL);
g_signal_connect(viewer, "rotation-changed", G_CALLBACK(on_view_changed), NULL);
-
- g_signal_connect(viewer, "realize", G_CALLBACK(on_realize), NULL);
+}
+static void grits_viewer_dispose(GObject *gobject)
+{
+ g_debug("GritsViewer: dispose");
+ GritsViewer *viewer = GRITS_VIEWER(gobject);
+ g_mutex_lock(&viewer->draw_lock);
+ if (viewer->draw_source)
+ g_source_remove(viewer->draw_source);
+ g_mutex_unlock(&viewer->draw_lock);
+ G_OBJECT_CLASS(grits_viewer_parent_class)->dispose(gobject);
}
static void grits_viewer_finalize(GObject *gobject)
{
g_debug("GritsViewer: finalize");
+ GritsViewer *viewer = GRITS_VIEWER(gobject);
+ g_mutex_clear(&viewer->draw_lock);
G_OBJECT_CLASS(grits_viewer_parent_class)->finalize(gobject);
+ g_debug("GritsViewer: finalize - done");
}
static void grits_viewer_class_init(GritsViewerClass *klass)
{
g_debug("GritsViewer: class_init");
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->dispose = grits_viewer_dispose;
gobject_class->finalize = grits_viewer_finalize;
/**