2 * Copyright (C) 2009-2010 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"
48 static guint signals[NUM_SIGNALS];
50 void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick)
52 GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
54 g_warning("GritsObject: draw - Unimplemented");
58 /* Skip hidden objects */
62 /* Support GritsTester */
63 if (!GRITS_IS_OPENGL(opengl)) {
64 g_debug("GritsObject: draw - drawing raw object");
65 klass->draw(object, opengl);
69 /* Calculae distance for LOD and horizon tests */
70 GritsPoint *center = &object->center;
71 if ((!(object->skip & GRITS_SKIP_LOD) ||
72 !(object->skip & GRITS_SKIP_HORIZON)) &&
73 (center->elev != -EARTH_R)) {
75 gdouble eye[3], obj[3];
76 grits_viewer_get_location(GRITS_VIEWER(opengl),
77 &eye[0], &eye[1], &eye[2]);
78 gdouble elev = eye[2];
79 lle2xyz(eye[0], eye[1], eye[2],
80 &eye[0], &eye[1], &eye[2]);
81 lle2xyz(center->lat, center->lon, center->elev,
82 &obj[0], &obj[1], &obj[2]);
83 gdouble dist = distd(obj, eye);
85 /* Level of detail test */
86 if (!(object->skip & GRITS_SKIP_LOD)
88 if (object->lod < dist)
93 if (!(object->skip & GRITS_SKIP_HORIZON)) {
94 gdouble c = EARTH_R+elev;
96 gdouble horizon = sqrt(c*c - a*a);
102 /* Save state, draw, restore state */
103 g_mutex_lock(opengl->sphere_lock);
104 if (!(object->skip & GRITS_SKIP_STATE)) {
105 glPushAttrib(GL_ALL_ATTRIB_BITS);
106 glMatrixMode(GL_PROJECTION); glPushMatrix();
107 glMatrixMode(GL_MODELVIEW); glPushMatrix();
110 if (!(object->skip & GRITS_SKIP_CENTER))
111 grits_viewer_center_position(GRITS_VIEWER(opengl),
114 object->center.elev);
116 if (pick && klass->pick)
117 klass->pick(object, opengl);
119 klass->draw(object, opengl);
121 if (!(object->skip & GRITS_SKIP_STATE)) {
123 glMatrixMode(GL_PROJECTION); glPopMatrix();
124 glMatrixMode(GL_MODELVIEW); glPopMatrix();
126 g_mutex_unlock(opengl->sphere_lock);
131 * @object: the object
132 * @opengl: the viewer the object is being displayed in
134 * Perform any OpenGL commands necessasairy to draw the object.
136 * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be
137 * restored to the default state after the call to draw.
139 void grits_object_draw(GritsObject *object, GritsOpenGL *opengl)
141 grits_object_pickdraw(object, opengl, FALSE);
144 void grits_object_hide(GritsObject *object, gboolean hidden)
146 GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object);
147 object->hidden = hidden;
149 klass->hide(object, hidden);
152 void grits_object_queue_draw(GritsObject *object)
155 gtk_widget_queue_draw(GTK_WIDGET(object->viewer));
159 void grits_object_pick_begin(GritsObject *object, GritsOpenGL *opengl)
161 object->state.picked = FALSE;
163 /* Check for connected signals */
164 for (int i = 0; i < NUM_SIGNALS; i++) {
165 if (g_signal_has_handler_pending(object, signals[i], 0, FALSE)) {
166 /* Someone is watching, render the object _once_ */
167 glPushName((guint)object);
168 grits_object_pickdraw(object, opengl, TRUE);
175 void grits_object_pick_pointer(GritsObject *object, double x, double y)
177 object->state.picked = TRUE;
180 void grits_object_pick_end(GritsObject *object)
182 if (object->state.picked) {
183 if (!object->state.selected)
184 g_signal_emit(object, signals[SIG_ENTER], 0);
185 object->state.selected = TRUE;
187 if (object->state.selected)
188 g_signal_emit(object, signals[SIG_LEAVE], 0);
189 object->state.selected = FALSE;
193 void grits_object_event(GritsObject *object, GdkEvent *event)
195 const int map[GDK_EVENT_LAST] = {
196 [GDK_BUTTON_PRESS ] SIG_BUTTON_PRESS,
197 [GDK_2BUTTON_PRESS ] SIG_BUTTON_PRESS,
198 [GDK_3BUTTON_PRESS ] SIG_BUTTON_PRESS,
199 [GDK_BUTTON_RELEASE] SIG_BUTTON_RELEASE,
200 [GDK_KEY_PRESS ] SIG_KEY_PRESS,
201 [GDK_KEY_RELEASE ] SIG_KEY_RELEASE,
202 [GDK_MOTION_NOTIFY ] SIG_MOTION,
204 if (!object->state.selected)
206 guint sig = signals[map[event->type]];
207 if (!g_signal_has_handler_pending(object, sig, 0, FALSE))
209 g_signal_emit(object, sig, 0, event);
213 G_DEFINE_ABSTRACT_TYPE(GritsObject, grits_object, G_TYPE_OBJECT);
214 static void grits_object_init(GritsObject *object)
216 object->center.lat = 0;
217 object->center.lon = 0;
218 object->center.elev = -EARTH_R;
221 static void grits_object_class_init(GritsObjectClass *klass)
223 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
226 * GritsObject::enter:
227 * @object: the object.
229 * The ::enter signal is emitted when the pointer moves over the object
231 signals[SIG_ENTER] = g_signal_new(
233 G_TYPE_FROM_CLASS(gobject_class),
238 g_cclosure_marshal_VOID__VOID,
243 * GritsViewer::leave:
244 * @object: the object.
246 * The ::leave signal is emitted when the pointer moves away from the
249 signals[SIG_LEAVE] = g_signal_new(
251 G_TYPE_FROM_CLASS(gobject_class),
256 g_cclosure_marshal_VOID__VOID,
261 * GritsViewer::button-press:
262 * @object: the object.
263 * @event: the GdkEventButton which triggered this signal
265 * The ::button-press signal is emitted when a button (typically from a
268 signals[SIG_BUTTON_PRESS] = g_signal_new(
270 G_TYPE_FROM_CLASS(gobject_class),
275 g_cclosure_marshal_VOID__POINTER,
281 * GritsViewer::button-release:
282 * @object: the object.
283 * @event: the GdkEventButton which triggered this signal
285 * The ::button-release signal is emitted when a button (typically from
286 * a mouse) is released.
288 signals[SIG_BUTTON_RELEASE] = g_signal_new(
290 G_TYPE_FROM_CLASS(gobject_class),
295 g_cclosure_marshal_VOID__POINTER,
301 * GritsViewer::key-press:
302 * @object: the object.
303 * @event: the GdkEventKey which triggered this signal
305 * The ::key-press signal is emitted when a key is pressed.
307 signals[SIG_KEY_PRESS] = g_signal_new(
309 G_TYPE_FROM_CLASS(gobject_class),
314 g_cclosure_marshal_VOID__POINTER,
320 * GritsViewer::key-release:
321 * @object: the object.
322 * @event: the GdkEventKey which triggered this signal
324 * The ::key-release signal is emitted when a key is released.
326 signals[SIG_KEY_RELEASE] = g_signal_new(
328 G_TYPE_FROM_CLASS(gobject_class),
333 g_cclosure_marshal_VOID__POINTER,
339 * GritsViewer::motion:
340 * @object: the object.
341 * @event: the GdkEventMotion which triggered this signal
343 * The ::motion signal is emitted the pointer moves over the object
345 signals[SIG_MOTION] = g_signal_new(
347 G_TYPE_FROM_CLASS(gobject_class),
352 g_cclosure_marshal_VOID__POINTER,