static gboolean on_motion_notify(GritsViewer *viewer, GdkEventMotion *event, gpointer _) { gdouble x = viewer->drag_x - event->x; gdouble y = viewer->drag_y - event->y; gdouble lat, lon, elev, scale, rx, ry, rz; grits_viewer_get_location(GRITS_VIEWER(viewer), &lat, &lon, &elev); grits_viewer_get_rotation(GRITS_VIEWER(viewer), &rx, &ry, &rz); scale = (elev/EARTH_R/15) * (sin(deg2rad(ABS(rx)))*4+1); switch (viewer->drag_mode) { case GRITS_DRAG_PAN: grits_viewer_pan(viewer, -y*scale, x*scale, 0); break; case GRITS_DRAG_ZOOM: grits_viewer_zoom(viewer, pow(2, -y/500)); break; case GRITS_DRAG_TILT: grits_viewer_rotate(viewer, y/10, 0, x/10); break; } viewer->drag_x = event->x; viewer->drag_y = event->y; return FALSE; }
/**************** * GObject code * ****************/ static void aweather_gui_parser_finished(GtkBuildable *_self, GtkBuilder *builder) { g_debug("AWeatherGui: parser finished"); AWeatherGui *self = AWEATHER_GUI(_self); self->builder = builder; /* Simple things */ gchar *config = g_build_filename(g_get_user_config_dir(), PACKAGE, "config.ini", NULL); gchar *defaults = g_build_filename(PKGDATADIR, "defaults.ini", NULL); self->prefs = grits_prefs_new(config, defaults); self->plugins = grits_plugins_new(PLUGINSDIR, self->prefs); self->viewer = GRITS_VIEWER(aweather_gui_get_widget(self, "main_viewer")); self->gtk_plugins = GTK_LIST_STORE(aweather_gui_get_object(self, "plugins")); grits_viewer_setup(self->viewer, self->plugins, self->prefs); g_free(config); g_free(defaults); /* Misc, helpers */ site_setup(self); menu_setup(self); time_setup(self); prefs_setup(self); icons_setup(self); /* Default size */ gint width = grits_prefs_get_integer(self->prefs, "aweather/width", NULL); gint height = grits_prefs_get_integer(self->prefs, "aweather/height", NULL); if (width && height) gtk_window_set_default_size(GTK_WINDOW(self), width, height); /* Connect signals */ gtk_builder_connect_signals(self->builder, self); g_signal_connect(self, "key-press-event", G_CALLBACK(on_gui_key_press), self); g_signal_connect_swapped(self->viewer, "offline", G_CALLBACK(gtk_toggle_action_set_active), aweather_gui_get_object(self, "offline")); g_signal_connect_swapped(self->viewer, "refresh", G_CALLBACK(set_update_timeout), self); g_signal_connect_swapped(self->viewer, "realize", G_CALLBACK(aweather_gui_load_plugins), self); }
/*********** * Helpers * ***********/ static void _set_visuals(GritsOpenGL *opengl) { double lat, lon, elev, rx, ry, rz; grits_viewer_get_location(GRITS_VIEWER(opengl), &lat, &lon, &elev); grits_viewer_get_rotation(GRITS_VIEWER(opengl), &rx, &ry, &rz); /* Set projection and clipping planes */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); double width = GTK_WIDGET(opengl)->allocation.width; double height = GTK_WIDGET(opengl)->allocation.height; double ang = atan(height/FOV_DIST); double atmos = 100000; double near = MAX(elev*0.75 - atmos, 50); // View 100km of atmosphere double far = elev + 2*EARTH_R + atmos; // on both sides of the earth grits_viewer_get_location(GRITS_VIEWER(opengl), &lat, &lon, &elev); glViewport(0, 0, width, height); gluPerspective(rad2deg(ang)*2, width/height, near, far); /* Setup camera and lighting */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Camera 1 */ glRotatef(rx, 1, 0, 0); glRotatef(rz, 0, 0, 1); /* Lighting */ #ifdef ROAM_DEBUG float light_ambient[] = {0.7f, 0.7f, 0.7f, 1.0f}; float light_diffuse[] = {2.0f, 2.0f, 2.0f, 1.0f}; #else float light_ambient[] = {0.2f, 0.2f, 0.2f, 1.0f}; float light_diffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; #endif float light_position[] = {-13*EARTH_R, 1*EARTH_R, 3*EARTH_R, 1.0f}; glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); float material_ambient[] = {1.0, 1.0, 1.0, 1.0}; float material_diffuse[] = {1.0, 1.0, 1.0, 1.0}; float material_specular[] = {0.0, 0.0, 0.0, 1.0}; float material_emission[] = {0.0, 0.0, 0.0, 1.0}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material_emission); glDisable(GL_TEXTURE_2D); glDisable(GL_COLOR_MATERIAL); /* Camera 2 */ glTranslatef(0, 0, -elev2rad(elev)); glRotatef(lat, 1, 0, 0); glRotatef(-lon, 0, 1, 0); glDisable(GL_ALPHA_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); #ifndef ROAM_DEBUG glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glClearDepth(1.0); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); #endif glEnable(GL_LINE_SMOOTH); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //glShadeModel(GL_FLAT); g_mutex_lock(opengl->sphere_lock); roam_sphere_update_view(opengl->sphere); g_mutex_unlock(opengl->sphere_lock); }
void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick) { GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object); if (!klass->draw) { g_warning("GritsObject: draw - Unimplemented"); return; } /* Skip hidden objects */ if (object->hidden) return; /* Skip object with no signals when picking */ for (int i = 0; pick; i++) { if (i == NUM_SIGNALS) return; if (g_signal_has_handler_pending(object, signals[i], 0, FALSE)) break; } /* Support GritsTester */ if (!GRITS_IS_OPENGL(opengl)) { g_debug("GritsObject: draw - drawing raw object"); klass->draw(object, opengl); return; } /* Calculate 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]; 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(center->lat, center->lon, center->elev, &obj[0], &obj[1], &obj[2]); gdouble dist = distd(obj, eye); /* 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); if (!(object->skip & GRITS_SKIP_STATE)) { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); } if (!(object->skip & GRITS_SKIP_CENTER)) grits_viewer_center_position(GRITS_VIEWER(opengl), object->center.lat, object->center.lon, object->center.elev); 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); }
/* Info */ static void info_expose(GritsCallback *compass, GritsOpenGL *opengl, gpointer _env) { GtkAllocation alloc; gtk_widget_get_allocation(GTK_WIDGET(opengl), &alloc); /* Create cairo surface */ guint tex = 0; const gchar *label0 = "Location: %7.3lf°, %8.3lf°, %4.0fm"; const gchar *label1 = "Cursor: %7.3lf°, %8.3lf°, %4.0fm"; gdouble width = 300; gdouble height = 200; cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cairo = cairo_create(surface); /* Text */ gdouble lat, lon, elev; grits_viewer_get_location(GRITS_VIEWER(opengl), &lat, &lon, &elev); gchar *text0 = g_strdup_printf(label0, lat, lon, elev); gchar *text1 = g_strdup_printf(label1, lat, lon, elev); /* Draw outline */ cairo_set_line_width(cairo, 3); cairo_set_source_rgba(cairo, 0, 0, 0, 0.75); cairo_move_to(cairo, 2, 20); cairo_text_path(cairo, text0); cairo_move_to(cairo, 2, 40); cairo_text_path(cairo, text1); cairo_stroke(cairo); /* Draw filler */ cairo_set_source_rgba(cairo, 1, 1, 1, 1); cairo_move_to(cairo, 2, 20); cairo_show_text(cairo, text0); cairo_move_to(cairo, 2, 40); cairo_show_text(cairo, text1); /* Setup pango */ PangoLayout *layout = pango_cairo_create_layout(cairo); PangoFontDescription *font = pango_font_description_from_string("Mono 9"); pango_layout_set_font_description(layout, font); pango_font_description_free(font); pango_layout_set_text(layout, text0, -1); pango_cairo_update_layout(cairo, layout); cairo_set_line_join(cairo, CAIRO_LINE_JOIN_ROUND); cairo_move_to(cairo, 2, 40); pango_cairo_layout_path(cairo, layout); for (float w = 0.2; w <= 0.8; w+=0.2) { cairo_set_line_width(cairo, (1-w)*8); cairo_set_source_rgba(cairo, 0, 0, 0, w); cairo_stroke_preserve(cairo); } cairo_set_source_rgba(cairo, 1, 1, 1, 1); pango_cairo_show_layout(cairo, layout); /* Load GL texture */ glEnable(GL_TEXTURE_2D); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(surface)); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* Draw surface */ glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); glDisable(GL_CULL_FACE); glTranslatef(alloc.width - width, alloc.height - height, 0); glBegin(GL_QUADS); glTexCoord2f(1, 0); glVertex3f(width, 0 , 0); // 0 - 3 0 glTexCoord2f(1, 1); glVertex3f(width, height, 0); // 1 - | | glTexCoord2f(0, 1); glVertex3f(0 , height, 0); // 2 - | | glTexCoord2f(0, 0); glVertex3f(0 , 0 , 0); // 3 - 2----1 glEnd(); }