aboutsummaryrefslogtreecommitdiff
path: root/src/displaywindow.c
diff options
context:
space:
mode:
authortaw27 <taw27@bf6ca9ba-c028-0410-8290-897cf20841d1>2007-02-05 21:12:57 +0000
committertaw27 <taw27@bf6ca9ba-c028-0410-8290-897cf20841d1>2007-02-05 21:12:57 +0000
commit05b5d261682b9136fb46476a64eab6980b0dba64 (patch)
treed7faa450b69cf2104ffff7fc89a95914284d23af /src/displaywindow.c
Initial import
git-svn-id: svn://cook.msm.cam.ac.uk:745/diff-tomo/dtr@1 bf6ca9ba-c028-0410-8290-897cf20841d1
Diffstat (limited to 'src/displaywindow.c')
-rw-r--r--src/displaywindow.c543
1 files changed, 543 insertions, 0 deletions
diff --git a/src/displaywindow.c b/src/displaywindow.c
new file mode 100644
index 0000000..58c9e10
--- /dev/null
+++ b/src/displaywindow.c
@@ -0,0 +1,543 @@
+/*
+ * displaywindow.c
+ *
+ * The display window
+ *
+ * (c) 2007 Thomas White <taw27@cam.ac.uk>
+ * dtr - Diffraction Tomography Reconstruction
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <math.h>
+#include <gdk/gdkgl.h>
+#include <gtk/gtkgl.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#include "trackball.h"
+#include "reflections.h"
+#include "main.h"
+
+enum {
+ DW_ORTHO,
+ DW_PERSPECTIVE
+};
+
+GtkUIManager *displaywindow_ui;
+GtkActionGroup *displaywindow_action_group;
+GtkWidget *displaywindow_window;
+GtkWidget *displaywindow_bigvbox;
+GtkWidget *displaywindow_status_bar;
+int displaywindow_view = DW_ORTHO;
+GtkWidget *displaywindow_drawing_area;
+GLfloat displaywindow_distance = 150;
+GLfloat displaywindow_x_pos = 0;
+GLfloat displaywindow_y_pos = 0;
+
+void error_report(const char *message) {
+
+ GtkWidget *window;
+
+ window = gtk_message_dialog_new(GTK_WINDOW(displaywindow_window), GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, message);
+
+ g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
+ gtk_widget_show(window);
+
+}
+
+static void displaywindow_about() {
+
+ GtkWidget *window;
+
+ const gchar *authors[] = {
+ "Thomas White <taw27@cam.ac.uk>",
+ "Gordon Ball <gfb21@cam.ac.uk>",
+ "Paul Midgley <pam33@cam.ac.uk>",
+ NULL
+ };
+
+ window = gtk_about_dialog_new();
+
+ gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(window), PACKAGE_NAME);
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), PACKAGE_VERSION);
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window), "(c) 2006-2007 Thomas White <taw27@cam.ac.uk>");
+ gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window), "Diffraction Tomography Reconstruction");
+ gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window), "(c) 2006-2007 Thomas White <taw27@cam.ac.uk>\n"
+ "Virtual trackball (c) Copyright 1993, 1994, Silicon Graphics, Inc.\n"
+ "\n"
+ "Research funded by:\n"
+ "The Engineering and Physical Sciences Research Council\n"
+ "FEI Electron Optics B.V.");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window), "http://www-hrem.msm.cam.ac.uk/");
+ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors);
+
+ g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy), NULL);
+
+ gtk_widget_show_all(window);
+
+}
+
+static void displaywindow_close() {
+ gtk_exit(0);
+}
+
+static void displaywindow_gl_set_ortho(GLfloat w, GLfloat h) {
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ if ( w > h ) {
+ GLfloat aspect = w/h;
+ glOrtho(-aspect*(displaywindow_distance/2), aspect*(displaywindow_distance/2), -(displaywindow_distance/2), (displaywindow_distance/2), 2.0, 1000.0);
+ } else {
+ GLfloat aspect = h/w;
+ glOrtho(-(displaywindow_distance/2), (displaywindow_distance/2), -aspect*(displaywindow_distance/2), aspect*(displaywindow_distance/2), 2.0, 1000.0);
+ }
+ glMatrixMode(GL_MODELVIEW);
+
+}
+
+static void displaywindow_gl_set_perspective(GLfloat w, GLfloat h) {
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ if ( w > h ) {
+ GLfloat aspect = w/h;
+ glFrustum(-aspect, aspect, -1.0, 1.0, 2.0, 1000.0);
+ } else {
+ GLfloat aspect = h/w;
+ glFrustum(-1.0, 1.0, -aspect, aspect, 2.0, 1000.0);
+ }
+ glMatrixMode(GL_MODELVIEW);
+
+}
+
+static gint displaywindow_changeview(GtkWidget *widget, GtkRadioAction *action) {
+
+ GLfloat w = displaywindow_drawing_area->allocation.width;
+ GLfloat h = displaywindow_drawing_area->allocation.height;
+ displaywindow_view = gtk_radio_action_get_current_value(action);
+
+ if ( displaywindow_view == DW_ORTHO ) {
+ displaywindow_gl_set_ortho(w, h);
+ } else {
+ displaywindow_gl_set_perspective(w, h);
+ }
+
+ return 0;
+
+}
+
+static void displaywindow_addui_callback(GtkUIManager *ui, GtkWidget *widget, GtkContainer *container) {
+
+ gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
+
+ /* Enable overflow menu if this is a toolbar */
+ if ( GTK_IS_TOOLBAR(widget) ) {
+ gtk_toolbar_set_show_arrow(GTK_TOOLBAR(widget), TRUE);
+ }
+
+}
+
+static void displaywindow_addmenubar() {
+
+ GtkActionEntry entries[] = {
+
+ { "FileAction", NULL, "_File", NULL, NULL, NULL },
+ { "SaveAction", GTK_STOCK_SAVE, "_Save Image...", NULL, NULL, G_CALLBACK(NULL) },
+ { "CloseAction", GTK_STOCK_CLOSE, "_Close", NULL, NULL, G_CALLBACK(displaywindow_close) },
+
+ { "ViewAction", NULL, "_View", NULL, NULL, NULL },
+
+ { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
+
+ { "HelpAction", NULL, "_Help", NULL, NULL, NULL },
+ { "AboutAction", GTK_STOCK_ABOUT, "_About DTR...", NULL, NULL, G_CALLBACK(displaywindow_about) },
+
+ };
+ guint n_entries = G_N_ELEMENTS(entries);
+ GtkRadioActionEntry toggles[] = {
+ { "OrthoAction", NULL, "_Orthographic", NULL, NULL, DW_ORTHO },
+ { "PerspectiveAction", NULL, "_Perspective", NULL, NULL, DW_PERSPECTIVE },
+ };
+ guint n_toggles = G_N_ELEMENTS(toggles);
+
+ GError *error = NULL;
+
+ displaywindow_action_group = gtk_action_group_new("dtrdisplaywindow");
+ gtk_action_group_add_actions(displaywindow_action_group, entries, n_entries, displaywindow_window);
+ gtk_action_group_add_radio_actions(displaywindow_action_group, toggles, n_toggles, -1, G_CALLBACK(displaywindow_changeview), NULL);
+
+ displaywindow_ui = gtk_ui_manager_new();
+ gtk_ui_manager_insert_action_group(displaywindow_ui, displaywindow_action_group, 0);
+ g_signal_connect(displaywindow_ui, "add_widget", G_CALLBACK(displaywindow_addui_callback), displaywindow_bigvbox);
+ if ( gtk_ui_manager_add_ui_from_file(displaywindow_ui, DATADIR"/dtr/displaywindow.ui", &error) == 0 ) {
+ fprintf(stderr, "Error loading message window menu bar: %s\n", error->message);
+ return;
+ }
+
+ gtk_window_add_accel_group(GTK_WINDOW(displaywindow_window), gtk_ui_manager_get_accel_group(displaywindow_ui));
+ gtk_ui_manager_ensure_update(displaywindow_ui);
+
+}
+
+static float displaywindow_x_start = 0.0;
+static float displaywindow_y_start = 0.0;
+
+static float view_quat[4] = { 0.0, 0.0, 0.0, 1.0 };
+
+static gboolean displaywindow_gl_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) {
+ displaywindow_x_start = event->x;
+ displaywindow_y_start = event->y;
+ return FALSE;
+}
+
+static gint displaywindow_gl_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer data) {
+
+ float w = widget->allocation.width;
+ float h = widget->allocation.height;
+ float x = event->x;
+ float y = event->y;
+ float d_quat[4];
+
+ if ( event->state & GDK_CONTROL_MASK ) {
+
+ /* Control-click changes 'zoom' */
+ displaywindow_distance += event->y - displaywindow_y_start;
+ if ( displaywindow_view == DW_ORTHO ) {
+ displaywindow_gl_set_ortho(w, h);
+ }
+
+ } else if ( event->state & GDK_SHIFT_MASK ) {
+
+ /* Shift-click translates */
+ displaywindow_x_pos += (event->x - displaywindow_x_start)/5;
+ displaywindow_y_pos += (event->y - displaywindow_y_start)/5;
+
+ } else {
+
+ /* Click rotates */
+ trackball(d_quat, (2.0*displaywindow_x_start - w)/w, (h-2.0*displaywindow_y_start)/h, (2.0*x-w)/w, (h-2.0*y)/h);
+ add_quats(d_quat, view_quat, view_quat);
+
+ }
+
+ displaywindow_x_start = x;
+ displaywindow_y_start = y;
+
+ gdk_window_invalidate_rect(widget->window, &widget->allocation, FALSE);
+ return TRUE;
+}
+
+static gint displaywindow_gl_expose(GtkWidget *widget, GdkEventExpose *event, ControlContext *ctx) {
+
+ GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
+ GLfloat light0_position[] = { 0.0, 0.0, 100.0, 0.0 };
+ GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
+ GLfloat light0_specular[] = { 0.5, 0.5, 0.5, 1.0 };
+ GLfloat light1_position[] = { 0.0, 0.0, -100.0, 0.0 };
+ GLfloat light1_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
+ GLfloat light1_specular[] = { 0.5, 0.5, 0.5, 1.0 };
+ GLfloat green[] = { 0.0, 1.0, 0.0, 1.0 };
+ GLfloat blue[] = { 0.0, 0.0, 1.0, 1.0 };
+ GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 };
+ GLfloat gold[] = { 0.7, 0.7, 0.0, 1.0 };
+ GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 };
+ GLfloat yellow_glass[] = { 1.0, 1.0, 0.0, 000.1 };
+ float m[4][4];
+// GLfloat fog_density = 0.03;
+ Reflection *reflection;
+ GLUquadricObj *quadric;
+
+ if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) {
+ return 0;
+ }
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_DEPTH_TEST);
+// glEnable(GL_FOG);
+// glFogfv(GL_FOG_DENSITY, &fog_density);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glLoadIdentity();
+ glTranslatef(displaywindow_x_pos, -displaywindow_y_pos, -displaywindow_distance);
+ build_rotmatrix(m, view_quat);
+ glMultMatrixf(&m[0][0]);
+
+ /* Set up lighting */
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
+ glEnable(GL_LIGHT1);
+ glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
+
+ /* Bounding cube: 100 nm^-1 side length */
+ glBegin(GL_LINE_LOOP);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
+ glVertex3f(50, 50, 50);
+ glVertex3f(-50, 50, 50);
+ glVertex3f(-50, -50, 50);
+ glVertex3f(50, -50, 50);
+ glEnd();
+ glBegin(GL_LINE_LOOP);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
+ glVertex3f(50, 50, -50);
+ glVertex3f(-50, 50, -50);
+ glVertex3f(-50, -50, -50);
+ glVertex3f(50, -50, -50);
+ glEnd();
+ glBegin(GL_LINES);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
+ glVertex3f(50, 50, 50);
+ glVertex3f(50, 50, -50);
+ glVertex3f(-50, 50, 50);
+ glVertex3f(-50, 50, -50);
+ glVertex3f(-50, -50, 50);
+ glVertex3f(-50, -50, -50);
+ glVertex3f(50, -50, 50);
+ glVertex3f(50, -50, -50);
+ glEnd();
+
+ /* Tilt axis */
+ glBegin(GL_LINES);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
+ glVertex3f(50, 0.0, 0.0);
+ glVertex3f(-50, 0.0, 0.0);
+ glEnd();
+ glBegin(GL_TRIANGLE_FAN);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
+ glVertex3f(50, 0.0, 0.0);
+ glVertex3f(50-5, 1.0, 1.0);
+ glVertex3f(50-5, -1.0, 1.0);
+ glVertex3f(50-5, -1.0, -1.0);
+ glVertex3f(50-5, 1.0, -1.0);
+ glVertex3f(50-5, 1.0, 1.0);
+ glEnd();
+
+ /* Plot all the normal (measured) reflections */
+ reflection = ctx->reflectionctx->reflections;
+ glBegin(GL_POINTS);
+ do {
+ if ( reflection->type == REFLECTION_NORMAL ) {
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green);
+ glVertex3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9);
+ }
+ reflection = reflection->next;
+ } while ( reflection != NULL );
+ glEnd();
+
+ /* Plot the other reflections */
+ reflection = ctx->reflectionctx->reflections;
+ quadric = gluNewQuadric();
+ do {
+ if ( reflection->type == REFLECTION_CENTRAL ) {
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue);
+ glPushMatrix();
+ glTranslatef(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9);
+ gluSphere(quadric, 0.2, 32, 32);
+ glPopMatrix();
+ }
+ if ( reflection->type == REFLECTION_GENERATED ) {
+
+ /* Generated reflections are displayed by index, not coordinates.
+ xyz field in Reflection will be used later for "measured" location. */
+ double x, y, z;
+ signed int h, k, l;
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gold);
+ glPushMatrix();
+
+ /* Change hkl to xyz */
+ h = reflection->h; k = reflection->k; l = reflection->l;
+ x = h*ctx->reflectionctx->basis->a.x + k*ctx->reflectionctx->basis->b.x + l*ctx->reflectionctx->basis->c.x;
+ y = h*ctx->reflectionctx->basis->a.y + k*ctx->reflectionctx->basis->b.y + l*ctx->reflectionctx->basis->c.y;
+ z = h*ctx->reflectionctx->basis->a.z + k*ctx->reflectionctx->basis->b.z + l*ctx->reflectionctx->basis->c.z;
+ glTranslatef(x/1e9, y/1e9, z/1e9);
+
+ gluSphere(quadric, 0.2, 32, 32);
+ glPopMatrix();
+
+ }
+ reflection = reflection->next;
+ } while ( reflection != NULL );
+
+ /* If this is an iterative prediction-refinement reconstruction, draw the unit cell */
+ if ( ctx->rmode == RECONSTRUCTION_PREDICTION ) {
+ glBegin(GL_LINE_STRIP);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue);
+ glVertex3f(0.0, 0.0, 0.0);
+ glVertex3f(ctx->reflectionctx->basis->a.x/1e9, ctx->reflectionctx->basis->a.y/1e9, ctx->reflectionctx->basis->a.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(0.0, 0.0, 0.0);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9, ctx->reflectionctx->basis->c.y/1e9, ctx->reflectionctx->basis->c.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9, ctx->reflectionctx->basis->c.y/1e9, ctx->reflectionctx->basis->c.z/1e9);
+
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9,
+ ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9,
+ ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9);
+ glVertex3f(ctx->reflectionctx->basis->a.x/1e9, ctx->reflectionctx->basis->a.y/1e9, ctx->reflectionctx->basis->a.z/1e9);
+ glEnd();
+ }
+
+ /* Zero plane */
+ glBegin(GL_QUADS);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow_glass);
+ glVertex3f(50, 50, 0.0);
+ glVertex3f(50, -50, 0.0);
+ glVertex3f(-50, -50, 0.0);
+ glVertex3f(-50, 50, 0.0);
+ glEnd();
+
+ if ( gdk_gl_drawable_is_double_buffered(gldrawable) ) {
+ gdk_gl_drawable_swap_buffers(gldrawable);
+ } else {
+ glFlush();
+ }
+
+ gdk_gl_drawable_gl_end(gldrawable);
+
+ return 0;
+
+}
+
+static gint displaywindow_gl_realise(GtkWidget *widget, gpointer data) {
+
+ GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
+ GLfloat w = widget->allocation.width;
+ GLfloat h = widget->allocation.height;
+
+ if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) {
+ return 0;
+ }
+
+ glClearColor(0.002, 0.0, 0.1, 1.0);
+ glClearDepth(1.0);
+ displaywindow_gl_set_ortho(w, h);
+
+ gdk_gl_drawable_gl_end(gldrawable);
+
+ return 0;
+
+}
+
+static gboolean displaywindow_gl_configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data) {
+
+ GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
+ GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
+ GLfloat w = widget->allocation.width;
+ GLfloat h = widget->allocation.height;
+
+ /* Set viewport */
+ if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) {
+ return FALSE;
+ }
+ glViewport(0, 0, w, h);
+ gdk_gl_drawable_gl_end(gldrawable);
+
+ /* Nudge the projection matrix routines to preserve the aspect ratio */
+ if ( displaywindow_view == DW_ORTHO ) {
+ displaywindow_gl_set_ortho(w, h);
+ } else {
+ displaywindow_gl_set_perspective(w, h);
+ }
+
+ return FALSE;
+
+}
+
+static gint displaywindow_closedown(GtkWidget *widget, gpointer data) {
+
+ return 0;
+
+}
+
+void displaywindow_open(ControlContext *ctx) {
+
+ const char *filename;
+ char *title;
+ GdkGLConfig *glconfig;
+
+ filename = basename(ctx->filename);
+ title = malloc(10+strlen(filename));
+ strcpy(title, "dtr: ");
+ strcat(title, filename);
+
+ displaywindow_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(displaywindow_window), title);
+ free(title);
+ displaywindow_bigvbox = gtk_vbox_new(FALSE, FALSE);
+ gtk_container_add(GTK_CONTAINER(displaywindow_window), displaywindow_bigvbox);
+ displaywindow_addmenubar();
+
+ displaywindow_status_bar = gtk_statusbar_new();
+ gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(displaywindow_status_bar), FALSE);
+ gtk_box_pack_end(GTK_BOX(displaywindow_bigvbox), displaywindow_status_bar, FALSE, FALSE, 0);
+
+ g_signal_connect(GTK_OBJECT(displaywindow_window), "destroy", G_CALLBACK(displaywindow_closedown), NULL);
+ g_signal_connect_after(GTK_OBJECT(displaywindow_window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
+
+ /* GL stuff */
+ glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE);
+ if ( glconfig == NULL ) {
+ fprintf(stderr, "Can't find double-buffered visual.\n");
+ exit(1);
+ }
+ gtk_container_set_reallocate_redraws(GTK_CONTAINER(displaywindow_window), TRUE);
+ displaywindow_drawing_area = gtk_drawing_area_new();
+ gtk_widget_set_size_request(displaywindow_drawing_area, 640, 640);
+ gtk_widget_set_gl_capability(displaywindow_drawing_area, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
+ gtk_box_pack_start(GTK_BOX(displaywindow_bigvbox), displaywindow_drawing_area, TRUE, TRUE, 0);
+ gtk_widget_add_events(displaywindow_drawing_area, GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_VISIBILITY_NOTIFY_MASK);
+ g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "configure_event", G_CALLBACK(displaywindow_gl_configure), NULL);
+ g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "realize", G_CALLBACK(displaywindow_gl_realise), NULL);
+ g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "expose_event", G_CALLBACK(displaywindow_gl_expose), ctx);
+ g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "button_press_event", G_CALLBACK(displaywindow_gl_button_press), NULL);
+ g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "motion_notify_event", G_CALLBACK(displaywindow_gl_motion_notify), NULL);
+
+ gtk_widget_show_all(displaywindow_window);
+
+}