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/>.
20 * @short_description: Environment plugin
22 * #GritsPluginEnv provides environmental information such as sky images. It can
23 * also paint a blank overlay on the surface so that other plugins can draw
24 * transparent overlays nicely.
38 static void sky_expose(GritsCallback *sky, GritsOpenGL *opengl, gpointer _env)
40 GritsPluginEnv *env = GRITS_PLUGIN_ENV(_env);
41 g_debug("GritsPluginEnv: expose_sky");
43 gdouble lat, lon, elev;
44 grits_viewer_get_location(env->viewer, &lat, &lon, &elev);
47 gdouble rg = MAX(0, 1-(elev/40000));
48 gdouble blue = MAX(0, 1-(elev/100000));
49 glClearColor(MIN(0.4,rg), MIN(0.4,rg), MIN(1,blue), 1.0f);
50 glClear(GL_COLOR_BUFFER_BIT);
52 /* Attempt to render an atmosphere */
53 glEnable(GL_COLOR_MATERIAL);
54 glDisable(GL_CULL_FACE);
55 glDisable(GL_LIGHTING);
56 glMatrixMode(GL_MODELVIEW);
57 glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
58 grits_viewer_center_position(env->viewer, lat, lon, -EARTH_R);
60 gdouble ds = EARTH_R+elev; // distance to self
61 gdouble da = EARTH_R+300000; // distance to top of atmosphere
62 gdouble dg = EARTH_R-100000; // distance to top of atmosphere
63 gdouble ang = acos(EARTH_R/ds); // angle to horizon
66 gdouble ar = sin(ang)*da; // top of quad fan "atomosphere"j
67 gdouble az = cos(ang)*da; //
69 gdouble gr = sin(ang)*dg; // bottom of quad fan "ground"
70 gdouble gz = cos(ang)*dg; //
72 glBegin(GL_QUAD_STRIP);
73 for (gdouble i = 0; i <= 2*G_PI; i += G_PI/30) {
74 glColor4f(0.3, 0.3, 1.0, 1.0); glVertex3f(gr*sin(i), gr*cos(i), gz);
75 glColor4f(0.3, 0.3, 1.0, 0.0); glVertex3f(ar*sin(i), ar*cos(i), az);
81 static void compass_draw_compass(gdouble scale)
83 gfloat thick = scale * 0.20;
86 float light_ambient[] = {0.4f, 0.4f, 0.4f, 0.4f};
87 float light_diffuse[] = {0.9f, 0.9f, 0.9f, 1.0f};
88 float light_position[] = {-scale*2, -scale*4, -scale*0.5, 1.0f};
89 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
90 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
91 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
94 gdouble colors[][3] = {
100 gdouble points[][3] = {
119 glEnable(GL_POLYGON_OFFSET_FILL);
120 glPolygonOffset(1, 1);
121 for (int i = 0; i < G_N_ELEMENTS(colors); i++) {
122 gdouble *color = colors[i];
124 for (int j = 0; j < G_N_ELEMENTS(faces); j++) {
126 gdouble *v0 = points[faces[j][0]];
127 gdouble *v1 = points[faces[j][1]];
128 gdouble *v2 = points[faces[j][2]];
129 crossd3(v2, v1, v0, norm);
131 glBegin(GL_TRIANGLES);
137 glRotatef(90, 0, 0, 1);
141 glEnable(GL_POLYGON_OFFSET_LINE);
142 glDisable(GL_LIGHTING);
143 glPolygonOffset(0, 0);
144 glColor4f(0, 0, 0, 0.25);
146 for (int i = 0; i < G_N_ELEMENTS(colors); i++) {
147 glBegin(GL_LINE_STRIP);
148 for (int j = 0; j < G_N_ELEMENTS(outline); j++)
149 glVertex3dv(points[outline[j]]);
151 glRotatef(90, 0, 0, 1);
155 static void compass_expose(GritsCallback *compass, GritsOpenGL *opengl, gpointer _env)
157 GritsPluginEnv *env = GRITS_PLUGIN_ENV(_env);
158 g_debug("GritsPluginEnv: compass_expose");
160 grits_viewer_get_rotation(env->viewer, &x, &y, &z);
162 /* Setup projection */
164 gtk_widget_get_allocation(GTK_WIDGET(opengl), &alloc);
165 float scale = CLAMP(MIN(alloc.width,alloc.height)/2.0 * 0.1, 40, 100);
166 float offset = scale + 20;
167 glTranslatef(alloc.width - offset, offset, 0);
170 glClear(GL_DEPTH_BUFFER_BIT);
171 glEnable(GL_COLOR_MATERIAL);
172 glEnable(GL_DEPTH_TEST);
173 glDisable(GL_CULL_FACE);
174 glEnable(GL_POLYGON_SMOOTH);
175 glEnable(GL_LINE_SMOOTH);
178 x = CLAMP(x, -66, 66);;
179 glRotatef(x, 1, 0, 0);
180 glRotatef(-z, 0, 0, 1);
181 compass_draw_compass(scale);
184 static gboolean compass_click(GritsCallback *compass, GdkEvent *evnet, GritsViewer *viewer)
186 grits_viewer_set_rotation(viewer, 0, 0, 0);
191 static void info_expose(GritsCallback *compass, GritsOpenGL *opengl, gpointer _env)
194 gtk_widget_get_allocation(GTK_WIDGET(opengl), &alloc);
196 /* Create cairo surface */
198 const gchar *label0 = "Location: %7.3lf°, %8.3lf°, %4.0fm";
199 const gchar *label1 = "Cursor: %7.3lf°, %8.3lf°, %4.0fm";
201 gdouble height = 200;
202 cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
203 cairo_t *cairo = cairo_create(surface);
206 gdouble lat, lon, elev;
207 grits_viewer_get_location(GRITS_VIEWER(opengl), &lat, &lon, &elev);
208 gchar *text0 = g_strdup_printf(label0, lat, lon, elev);
209 gchar *text1 = g_strdup_printf(label1, lat, lon, elev);
212 cairo_set_line_width(cairo, 3);
213 cairo_set_source_rgba(cairo, 0, 0, 0, 0.75);
214 cairo_move_to(cairo, 2, 20); cairo_text_path(cairo, text0);
215 cairo_move_to(cairo, 2, 40); cairo_text_path(cairo, text1);
219 cairo_set_source_rgba(cairo, 1, 1, 1, 1);
220 cairo_move_to(cairo, 2, 20); cairo_show_text(cairo, text0);
221 cairo_move_to(cairo, 2, 40); cairo_show_text(cairo, text1);
224 PangoLayout *layout = pango_cairo_create_layout(cairo);
225 PangoFontDescription *font = pango_font_description_from_string("Mono 9");
226 pango_layout_set_font_description(layout, font);
227 pango_font_description_free(font);
228 pango_layout_set_text(layout, text0, -1);
229 pango_cairo_update_layout(cairo, layout);
230 cairo_set_line_join(cairo, CAIRO_LINE_JOIN_ROUND);
231 cairo_move_to(cairo, 2, 40);
232 pango_cairo_layout_path(cairo, layout);
233 for (float w = 0.2; w <= 0.8; w+=0.2) {
234 cairo_set_line_width(cairo, (1-w)*8);
235 cairo_set_source_rgba(cairo, 0, 0, 0, w);
236 cairo_stroke_preserve(cairo);
238 cairo_set_source_rgba(cairo, 1, 1, 1, 1);
239 pango_cairo_show_layout(cairo, layout);
241 /* Load GL texture */
242 glEnable(GL_TEXTURE_2D);
243 glGenTextures(1, &tex);
244 glBindTexture(GL_TEXTURE_2D, tex);
245 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
246 glPixelStorei(GL_PACK_ALIGNMENT, 1);
247 glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height,
248 0, GL_BGRA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(surface));
249 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
250 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
253 glDisable(GL_LIGHTING);
254 glDisable(GL_COLOR_MATERIAL);
255 glDisable(GL_DEPTH_TEST);
256 glEnable(GL_TEXTURE_2D);
257 glBindTexture(GL_TEXTURE_2D, tex);
258 glDisable(GL_CULL_FACE);
259 glTranslatef(alloc.width - width, alloc.height - height, 0);
261 glTexCoord2f(1, 0); glVertex3f(width, 0 , 0); // 0 - 3 0
262 glTexCoord2f(1, 1); glVertex3f(width, height, 0); // 1 - | |
263 glTexCoord2f(0, 1); glVertex3f(0 , height, 0); // 2 - | |
264 glTexCoord2f(0, 0); glVertex3f(0 , 0 , 0); // 3 - 2----1
272 * grits_plugin_env_new:
273 * @viewer: the #GritsViewer to use for drawing
274 * @prefs: the #GritsPrefs for storing configurations
276 * Create a new instance of the environment plugin.
278 * Returns: the new #GritsPluginEnv
280 GritsPluginEnv *grits_plugin_env_new(GritsViewer *viewer, GritsPrefs *prefs)
282 g_debug("GritsPluginEnv: new");
283 GritsPluginEnv *env = g_object_new(GRITS_TYPE_PLUGIN_ENV, NULL);
284 env->viewer = g_object_ref(viewer);
285 env->prefs = g_object_ref(prefs);
288 GritsCallback *sky = grits_callback_new(sky_expose, env);
289 grits_viewer_add(viewer, GRITS_OBJECT(sky), GRITS_LEVEL_BACKGROUND, FALSE);
290 env->refs = g_list_prepend(env->refs, sky);
293 GritsCallback *compass = grits_callback_new(compass_expose, env);
294 grits_viewer_add(viewer, GRITS_OBJECT(compass), GRITS_LEVEL_HUD, TRUE);
295 g_signal_connect(compass, "clicked", G_CALLBACK(compass_click), viewer);
296 grits_object_set_cursor(GRITS_OBJECT(compass), GDK_CROSS);
297 env->refs = g_list_prepend(env->refs, compass);
300 //GritsCallback *info = grits_callback_new(info_expose, env);
301 //grits_viewer_add(viewer, GRITS_OBJECT(info), GRITS_LEVEL_HUD, FALSE);
302 //env->refs = g_list_prepend(env->refs, info);
306 //GritsTile *background = grits_tile_new(NULL, NORTH, SOUTH, EAST, WEST);
307 //glGenTextures(1, &env->tex);
308 //background->data = &env->tex;
309 //grits_viewer_add(viewer, GRITS_OBJECT(background), GRITS_LEVEL_BACKGROUND, FALSE);
310 //env->refs = g_list_prepend(env->refs, background);
320 static void grits_plugin_env_plugin_init(GritsPluginInterface *iface);
321 G_DEFINE_TYPE_WITH_CODE(GritsPluginEnv, grits_plugin_env, G_TYPE_OBJECT,
322 G_IMPLEMENT_INTERFACE(GRITS_TYPE_PLUGIN,
323 grits_plugin_env_plugin_init));
324 static void grits_plugin_env_plugin_init(GritsPluginInterface *iface)
326 g_debug("GritsPluginEnv: plugin_init");
327 /* Add methods to the interface */
329 /* Class/Object init */
330 static void grits_plugin_env_init(GritsPluginEnv *env)
332 g_debug("GritsPluginEnv: init");
335 static void grits_plugin_env_dispose(GObject *gobject)
337 g_debug("GritsPluginEnv: dispose");
338 GritsPluginEnv *env = GRITS_PLUGIN_ENV(gobject);
339 /* Drop references */
341 for (GList *cur = env->refs; cur; cur = cur->next)
342 grits_object_destroy_pointer(&cur->data);
343 g_object_unref(env->viewer);
344 g_object_unref(env->prefs);
345 glDeleteTextures(1, &env->tex);
348 G_OBJECT_CLASS(grits_plugin_env_parent_class)->dispose(gobject);
350 static void grits_plugin_env_class_init(GritsPluginEnvClass *klass)
352 g_debug("GritsPluginEnv: class_init");
353 GObjectClass *gobject_class = (GObjectClass*)klass;
354 gobject_class->dispose = grits_plugin_env_dispose;