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 grits_viewer_queue_draw(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 = GRITS_CLICK_THRESHOLD;
215 if (sig == SIG_MOTION && object->state.clicking)
216 object->state.clicking -= 1;
217 if (sig == SIG_BUTTON_RELEASE && object->state.clicking)
218 g_signal_emit(object, signals[SIG_CLICKED], 0, event, &rval);
219 if (sig == SIG_BUTTON_RELEASE)
220 object->state.clicking = 0;
222 /* Emit this signal */
224 if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE))
226 g_signal_emit(object, signals[sig], 0, event, &rval);
230 g_debug("GritsObject: breaking chained event");
235 G_DEFINE_ABSTRACT_TYPE(GritsObject, grits_object, G_TYPE_OBJECT);
236 static void grits_object_init(GritsObject *object)
238 object->center.lat = 0;
239 object->center.lon = 0;
240 object->center.elev = -EARTH_R;
243 static void grits_object_class_init(GritsObjectClass *klass)
245 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
248 * GritsObject::enter:
249 * @object: the object.
251 * The ::enter signal is emitted when the pointer moves over the object
253 signals[SIG_ENTER] = g_signal_new(
255 G_TYPE_FROM_CLASS(gobject_class),
260 grits_cclosure_marshal_BOOLEAN__POINTER,
266 * GritsViewer::leave:
267 * @object: the object.
269 * The ::leave signal is emitted when the pointer moves away from the
272 signals[SIG_LEAVE] = g_signal_new(
274 G_TYPE_FROM_CLASS(gobject_class),
279 grits_cclosure_marshal_BOOLEAN__POINTER,
285 * GritsViewer::clicked:
286 * @object: the object.
288 * The ::clicked signal is emitted when the user clicks on the object
290 signals[SIG_CLICKED] = g_signal_new(
292 G_TYPE_FROM_CLASS(gobject_class),
297 grits_cclosure_marshal_BOOLEAN__POINTER,
303 * GritsViewer::button-press:
304 * @object: the object.
305 * @event: the GdkEventButton which triggered this signal
307 * The ::button-press signal is emitted when a button (typically from a
310 signals[SIG_BUTTON_PRESS] = g_signal_new(
312 G_TYPE_FROM_CLASS(gobject_class),
317 grits_cclosure_marshal_BOOLEAN__POINTER,
323 * GritsViewer::button-release:
324 * @object: the object.
325 * @event: the GdkEventButton which triggered this signal
327 * The ::button-release signal is emitted when a button (typically from
328 * a mouse) is released.
330 signals[SIG_BUTTON_RELEASE] = g_signal_new(
332 G_TYPE_FROM_CLASS(gobject_class),
337 grits_cclosure_marshal_BOOLEAN__POINTER,
343 * GritsViewer::key-press:
344 * @object: the object.
345 * @event: the GdkEventKey which triggered this signal
347 * The ::key-press signal is emitted when a key is pressed.
349 signals[SIG_KEY_PRESS] = g_signal_new(
351 G_TYPE_FROM_CLASS(gobject_class),
356 grits_cclosure_marshal_BOOLEAN__POINTER,
362 * GritsViewer::key-release:
363 * @object: the object.
364 * @event: the GdkEventKey which triggered this signal
366 * The ::key-release signal is emitted when a key is released.
368 signals[SIG_KEY_RELEASE] = g_signal_new(
370 G_TYPE_FROM_CLASS(gobject_class),
375 grits_cclosure_marshal_BOOLEAN__POINTER,
381 * GritsViewer::motion:
382 * @object: the object.
383 * @event: the GdkEventMotion which triggered this signal
385 * The ::motion signal is emitted the pointer moves over the object
387 signals[SIG_MOTION] = g_signal_new(
389 G_TYPE_FROM_CLASS(gobject_class),
394 grits_cclosure_marshal_BOOLEAN__POINTER,