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"
49 static guint signals[NUM_SIGNALS];
51 void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick)
53 GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
56 g_warning("GritsObject: draw - Unimplemented");
60 /* Skip hidden objects */
64 /* Skip object with no signals when picking */
65 for (int i = 0; pick; i++) {
68 if (g_signal_has_handler_pending(object, signals[i], 0, FALSE))
72 /* Support GritsTester */
73 if (!GRITS_IS_OPENGL(opengl)) {
74 g_debug("GritsObject: draw - drawing raw object");
75 klass->draw(object, opengl);
79 /* Calculate distance for LOD and horizon tests */
80 GritsPoint *center = &object->center;
81 if ((!(object->skip & GRITS_SKIP_LOD) ||
82 !(object->skip & GRITS_SKIP_HORIZON)) &&
83 (center->elev != -EARTH_R)) {
85 gdouble eye[3], obj[3];
86 grits_viewer_get_location(GRITS_VIEWER(opengl),
87 &eye[0], &eye[1], &eye[2]);
88 gdouble elev = eye[2];
89 lle2xyz(eye[0], eye[1], eye[2],
90 &eye[0], &eye[1], &eye[2]);
91 lle2xyz(center->lat, center->lon, center->elev,
92 &obj[0], &obj[1], &obj[2]);
93 gdouble dist = distd(obj, eye);
95 /* Level of detail test */
96 if (!(object->skip & GRITS_SKIP_LOD)
98 if (object->lod < dist)
103 if (!(object->skip & GRITS_SKIP_HORIZON)) {
104 gdouble c = EARTH_R+elev;
106 gdouble horizon = sqrt(c*c - a*a);
112 /* Save state, draw, restore state */
113 g_mutex_lock(opengl->sphere_lock);
114 if (!(object->skip & GRITS_SKIP_STATE)) {
115 glPushAttrib(GL_ALL_ATTRIB_BITS);
116 glMatrixMode(GL_PROJECTION); glPushMatrix();
117 glMatrixMode(GL_MODELVIEW); glPushMatrix();
120 if (!(object->skip & GRITS_SKIP_CENTER))
121 grits_viewer_center_position(GRITS_VIEWER(opengl),
124 object->center.elev);
126 if (pick && klass->pick)
127 klass->pick(object, opengl);
129 klass->draw(object, opengl);
131 if (!(object->skip & GRITS_SKIP_STATE)) {
133 glMatrixMode(GL_PROJECTION); glPopMatrix();
134 glMatrixMode(GL_MODELVIEW); glPopMatrix();
136 g_mutex_unlock(opengl->sphere_lock);
141 * @object: the object
142 * @opengl: the viewer the object is being displayed in
144 * Perform any OpenGL commands necessasairy to draw the object.
146 * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be
147 * restored to the default state after the call to draw.
149 void grits_object_draw(GritsObject *object, GritsOpenGL *opengl)
151 grits_object_pickdraw(object, opengl, FALSE);
154 void grits_object_hide(GritsObject *object, gboolean hidden)
156 GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
157 object->hidden = hidden;
159 klass->hide(object, hidden);
162 void grits_object_queue_draw(GritsObject *object)
165 gtk_widget_queue_draw(GTK_WIDGET(object->viewer));
169 void grits_object_pick(GritsObject *object, GritsOpenGL *opengl)
171 grits_object_pickdraw(object, opengl, TRUE);
174 void grits_object_set_pointer(GritsObject *object, gboolean selected)
177 if (!object->state.selected)
178 g_signal_emit(object, signals[SIG_ENTER], 0);
179 object->state.selected = TRUE;
181 if (object->state.selected)
182 g_signal_emit(object, signals[SIG_LEAVE], 0);
183 object->state.selected = FALSE;
187 void grits_object_event(GritsObject *object, GdkEvent *event)
189 const int map[GDK_EVENT_LAST] = {
190 [GDK_BUTTON_PRESS ] SIG_BUTTON_PRESS,
191 [GDK_2BUTTON_PRESS ] SIG_BUTTON_PRESS,
192 [GDK_3BUTTON_PRESS ] SIG_BUTTON_PRESS,
193 [GDK_BUTTON_RELEASE] SIG_BUTTON_RELEASE,
194 [GDK_KEY_PRESS ] SIG_KEY_PRESS,
195 [GDK_KEY_RELEASE ] SIG_KEY_RELEASE,
196 [GDK_MOTION_NOTIFY ] SIG_MOTION,
198 if (!object->state.selected)
200 guint sig = map[event->type];
202 /* Handle button click */
203 if (sig == SIG_BUTTON_PRESS)
204 object->state.clicking = TRUE;
205 if (sig == SIG_BUTTON_RELEASE && object->state.clicking)
206 g_signal_emit(object, signals[SIG_CLICKED], 0, event);
207 if (sig == SIG_BUTTON_RELEASE || sig == SIG_MOTION)
208 object->state.clicking = FALSE;
210 /* Emit this signal */
211 if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE))
213 g_signal_emit(object, signals[sig], 0, event);
217 G_DEFINE_ABSTRACT_TYPE(GritsObject, grits_object, G_TYPE_OBJECT);
218 static void grits_object_init(GritsObject *object)
220 object->center.lat = 0;
221 object->center.lon = 0;
222 object->center.elev = -EARTH_R;
225 static void grits_object_class_init(GritsObjectClass *klass)
227 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
230 * GritsObject::enter:
231 * @object: the object.
233 * The ::enter signal is emitted when the pointer moves over the object
235 signals[SIG_ENTER] = g_signal_new(
237 G_TYPE_FROM_CLASS(gobject_class),
242 g_cclosure_marshal_VOID__VOID,
247 * GritsViewer::leave:
248 * @object: the object.
250 * The ::leave signal is emitted when the pointer moves away from the
253 signals[SIG_LEAVE] = g_signal_new(
255 G_TYPE_FROM_CLASS(gobject_class),
260 g_cclosure_marshal_VOID__VOID,
265 * GritsViewer::clicked:
266 * @object: the object.
268 * The ::clicked signal is emitted when the user clicks on the object
270 signals[SIG_CLICKED] = g_signal_new(
272 G_TYPE_FROM_CLASS(gobject_class),
277 g_cclosure_marshal_VOID__VOID,
282 * GritsViewer::button-press:
283 * @object: the object.
284 * @event: the GdkEventButton which triggered this signal
286 * The ::button-press signal is emitted when a button (typically from a
289 signals[SIG_BUTTON_PRESS] = g_signal_new(
291 G_TYPE_FROM_CLASS(gobject_class),
296 g_cclosure_marshal_VOID__POINTER,
302 * GritsViewer::button-release:
303 * @object: the object.
304 * @event: the GdkEventButton which triggered this signal
306 * The ::button-release signal is emitted when a button (typically from
307 * a mouse) is released.
309 signals[SIG_BUTTON_RELEASE] = g_signal_new(
311 G_TYPE_FROM_CLASS(gobject_class),
316 g_cclosure_marshal_VOID__POINTER,
322 * GritsViewer::key-press:
323 * @object: the object.
324 * @event: the GdkEventKey which triggered this signal
326 * The ::key-press signal is emitted when a key is pressed.
328 signals[SIG_KEY_PRESS] = g_signal_new(
330 G_TYPE_FROM_CLASS(gobject_class),
335 g_cclosure_marshal_VOID__POINTER,
341 * GritsViewer::key-release:
342 * @object: the object.
343 * @event: the GdkEventKey which triggered this signal
345 * The ::key-release signal is emitted when a key is released.
347 signals[SIG_KEY_RELEASE] = g_signal_new(
349 G_TYPE_FROM_CLASS(gobject_class),
354 g_cclosure_marshal_VOID__POINTER,
360 * GritsViewer::motion:
361 * @object: the object.
362 * @event: the GdkEventMotion which triggered this signal
364 * The ::motion signal is emitted the pointer moves over the object
366 signals[SIG_MOTION] = g_signal_new(
368 G_TYPE_FROM_CLASS(gobject_class),
373 g_cclosure_marshal_VOID__POINTER,