X-Git-Url: http://pileus.org/git/?p=grits;a=blobdiff_plain;f=src%2Fobjects%2Fgrits-object.c;h=65d7b420aae2e44e55e6585b327a385d104a273f;hp=735e62e2cb78ff5d8e0b9c964258d0115ce1f100;hb=7940344c1faea5b80fb39b44419b508568d3a6fc;hpb=4bef8517366b0195e321add06250e7d659434661 diff --git a/src/objects/grits-object.c b/src/objects/grits-object.c index 735e62e..65d7b42 100644 --- a/src/objects/grits-object.c +++ b/src/objects/grits-object.c @@ -16,43 +16,43 @@ */ /** - * SECTION:gis-object + * SECTION:grits-object * @short_description: Base class for drawing operations * - * Objects in libgis are things which can be added to the viewer and will be + * Objects in grits are things which can be added to the viewer and will be * displayed to the user. Each object has information such as it's location and * level of detail which are used by the viewer to determine which objects * should be drawn. * - * Each #GisObject is also a #GObject, but not every GObject in libgis is a - * GisObject. The "Object" part of the name is just coincidence. + * Each #GritsObject is also a #GObject, but not every GObject in grits is a + * GritsObject. The "Object" part of the name is just coincidence. */ #include #include #include -#include "gis-object.h" +#include "grits-object.h" +/* Constants */ +enum { + SIG_ENTER, + SIG_LEAVE, + SIG_CLICKED, + SIG_BUTTON_PRESS, + SIG_BUTTON_RELEASE, + SIG_KEY_PRESS, + SIG_KEY_RELEASE, + SIG_MOTION, + NUM_SIGNALS, +}; +static guint signals[NUM_SIGNALS]; -/************* - * 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) +void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick) { - GisObjectClass *klass = GIS_OBJECT_GET_CLASS(object); + GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object); if (!klass->draw) { - g_warning("GisObject: draw - Unimplemented"); + g_warning("GritsObject: draw - Unimplemented"); return; } @@ -60,47 +60,325 @@ void gis_object_draw(GisObject *object, GisOpenGL *opengl) if (object->hidden) return; - /* Skip out of range objects */ - if (object->lod > 0) { + /* Support GritsTester */ + if (!GRITS_IS_OPENGL(opengl)) { + g_debug("GritsObject: draw - drawing raw object"); + klass->draw(object, opengl); + return; + } + + /* Calculae distance for LOD and horizon tests */ + GritsPoint *center = &object->center; + if ((!(object->skip & GRITS_SKIP_LOD) || + !(object->skip & GRITS_SKIP_HORIZON)) && + (center->elev != -EARTH_R)) { /* LOD test */ gdouble eye[3], obj[3]; - gis_viewer_get_location(GIS_VIEWER(opengl), &eye[0], &eye[1], &eye[2]); + grits_viewer_get_location(GRITS_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]); + lle2xyz(eye[0], eye[1], eye[2], + &eye[0], &eye[1], &eye[2]); + lle2xyz(center->lat, center->lon, 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; + /* Level of detail test */ + if (!(object->skip & GRITS_SKIP_LOD) + && object->lod > 0) { + if (object->lod < dist) + return; + } + + /* Horizon test */ + if (!(object->skip & GRITS_SKIP_HORIZON)) { + 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(); + if (!(object->skip & GRITS_SKIP_STATE)) { + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_PROJECTION); glPushMatrix(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); + } - klass->draw(object, opengl); + if (!(object->skip & GRITS_SKIP_CENTER)) + grits_viewer_center_position(GRITS_VIEWER(opengl), + object->center.lat, + object->center.lon, + object->center.elev); - glPopAttrib(); - glMatrixMode(GL_PROJECTION); glPopMatrix(); - glMatrixMode(GL_MODELVIEW); glPopMatrix(); + if (pick && klass->pick) + klass->pick(object, opengl); + else + klass->draw(object, opengl); + + if (!(object->skip & GRITS_SKIP_STATE)) { + glPopAttrib(); + glMatrixMode(GL_PROJECTION); glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); + } g_mutex_unlock(opengl->sphere_lock); } +/** + * grits_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 grits_object_draw(GritsObject *object, GritsOpenGL *opengl) +{ + grits_object_pickdraw(object, opengl, FALSE); +} + +void grits_object_hide(GritsObject *object, gboolean hidden) +{ + GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object); + object->hidden = hidden; + if (klass->hide) + klass->hide(object, hidden); +} + +void grits_object_queue_draw(GritsObject *object) +{ + if (object->viewer) + gtk_widget_queue_draw(GTK_WIDGET(object->viewer)); +} + +/* Event handling */ +void grits_object_pick_begin(GritsObject *object, GritsOpenGL *opengl) +{ + object->state.picked = FALSE; + + /* Check for connected signals */ + for (int i = 0; i < NUM_SIGNALS; i++) { + if (g_signal_has_handler_pending(object, signals[i], 0, FALSE)) { + /* Someone is watching, render the object _once_ */ + glPushName((guint)object); + grits_object_pickdraw(object, opengl, TRUE); + glPopName(); + return; + } + } +} + +void grits_object_pick_pointer(GritsObject *object, double x, double y) +{ + object->state.picked = TRUE; +} + +void grits_object_pick_end(GritsObject *object) +{ + if (object->state.picked) { + if (!object->state.selected) + g_signal_emit(object, signals[SIG_ENTER], 0); + object->state.selected = TRUE; + } else { + if (object->state.selected) + g_signal_emit(object, signals[SIG_LEAVE], 0); + object->state.selected = FALSE; + } +} + +void grits_object_event(GritsObject *object, GdkEvent *event) +{ + const int map[GDK_EVENT_LAST] = { + [GDK_BUTTON_PRESS ] SIG_BUTTON_PRESS, + [GDK_2BUTTON_PRESS ] SIG_BUTTON_PRESS, + [GDK_3BUTTON_PRESS ] SIG_BUTTON_PRESS, + [GDK_BUTTON_RELEASE] SIG_BUTTON_RELEASE, + [GDK_KEY_PRESS ] SIG_KEY_PRESS, + [GDK_KEY_RELEASE ] SIG_KEY_RELEASE, + [GDK_MOTION_NOTIFY ] SIG_MOTION, + }; + if (!object->state.selected) + return; + guint sig = map[event->type]; + + /* Handle button click */ + if (sig == SIG_BUTTON_PRESS) + object->state.clicking = TRUE; + if (sig == SIG_BUTTON_RELEASE && object->state.clicking) + g_signal_emit(object, signals[SIG_CLICKED], 0, event); + if (sig == SIG_BUTTON_RELEASE || sig == SIG_MOTION) + object->state.clicking = FALSE; + + /* Emit this signal */ + if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE)) + return; + g_signal_emit(object, signals[sig], 0, event); +} + /* GObject stuff */ -G_DEFINE_ABSTRACT_TYPE(GisObject, gis_object, G_TYPE_OBJECT); -static void gis_object_init(GisObject *object) +G_DEFINE_ABSTRACT_TYPE(GritsObject, grits_object, G_TYPE_OBJECT); +static void grits_object_init(GritsObject *object) { + object->center.lat = 0; + object->center.lon = 0; + object->center.elev = -EARTH_R; } -static void gis_object_class_init(GisObjectClass *klass) +static void grits_object_class_init(GritsObjectClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + /** + * GritsObject::enter: + * @object: the object. + * + * The ::enter signal is emitted when the pointer moves over the object + */ + signals[SIG_ENTER] = g_signal_new( + "enter", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * GritsViewer::leave: + * @object: the object. + * + * The ::leave signal is emitted when the pointer moves away from the + * object + */ + signals[SIG_LEAVE] = g_signal_new( + "leave", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * GritsViewer::clicked: + * @object: the object. + * + * The ::clicked signal is emitted when the user clicks on the object + */ + signals[SIG_CLICKED] = g_signal_new( + "clicked", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * GritsViewer::button-press: + * @object: the object. + * @event: the GdkEventButton which triggered this signal + * + * The ::button-press signal is emitted when a button (typically from a + * mouse) is pressed. + */ + signals[SIG_BUTTON_PRESS] = g_signal_new( + "button-press", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::button-release: + * @object: the object. + * @event: the GdkEventButton which triggered this signal + * + * The ::button-release signal is emitted when a button (typically from + * a mouse) is released. + */ + signals[SIG_BUTTON_RELEASE] = g_signal_new( + "button-release", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::key-press: + * @object: the object. + * @event: the GdkEventKey which triggered this signal + * + * The ::key-press signal is emitted when a key is pressed. + */ + signals[SIG_KEY_PRESS] = g_signal_new( + "key-press", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::key-release: + * @object: the object. + * @event: the GdkEventKey which triggered this signal + * + * The ::key-release signal is emitted when a key is released. + */ + signals[SIG_KEY_RELEASE] = g_signal_new( + "key-release", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::motion: + * @object: the object. + * @event: the GdkEventMotion which triggered this signal + * + * The ::motion signal is emitted the pointer moves over the object + */ + signals[SIG_MOTION] = g_signal_new( + "motion", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); }