2 * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * SECTION:grits-object
20 * @short_description: Base class for drawing operations
22 * Objects in grits are things which can be added to the viewer and will be
23 * displayed to the user. Each object has information such as it's location and
24 * level of detail which are used by the viewer to determine which objects
27 * Each #GritsObject is also a #GObject, but not every GObject in grits is a
28 * GritsObject. The "Object" part of the name is just coincidence.
35 #include "grits-object.h"
36 #include "grits-marshal.h"
50 static guint signals[NUM_SIGNALS];
52 void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick)
54 GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
57 g_warning("GritsObject: draw - Unimplemented");
61 /* Skip hidden objects */
65 /* Skip object with no signals when picking */
66 for (int i = 0; pick; i++) {
69 if (g_signal_has_handler_pending(object, signals[i], 0, FALSE))
73 /* Support GritsTester */
74 if (!GRITS_IS_OPENGL(opengl)) {
75 g_debug("GritsObject: draw - drawing raw object");
76 klass->draw(object, opengl);
80 /* Calculate distance for LOD and horizon tests */
81 GritsPoint *center = &object->center;
82 if ((!(object->skip & GRITS_SKIP_LOD) ||
83 !(object->skip & GRITS_SKIP_HORIZON)) &&
84 (center->elev != -EARTH_R)) {
86 gdouble eye[3], obj[3];
87 grits_viewer_get_location(GRITS_VIEWER(opengl),
88 &eye[0], &eye[1], &eye[2]);
89 gdouble elev = eye[2];
90 lle2xyz(eye[0], eye[1], eye[2],
91 &eye[0], &eye[1], &eye[2]);
92 lle2xyz(center->lat, center->lon, center->elev,
93 &obj[0], &obj[1], &obj[2]);
94 gdouble dist = distd(obj, eye);
96 /* Level of detail test */
97 if (!(object->skip & GRITS_SKIP_LOD)
99 if (object->lod < dist)
104 if (!(object->skip & GRITS_SKIP_HORIZON)) {
105 gdouble c = EARTH_R+elev;
107 gdouble horizon = sqrt(c*c - a*a);
113 /* Save state, draw, restore state */
114 g_mutex_lock(opengl->sphere_lock);
115 if (!(object->skip & GRITS_SKIP_STATE)) {
116 glPushAttrib(GL_ALL_ATTRIB_BITS);
117 glMatrixMode(GL_PROJECTION); glPushMatrix();
118 glMatrixMode(GL_MODELVIEW); glPushMatrix();
121 if (!(object->skip & GRITS_SKIP_CENTER))
122 grits_viewer_center_position(GRITS_VIEWER(opengl),
125 object->center.elev);
127 if (pick && klass->pick)
128 klass->pick(object, opengl);
130 klass->draw(object, opengl);
132 if (!(object->skip & GRITS_SKIP_STATE)) {
134 glMatrixMode(GL_PROJECTION); glPopMatrix();
135 glMatrixMode(GL_MODELVIEW); glPopMatrix();
137 g_mutex_unlock(opengl->sphere_lock);
142 * @object: the object
143 * @opengl: the viewer the object is being displayed in
145 * Perform any OpenGL commands necessasairy to draw the object.
147 * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be
148 * restored to the default state after the call to draw.
150 void grits_object_draw(GritsObject *object, GritsOpenGL *opengl)
152 grits_object_pickdraw(object, opengl, FALSE);
155 void grits_object_hide(GritsObject *object, gboolean hidden)
157 GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
158 object->hidden = hidden;
160 klass->hide(object, hidden);
163 void grits_object_queue_draw(GritsObject *object)
166 gtk_widget_queue_draw(GTK_WIDGET(object->viewer));
169 void grits_object_set_cursor(GritsObject *object, GdkCursorType cursor)
171 // Used by grits OpenGL
172 object->cursor = gdk_cursor_new(cursor);
176 void grits_object_pick(GritsObject *object, GritsOpenGL *opengl)
178 grits_object_pickdraw(object, opengl, TRUE);
181 gboolean grits_object_set_pointer(GritsObject *object, GdkEvent *event, gboolean selected)
183 gboolean rval = FALSE;
185 if (!object->state.selected)
186 g_signal_emit(object, signals[SIG_ENTER], 0, event, &rval);
187 object->state.selected = TRUE;
189 if (object->state.selected)
190 g_signal_emit(object, signals[SIG_LEAVE], 0, event, &rval);
191 object->state.selected = FALSE;
196 gboolean grits_object_event(GritsObject *object, GdkEvent *event)
198 const int map[GDK_EVENT_LAST] = {
199 [GDK_BUTTON_PRESS ] SIG_BUTTON_PRESS,
200 [GDK_2BUTTON_PRESS ] SIG_BUTTON_PRESS,
201 [GDK_3BUTTON_PRESS ] SIG_BUTTON_PRESS,
202 [GDK_BUTTON_RELEASE] SIG_BUTTON_RELEASE,
203 [GDK_KEY_PRESS ] SIG_KEY_PRESS,
204 [GDK_KEY_RELEASE ] SIG_KEY_RELEASE,
205 [GDK_MOTION_NOTIFY ] SIG_MOTION,
207 if (!object->state.selected)
209 guint sig = map[event->type];
210 gboolean rval = FALSE;
212 /* Handle button click */
213 if (sig == SIG_BUTTON_PRESS)
214 object->state.clicking = TRUE;
215 if (sig == SIG_BUTTON_RELEASE && object->state.clicking)
216 g_signal_emit(object, signals[SIG_CLICKED], 0, event, &rval);
217 if (sig == SIG_BUTTON_RELEASE || sig == SIG_MOTION)
218 object->state.clicking = FALSE;
220 /* Emit this signal */
222 if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE))
224 g_signal_emit(object, signals[sig], 0, event, &rval);
228 g_debug("GritsObject: breaking chained event");
233 G_DEFINE_ABSTRACT_TYPE(GritsObject, grits_object, G_TYPE_OBJECT);
234 static void grits_object_init(GritsObject *object)
236 object->center.lat = 0;
237 object->center.lon = 0;
238 object->center.elev = -EARTH_R;
241 static void grits_object_class_init(GritsObjectClass *klass)
243 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
246 * GritsObject::enter:
247 * @object: the object.
249 * The ::enter signal is emitted when the pointer moves over the object
251 signals[SIG_ENTER] = g_signal_new(
253 G_TYPE_FROM_CLASS(gobject_class),
258 grits_cclosure_marshal_BOOLEAN__POINTER,
264 * GritsViewer::leave:
265 * @object: the object.
267 * The ::leave signal is emitted when the pointer moves away from the
270 signals[SIG_LEAVE] = g_signal_new(
272 G_TYPE_FROM_CLASS(gobject_class),
277 grits_cclosure_marshal_BOOLEAN__POINTER,
283 * GritsViewer::clicked:
284 * @object: the object.
286 * The ::clicked signal is emitted when the user clicks on the object
288 signals[SIG_CLICKED] = g_signal_new(
290 G_TYPE_FROM_CLASS(gobject_class),
295 grits_cclosure_marshal_BOOLEAN__POINTER,
301 * GritsViewer::button-press:
302 * @object: the object.
303 * @event: the GdkEventButton which triggered this signal
305 * The ::button-press signal is emitted when a button (typically from a
308 signals[SIG_BUTTON_PRESS] = g_signal_new(
310 G_TYPE_FROM_CLASS(gobject_class),
315 grits_cclosure_marshal_BOOLEAN__POINTER,
321 * GritsViewer::button-release:
322 * @object: the object.
323 * @event: the GdkEventButton which triggered this signal
325 * The ::button-release signal is emitted when a button (typically from
326 * a mouse) is released.
328 signals[SIG_BUTTON_RELEASE] = g_signal_new(
330 G_TYPE_FROM_CLASS(gobject_class),
335 grits_cclosure_marshal_BOOLEAN__POINTER,
341 * GritsViewer::key-press:
342 * @object: the object.
343 * @event: the GdkEventKey which triggered this signal
345 * The ::key-press signal is emitted when a key is pressed.
347 signals[SIG_KEY_PRESS] = g_signal_new(
349 G_TYPE_FROM_CLASS(gobject_class),
354 grits_cclosure_marshal_BOOLEAN__POINTER,
360 * GritsViewer::key-release:
361 * @object: the object.
362 * @event: the GdkEventKey which triggered this signal
364 * The ::key-release signal is emitted when a key is released.
366 signals[SIG_KEY_RELEASE] = g_signal_new(
368 G_TYPE_FROM_CLASS(gobject_class),
373 grits_cclosure_marshal_BOOLEAN__POINTER,
379 * GritsViewer::motion:
380 * @object: the object.
381 * @event: the GdkEventMotion which triggered this signal
383 * The ::motion signal is emitted the pointer moves over the object
385 signals[SIG_MOTION] = g_signal_new(
387 G_TYPE_FROM_CLASS(gobject_class),
392 grits_cclosure_marshal_BOOLEAN__POINTER,