/* * displaywindow.c * * The display window * * (c) 2007 Thomas White * * dtr - Diffraction Tomography Reconstruction * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #define GL_GLEXT_PROTOTYPES 1 #include #include #include #include "trackball.h" #include "reflections.h" #include "main.h" #include "displaywindow.h" #include "basis.h" #include "dirax.h" #include "reproject.h" #include "cache.h" #include "mapping.h" #include "refine.h" static void displaywindow_gl_set_ortho(DisplayWindow *dw, GLfloat w, GLfloat h) { GLfloat aspect = w/h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-aspect*(dw->distance/2.0), aspect*(dw->distance/2.0), -(dw->distance/2.0), (dw->distance/2.0), 0.001, 400.0); glMatrixMode(GL_MODELVIEW); } static void displaywindow_gl_set_perspective(DisplayWindow *dw, GLfloat w, GLfloat h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0, w/h, 0.001, 400.0); glMatrixMode(GL_MODELVIEW); } static gint displaywindow_changeview(GtkWidget *widget, GtkRadioAction *action, DisplayWindow *dw) { GLfloat w = dw->drawing_area->allocation.width; GLfloat h = dw->drawing_area->allocation.height; dw->view = gtk_radio_action_get_current_value(action); if ( dw->view == DW_ORTHO ) { displaywindow_gl_set_ortho(dw, w, h); } else { displaywindow_gl_set_perspective(dw, w, h); } return 0; } static gboolean displaywindow_gl_button_press(GtkWidget *widget, GdkEventButton *event, DisplayWindow *dw) { dw->x_start = event->x; dw->y_start = event->y; return FALSE; } static gint displaywindow_gl_motion_notify(GtkWidget *widget, GdkEventMotion *event, DisplayWindow *dw) { 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' */ dw->distance += event->y - dw->y_start; if ( dw->distance < 1.0 ) dw->distance = 1.0; if ( dw->distance > 310.0 ) dw->distance = 310.0; if ( dw->view == DW_ORTHO ) { displaywindow_gl_set_ortho(dw, w, h); } else { displaywindow_gl_set_perspective(dw, w, h); } } else if ( event->state & GDK_SHIFT_MASK ) { /* Shift-click translates */ dw->x_pos += (event->x - dw->x_start)/5; dw->y_pos += (event->y - dw->y_start)/5; } else { /* Click rotates */ trackball(d_quat, (2.0*dw->x_start - w)/w, (h-2.0*dw->y_start)/h, (2.0*x-w)/w, (h-2.0*y)/h); add_quats(d_quat, dw->view_quat, dw->view_quat); } dw->x_start = x; dw->y_start = y; gdk_window_invalidate_rect(widget->window, &widget->allocation, FALSE); return TRUE; } #define BLOB_BITS 5 #define VERTICES_IN_A_BLOB 4*BLOB_BITS*BLOB_BITS*2 #define ADD_VERTEX \ vertices[3*i + 0] = reflection->x/1e9 + size*xv; \ vertices[3*i + 1] = reflection->y/1e9 + size*yv; \ vertices[3*i + 2] = reflection->z/1e9 + size*zv; \ normals[3*i + 0] = xv; \ normals[3*i + 1] = yv; \ normals[3*i + 2] = zv; \ i++; #define DRAW_BLOB \ double step = M_PI/(double)BLOB_BITS; \ double size = 0.15; \ int is, js; \ for ( is=0; isctx; /* "Measured" reflections */ if ( dw->gl_use_buffers ) { glGenBuffersARB(1, &dw->gl_ref_vertex_buffer); glGenBuffersARB(1, &dw->gl_ref_normal_buffer); } reflection = ctx->reflectionlist->reflections; i = 0; while ( reflection != NULL ) { if ( reflection->type == REFLECTION_NORMAL ) i++; reflection = reflection->next; }; dw->gl_ref_num_vertices = i; if ( dw->gl_ref_num_vertices ) { i = 0; reflection = ctx->reflectionlist->reflections; vertices = malloc(3*dw->gl_ref_num_vertices*sizeof(GLfloat)); normals = malloc(3*dw->gl_ref_num_vertices*sizeof(GLfloat)); while ( reflection != NULL ) { if ( reflection->type == REFLECTION_NORMAL ) { vertices[3*i + 0] = reflection->x/1e9; vertices[3*i + 1] = reflection->y/1e9; vertices[3*i + 2] = reflection->z/1e9; normals[3*i + 0] = reflection->x/1e9; normals[3*i + 1] = reflection->y/1e9; normals[3*i + 2] = reflection->z/1e9; i++; } reflection = reflection->next; }; if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_ref_vertex_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_ref_num_vertices*sizeof(GLfloat), vertices, GL_STATIC_DRAW); free(vertices); glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_ref_normal_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_ref_num_vertices*sizeof(GLfloat), normals, GL_STATIC_DRAW); free(normals); } else { dw->gl_ref_vertex_array = vertices; dw->gl_ref_normal_array = normals; } } /* Marker "reflections" */ if ( dw->gl_use_buffers ) { glGenBuffersARB(1, &dw->gl_marker_vertex_buffer); glGenBuffersARB(1, &dw->gl_marker_normal_buffer); } reflection = ctx->reflectionlist->reflections; i = 0; while ( reflection != NULL ) { if ( reflection->type == REFLECTION_MARKER ) i++; reflection = reflection->next; }; dw->gl_marker_num_vertices = i*VERTICES_IN_A_BLOB; if ( dw->gl_marker_num_vertices ) { i = 0; reflection = ctx->reflectionlist->reflections; vertices = malloc(3*dw->gl_marker_num_vertices*sizeof(GLfloat)); normals = malloc(3*dw->gl_marker_num_vertices*sizeof(GLfloat)); while ( reflection != NULL ) { if ( reflection->type == REFLECTION_MARKER ) { DRAW_BLOB } reflection = reflection->next; }; if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_marker_vertex_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_marker_num_vertices*sizeof(GLfloat), vertices, GL_STATIC_DRAW); free(vertices); glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_marker_normal_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_marker_num_vertices*sizeof(GLfloat), normals, GL_STATIC_DRAW); free(normals); } else { dw->gl_marker_vertex_array = vertices; dw->gl_marker_normal_array = normals; } } /* Generated reflections */ if ( dw->gl_use_buffers ) { glGenBuffersARB(1, &dw->gl_gen_vertex_buffer); glGenBuffersARB(1, &dw->gl_gen_normal_buffer); } reflection = ctx->reflectionlist->reflections; i = 0; while ( reflection != NULL ) { if ( reflection->type == REFLECTION_GENERATED ) i++; reflection = reflection->next; }; dw->gl_gen_num_vertices = i*VERTICES_IN_A_BLOB; if ( dw->gl_gen_num_vertices ) { i = 0; reflection = ctx->reflectionlist->reflections; vertices = malloc(3*dw->gl_gen_num_vertices*sizeof(GLfloat)); normals = malloc(3*dw->gl_gen_num_vertices*sizeof(GLfloat)); while ( reflection != NULL ) { if ( reflection->type == REFLECTION_GENERATED ) { DRAW_BLOB } reflection = reflection->next; }; if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_gen_vertex_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_gen_num_vertices*sizeof(GLfloat), vertices, GL_STATIC_DRAW); free(vertices); glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_gen_normal_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_gen_num_vertices*sizeof(GLfloat), normals, GL_STATIC_DRAW); free(normals); glBindBufferARB(GL_ARRAY_BUFFER, 0); /* ************* */ } else { dw->gl_gen_vertex_array = vertices; dw->gl_gen_normal_array = normals; } } /* Indexing lines */ if ( ctx->cell && dw->lines ) { int max_ind; signed int h, k, l; max_ind = 10; dw->gl_line_num_vertices = 3*2*((2*1+1)*(2*1+1)); if ( dw->gl_use_buffers ) { glGenBuffersARB(1, &dw->gl_line_vertex_buffer); } reflection = ctx->reflectionlist->reflections; vertices = malloc(3*dw->gl_line_num_vertices*sizeof(GLfloat)); i=0; /* Lines parallel to a */ for ( k=-1; k<=1; k++ ) { for ( l=-1; l<=1; l++ ) { vertices[3*i + 0] = (ctx->cell->a.x*(-max_ind) + ctx->cell->b.x*k + ctx->cell->c.x*l)/1e9; vertices[3*i + 1] = (ctx->cell->a.y*(-max_ind) + ctx->cell->b.y*k + ctx->cell->c.y*l)/1e9; vertices[3*i + 2] = (ctx->cell->a.z*(-max_ind) + ctx->cell->b.z*k + ctx->cell->c.z*l)/1e9; i++; vertices[3*i + 0] = (ctx->cell->a.x*(max_ind) + ctx->cell->b.x*k + ctx->cell->c.x*l)/1e9; vertices[3*i + 1] = (ctx->cell->a.y*(max_ind) + ctx->cell->b.y*k + ctx->cell->c.y*l)/1e9; vertices[3*i + 2] = (ctx->cell->a.z*(max_ind) + ctx->cell->b.z*k + ctx->cell->c.z*l)/1e9; i++; } } /* Lines parallel to b */ for ( h=-1; h<=1; h++ ) { for ( l=-1; l<=1; l++ ) { vertices[3*i + 0] = (ctx->cell->a.x*h + ctx->cell->b.x*(-max_ind) + ctx->cell->c.x*l)/1e9; vertices[3*i + 1] = (ctx->cell->a.y*h + ctx->cell->b.y*(-max_ind) + ctx->cell->c.y*l)/1e9; vertices[3*i + 2] = (ctx->cell->a.z*h + ctx->cell->b.z*(-max_ind) + ctx->cell->c.z*l)/1e9; i++; vertices[3*i + 0] = (ctx->cell->a.x*h + ctx->cell->b.x*(max_ind) + ctx->cell->c.x*l)/1e9; vertices[3*i + 1] = (ctx->cell->a.y*h + ctx->cell->b.y*(max_ind) + ctx->cell->c.y*l)/1e9; vertices[3*i + 2] = (ctx->cell->a.z*h + ctx->cell->b.z*(max_ind) + ctx->cell->c.z*l)/1e9; i++; } } /* Lines parallel to c */ for ( h=-1; h<=1; h++ ) { for ( k=-1; k<=1; k++ ) { vertices[3*i + 0] = (ctx->cell->a.x*h + ctx->cell->b.x*k + ctx->cell->c.x*(-max_ind))/1e9; vertices[3*i + 1] = (ctx->cell->a.y*h + ctx->cell->b.y*k + ctx->cell->c.y*(-max_ind))/1e9; vertices[3*i + 2] = (ctx->cell->a.z*h + ctx->cell->b.z*k + ctx->cell->c.z*(-max_ind))/1e9; i++; vertices[3*i + 0] = (ctx->cell->a.x*h + ctx->cell->b.x*k + ctx->cell->c.x*(max_ind))/1e9; vertices[3*i + 1] = (ctx->cell->a.y*h + ctx->cell->b.y*k + ctx->cell->c.y*(max_ind))/1e9; vertices[3*i + 2] = (ctx->cell->a.z*h + ctx->cell->b.z*k + ctx->cell->c.z*(max_ind))/1e9; i++; } } if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_line_vertex_buffer); glBufferDataARB(GL_ARRAY_BUFFER, 3*dw->gl_line_num_vertices*sizeof(GLfloat), vertices, GL_STATIC_DRAW); free(vertices); } else { dw->gl_line_vertex_array = vertices; } } dw->gl_list_id = glGenLists(1); glNewList(dw->gl_list_id, GL_COMPILE); #if 0 GLUquadric *quad; quad = gluNewQuadric(); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, yellow); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 10.0); gluSphere(quad, 10, 32, 32); #endif /* Bounding cube: 100 nm^-1 side length */ if ( dw->cube ) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, blue); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glBegin(GL_LINE_LOOP); glNormal3f(50.0, 50.0, 50.0); glVertex3f(50.0, 50.0, 50.0); glNormal3f(-50.0, 50.0, 50.0); glVertex3f(-50.0, 50.0, 50.0); glNormal3f(-50.0, -50.0, 50.0); glVertex3f(-50.0, -50.0, 50.0); glNormal3f(50.0, -50.0, 50.0); glVertex3f(50.0, -50.0, 50.0); glEnd(); glBegin(GL_LINE_LOOP); glNormal3f(50.0, 50.0, -50.0); glVertex3f(50.0, 50.0, -50.0); glNormal3f(-50.0, 50.0, -50.0); glVertex3f(-50.0, 50.0, -50.0); glNormal3f(-50.0, -50.0, -50.0); glVertex3f(-50.0, -50.0, -50.0); glNormal3f(50.0, -50.0, -50.0); glVertex3f(50.0, -50.0, -50.0); glEnd(); glBegin(GL_LINES); glNormal3f(50.0, 50.0, 50.0); glVertex3f(50.0, 50.0, 50.0); glNormal3f(50.0, 50.0, -50.0); glVertex3f(50.0, 50.0, -50.0); glNormal3f(-50.0, 50.0, 50.0); glVertex3f(-50.0, 50.0, 50.0); glNormal3f(-50.0, 50.0, -50.0); glVertex3f(-50.0, 50.0, -50.0); glNormal3f(-50.0, -50.0, 50.0); glVertex3f(-50.0, -50.0, 50.0); glNormal3f(-50.0, -50.0, -50.0); glVertex3f(-50.0, -50.0, -50.0); glNormal3f(50.0, -50.0, 50.0); glVertex3f(50.0, -50.0, 50.0); glNormal3f(50.0, -50.0, -50.0); glVertex3f(50.0, -50.0, -50.0); glEnd(); } /* x, y, z pointers */ int pointer_head_face; glPushMatrix(); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, red); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); glScalef(10.0, 1.0, 1.0); DRAW_POINTER_LINE glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); DRAW_POINTER_HEAD glPopMatrix(); glPushMatrix(); glRotatef(90.0, 0.0, 0.0, 1.0); glScalef(10.0, 1.0, 1.0); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, green); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); DRAW_POINTER_LINE glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green); DRAW_POINTER_HEAD glPopMatrix(); glPushMatrix(); glRotatef(-90.0, 0.0, 1.0, 0.0); glScalef(10.0, 1.0, 1.0); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, bblue); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); DRAW_POINTER_LINE glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, bblue); DRAW_POINTER_HEAD glPopMatrix(); /* Plot the other reflections */ reflection = ctx->reflectionlist->reflections; while ( reflection != NULL ) { if ( reflection->type == REFLECTION_VECTOR_MARKER_1 ) { glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glBegin(GL_LINES); glNormal3f(0.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glNormal3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); glVertex3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); glEnd(); } if ( reflection->type == REFLECTION_VECTOR_MARKER_2 ) { glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glBegin(GL_LINES); glNormal3f(0.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glNormal3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); glVertex3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); glEnd(); } if ( reflection->type == REFLECTION_VECTOR_MARKER_3 ) { glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glBegin(GL_LINES); glNormal3f(0.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glNormal3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); glVertex3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); glEnd(); } reflection = reflection->next; }; /* Draw the reciprocal unit cell if one is available */ if ( ctx->cell && !dw->lines ) { glBegin(GL_LINE_STRIP); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, red); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glNormal3f(1.0, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(ctx->cell->a.x/1e9, ctx->cell->a.y/1e9, ctx->cell->a.z/1e9); glVertex3f(ctx->cell->a.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->a.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->a.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->b.x/1e9, ctx->cell->b.y/1e9, ctx->cell->b.z/1e9); glVertex3f(0.0, 0.0, 0.0); glVertex3f(ctx->cell->c.x/1e9, ctx->cell->c.y/1e9, ctx->cell->c.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->a.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->a.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->a.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->a.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->a.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->a.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->c.x/1e9, ctx->cell->c.y/1e9, ctx->cell->c.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->b.x/1e9, ctx->cell->b.y/1e9, ctx->cell->b.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->a.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->a.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->a.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->a.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->a.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->a.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->a.x/1e9 + ctx->cell->b.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->a.y/1e9 + ctx->cell->b.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->a.z/1e9 + ctx->cell->b.z/1e9); glVertex3f(ctx->cell->c.x/1e9 + ctx->cell->a.x/1e9, ctx->cell->c.y/1e9 + ctx->cell->a.y/1e9, ctx->cell->c.z/1e9 + ctx->cell->a.z/1e9); glVertex3f(ctx->cell->a.x/1e9, ctx->cell->a.y/1e9, ctx->cell->a.z/1e9); glEnd(); } /* Tilt axis */ if ( ctx->images ) { glPushMatrix(); /* Images rotate clockwise by omega to put tilt axis at +x, * so rotate tilt axis anticlockwise by omega. * Since the rotation is about +z, this is already anticlockwise * when looking down z. */ glRotatef(ctx->images->images[0].omega, 0.0, 0.0, 1.0); glScalef(50.0, 1.0, 1.0); glTranslatef(-0.5, 0.0, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, yellow); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); DRAW_POINTER_LINE glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); DRAW_POINTER_HEAD glPopMatrix(); } /* Zero plane (must be drawn last for transparency to work) */ glBegin(GL_QUADS); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glNormal3f(0.0, 0.0, 1.0); glVertex3f(50.0, 50.0, 0.0); glVertex3f(50.0, -50.0, 0.0); glVertex3f(-50.0, -50.0, 0.0); glVertex3f(-50.0, 50.0, 0.0); glEnd(); glEndList(); //printf("DW: Vertex counts: meas:%i, mark:%i, gen:%i\n", dw->gl_ref_num_vertices, dw->gl_marker_num_vertices, dw->gl_gen_num_vertices); } static gint displaywindow_gl_expose(GtkWidget *widget, GdkEventExpose *event, DisplayWindow *dw) { GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); float m[4][4]; GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat green[] = { 0.0, 1.0, 0.0, 1.0 }; GLfloat blue[] = { 0.0, 0.0, 0.5, 1.0 }; GLfloat blue_spec[] = { 0.0, 0.0, 1.0, 1.0 }; GLfloat gold[] = { 0.5, 0.5, 0.0, 1.0 }; GLfloat gold_spec[] = { 0.9, 0.9, 0.0, 1.0 }; GLfloat light0_position[] = { 100.0, 100.0, 100.0, 0.0 }; GLfloat light0_diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat light0_specular[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat bg_top[] = { 0.0, 0.2, 0.0, 1.0 }; GLfloat bg_bot[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat grey[] = { 0.6, 0.6, 0.6, 1.0 }; if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) { return 0; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if ( dw->background ) { GLfloat w = dw->drawing_area->allocation.width; GLfloat h = dw->drawing_area->allocation.height; GLfloat aspect = w/h; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -20.0); /* Draw the background (this is done before setting up rotations) */ /* Set up "private" projection matrix */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-aspect*3.0, aspect*3.0, -3.0, 3.0, 0.001, 21.0); /* Draw background plane */ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, black); glMaterialfv(GL_FRONT, GL_SPECULAR, black); glMaterialf(GL_FRONT, GL_SHININESS, 0.0); glBegin(GL_QUADS); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, bg_bot); glVertex3f(-3.0*aspect, -3.0, 0.0); glVertex3f(+3.0*aspect, -3.0, 0.0); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, bg_top); glVertex3f(+3.0*aspect, +3.0, 0.0); glVertex3f(-3.0*aspect, +3.0, 0.0); glEnd(); /* Restore the old projection matrix */ glPopMatrix(); glClear(GL_DEPTH_BUFFER_BIT); /* Background does not count for depth test purposes */ } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Set up 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); /* The z component of this makes no difference if the projection is orthographic, * but controls zoom when perspective is used */ glTranslatef(0.0, 0.0, -400.0); glTranslatef(dw->x_pos, -dw->y_pos, 400.0-dw->distance); build_rotmatrix(m, dw->view_quat); glMultMatrixf(&m[0][0]); /* Draw the "measured" reflections */ if ( dw->gl_ref_num_vertices ) { glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, green); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_ref_vertex_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_ref_normal_buffer); glNormalPointer(GL_FLOAT, 0, NULL); glDrawArrays(GL_POINTS, 0, dw->gl_ref_num_vertices); glBindBufferARB(GL_ARRAY_BUFFER, 0); } else { glVertexPointer(3, GL_FLOAT, 0, dw->gl_ref_vertex_array); glNormalPointer(GL_FLOAT, 0, dw->gl_ref_normal_array); glDrawArrays(GL_POINTS, 0, dw->gl_ref_num_vertices); } glDisableClientState(GL_NORMAL_ARRAY); glPopClientAttrib(); } /* Draw marker points */ if ( dw->gl_marker_num_vertices ) { glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, blue_spec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0); if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_marker_vertex_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_marker_normal_buffer); glNormalPointer(GL_FLOAT, 0, NULL); glDrawArrays(GL_QUADS, 0, dw->gl_marker_num_vertices); glBindBufferARB(GL_ARRAY_BUFFER, 0); } else { glVertexPointer(3, GL_FLOAT, 0, dw->gl_marker_vertex_array); glNormalPointer(GL_FLOAT, 0, dw->gl_marker_normal_array); glDrawArrays(GL_QUADS, 0, dw->gl_marker_num_vertices); } glDisableClientState(GL_NORMAL_ARRAY); glPopClientAttrib(); } /* Draw generated reflections */ if ( dw->gl_gen_num_vertices ) { glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gold); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gold_spec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.0); if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_gen_vertex_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_gen_normal_buffer); glNormalPointer(GL_FLOAT, 0, NULL); glDrawArrays(GL_QUADS, 0, dw->gl_gen_num_vertices); glBindBufferARB(GL_ARRAY_BUFFER, 0); } else { glVertexPointer(3, GL_FLOAT, 0, dw->gl_gen_vertex_array); glNormalPointer(GL_FLOAT, 0, dw->gl_gen_normal_array); glDrawArrays(GL_QUADS, 0, dw->gl_gen_num_vertices); } glDisableClientState(GL_NORMAL_ARRAY); glPopClientAttrib(); } /* Draw indexing lines */ if ( dw->lines && dw->gl_line_num_vertices ) { glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, grey); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_line_vertex_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glDrawArrays(GL_LINES, 0, dw->gl_line_num_vertices); glBindBufferARB(GL_ARRAY_BUFFER, 0); } else { glVertexPointer(3, GL_FLOAT, 0, dw->gl_line_vertex_array); glDrawArrays(GL_LINES, 0, dw->gl_line_num_vertices); } glPopClientAttrib(); } /* Draw everything else */ glCallList(dw->gl_list_id); if ( gdk_gl_drawable_is_double_buffered(gldrawable) ) { gdk_gl_drawable_swap_buffers(gldrawable); } else { glFlush(); } gdk_gl_drawable_gl_end(gldrawable); return TRUE; } static gint displaywindow_gl_realise(GtkWidget *widget, DisplayWindow *dw) { 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; } displaywindow_gl_set_ortho(dw, w, h); displaywindow_gl_prepare(dw); gdk_gl_drawable_gl_end(gldrawable); return 0; } static gboolean displaywindow_gl_configure(GtkWidget *widget, GdkEventConfigure *event, DisplayWindow *dw) { 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); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glShadeModel(GL_SMOOTH); glEnable(GL_LINE_SMOOTH); /* Nudge the projection matrix routines to preserve the aspect ratio */ if ( dw->view == DW_ORTHO ) { displaywindow_gl_set_ortho(dw, w, h); } else { displaywindow_gl_set_perspective(dw, w, h); } gdk_gl_drawable_gl_end(gldrawable); return FALSE; } static void displaywindow_gl_free_resources(DisplayWindow *dw) { if ( dw->gl_use_buffers ) { glDeleteBuffersARB(1, &dw->gl_ref_vertex_buffer); glDeleteBuffersARB(1, &dw->gl_ref_normal_buffer); glDeleteBuffersARB(1, &dw->gl_marker_vertex_buffer); glDeleteBuffersARB(1, &dw->gl_marker_normal_buffer); glDeleteBuffersARB(1, &dw->gl_gen_vertex_buffer); glDeleteBuffersARB(1, &dw->gl_gen_normal_buffer); glDeleteBuffersARB(1, &dw->gl_line_vertex_buffer); } else { free(dw->gl_ref_vertex_array); free(dw->gl_ref_normal_array); free(dw->gl_marker_vertex_array); free(dw->gl_marker_normal_array); free(dw->gl_gen_vertex_array); free(dw->gl_gen_normal_array); free(dw->gl_line_vertex_array); } glDeleteLists(dw->gl_list_id, 1); } static gint displaywindow_closedown(GtkWidget *widget, DisplayWindow *dw) { displaywindow_gl_free_resources(dw); gtk_exit(0); return 0; } static void displaywindow_about(GtkWidget *widget, DisplayWindow *dw) { GtkWidget *window; const gchar *authors[] = { "Thomas White ", "Gordon Ball ", "Paul Midgley ", 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 and contributors"); 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 \n" "Virtual trackball (c) Copyright 1993, 1994, Silicon Graphics, Inc.\n" "See Credits for a full list of contributors\n" "\n" "Research funded by:\n" "FEI Electron Optics B.V.\n" "The Engineering and Physical Sciences Research Council"); 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(GtkWidget *widget, DisplayWindow *dw) { gtk_exit(0); } static void displaywindow_dirax(GtkWidget *widget, DisplayWindow *dw) { dirax_invoke(dw->ctx); } static void displaywindow_reproject(GtkWidget *widget, DisplayWindow *dw) { reproject_open(dw->ctx); } static void displaywindow_dirax_stop(GtkWidget *widget, DisplayWindow *dw) { dirax_stop(dw->ctx); } static void displaywindow_dirax_rerun(GtkWidget *widget, DisplayWindow *dw) { dirax_rerun(dw->ctx); } 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 gint displaywindow_changecube(GtkWidget *widget, DisplayWindow *dw) { dw->cube = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget)); displaywindow_update(dw); return 0; } static gint displaywindow_changelines(GtkWidget *widget, DisplayWindow *dw) { dw->lines = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget)); displaywindow_update(dw); return 0; } static gint displaywindow_changebackground(GtkWidget *widget, DisplayWindow *dw) { dw->background = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget)); displaywindow_update(dw); return 0; } static gint displaywindow_savecache_response(GtkWidget *widget, gint response, ControlContext *ctx) { if ( response == GTK_RESPONSE_ACCEPT ) { char *cache_filename; cache_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); if ( cache_save(ctx->images, cache_filename) ) { displaywindow_error("Failed to save cache file.", ctx->dw); } g_free(cache_filename); } gtk_widget_destroy(widget); return 0; } static gint displaywindow_savecache(GtkWidget *widget, DisplayWindow *dw) { dw->savecache_window = gtk_file_chooser_dialog_new("Save Reflections to Cache", GTK_WINDOW(dw->window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); g_signal_connect(G_OBJECT(dw->savecache_window), "response", G_CALLBACK(displaywindow_savecache_response), dw->ctx); gtk_widget_show_all(dw->savecache_window); return 0; } static gint displaywindow_setaxis_response(GtkWidget *widget, gint response, DisplayWindow *dw) { if ( response == GTK_RESPONSE_OK ) { const char *offset; float off; offset = gtk_entry_get_text(GTK_ENTRY(dw->tiltaxis_entry)); sscanf(offset, "%f", &off); mapping_adjust_axis(dw->ctx, off); } gtk_widget_destroy(widget); return 0; } static gint displaywindow_setaxis_activate(GtkWidget *widget, DisplayWindow *dw) { return displaywindow_setaxis_response(dw->tiltaxis_window, GTK_RESPONSE_OK, dw); } static gint displaywindow_incraxis(GtkWidget *widget, DisplayWindow *dw) { mapping_adjust_axis(dw->ctx, 0.2); return 0; } static gint displaywindow_decraxis(GtkWidget *widget, DisplayWindow *dw) { mapping_adjust_axis(dw->ctx, -0.2); return 0; } static gint displaywindow_setaxis(GtkWidget *widget, DisplayWindow *dw) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *table; GtkWidget *label; dw->tiltaxis_window = gtk_dialog_new_with_buttons("Set Tilt Axis Position", GTK_WINDOW(dw->window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); vbox = gtk_vbox_new(FALSE, 0); hbox = gtk_hbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dw->tiltaxis_window)->vbox), GTK_WIDGET(hbox), FALSE, FALSE, 7); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 5); table = gtk_table_new(1, 3, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 5); gtk_table_set_col_spacings(GTK_TABLE(table), 5); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0); label = gtk_label_new("Tilt Axis Offset:"); gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label), 1, 2, 1, 2); label = gtk_label_new("degrees"); gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label), 3, 4, 1, 2); dw->tiltaxis_entry = gtk_entry_new(); gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(dw->tiltaxis_entry), 2, 3, 1, 2); gtk_entry_set_alignment(GTK_ENTRY(dw->tiltaxis_entry), 1); g_signal_connect(G_OBJECT(dw->tiltaxis_window), "response", G_CALLBACK(displaywindow_setaxis_response), dw); g_signal_connect(G_OBJECT(dw->tiltaxis_entry), "activate", G_CALLBACK(displaywindow_setaxis_activate), dw); gtk_widget_show_all(dw->tiltaxis_window); gtk_widget_grab_focus(GTK_WIDGET(dw->tiltaxis_entry)); return 0; } static gint displaywindow_refine(GtkWidget *widget, DisplayWindow *dw) { refine_open(dw->ctx); return 0; } static void displaywindow_addmenubar(DisplayWindow *dw) { GtkActionEntry entries[] = { { "FileAction", NULL, "_File", NULL, NULL, NULL }, { "SaveCacheAction", GTK_STOCK_SAVE, "Save Image Analysis to _Cache", NULL, NULL, G_CALLBACK(displaywindow_savecache) }, { "CloseAction", GTK_STOCK_QUIT, "_Quit", NULL, NULL, G_CALLBACK(displaywindow_close) }, { "ViewAction", NULL, "_View", NULL, NULL, NULL }, { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL }, { "DirAxAction", GTK_STOCK_EXECUTE, "Start _DirAx", "D", NULL, G_CALLBACK(displaywindow_dirax) }, { "DirAxReRunAction", NULL, "Run another DirAx cycle", NULL, NULL, G_CALLBACK(displaywindow_dirax_rerun) }, { "StopDirAxAction", NULL, "Stop DirAx", NULL, NULL, G_CALLBACK(displaywindow_dirax_stop) }, { "ReprojectAction", NULL, "_Reproject Diffraction Patterns", NULL, NULL, G_CALLBACK(displaywindow_reproject) }, { "RefineAction", GTK_STOCK_EXECUTE, "Refine Reconstruction", NULL, NULL, G_CALLBACK(displaywindow_refine) }, { "SetAxisAction", NULL, "Set Tilt Axis Position", NULL, NULL, G_CALLBACK(displaywindow_setaxis) }, { "IncrAxisAction", NULL, "Increase Tilt Axis Position", "Up", NULL, G_CALLBACK(displaywindow_incraxis) }, { "DecrAxisAction", NULL, "Decrease Tilt Axis Position", "Down", NULL, G_CALLBACK(displaywindow_decraxis) }, { "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 radios[] = { { "OrthoAction", NULL, "_Orthographic", NULL, NULL, DW_ORTHO }, { "PerspectiveAction", NULL, "_Perspective", NULL, NULL, DW_PERSPECTIVE }, }; guint n_radios = G_N_ELEMENTS(radios); GtkToggleActionEntry toggles[] = { { "CubeAction", NULL, "Show 100 nm^-1 _Cube", NULL, NULL, G_CALLBACK(displaywindow_changecube), dw->cube }, { "LinesAction", NULL, "Show Indexing Lines", NULL, NULL, G_CALLBACK(displaywindow_changelines), dw->lines }, { "BackgroundAction", NULL, "Show Coloured Background", NULL, NULL, G_CALLBACK(displaywindow_changebackground), dw->background }, }; guint n_toggles = G_N_ELEMENTS(toggles); GError *error = NULL; dw->action_group = gtk_action_group_new("dtrdisplaywindow"); gtk_action_group_add_actions(dw->action_group, entries, n_entries, dw); gtk_action_group_add_radio_actions(dw->action_group, radios, n_radios, -1, G_CALLBACK(displaywindow_changeview), dw); gtk_action_group_add_toggle_actions(dw->action_group, toggles, n_toggles, dw); dw->ui = gtk_ui_manager_new(); gtk_ui_manager_insert_action_group(dw->ui, dw->action_group, 0); g_signal_connect(dw->ui, "add_widget", G_CALLBACK(displaywindow_addui_callback), dw->bigvbox); if ( gtk_ui_manager_add_ui_from_file(dw->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(dw->window), gtk_ui_manager_get_accel_group(dw->ui)); gtk_ui_manager_ensure_update(dw->ui); } DisplayWindow *displaywindow_open(ControlContext *ctx) { const char *filename; char *title; GdkGLConfig *glconfig; DisplayWindow *dw; dw = malloc(sizeof(DisplayWindow)); filename = basename(ctx->filename); title = malloc(10+strlen(filename)); strcpy(title, filename); strcat(title, " - dtr"); dw->gl_use_buffers = 1; dw->view = DW_ORTHO; dw->distance = 150; dw->x_pos = 0; dw->y_pos = 0; dw->view_quat[0] = 0.0; dw->view_quat[1] = 0.0; dw->view_quat[2] = 0.0; dw->view_quat[3] = 1.0; dw->ctx = ctx; dw->cube = TRUE; dw->lines = FALSE; dw->background = TRUE; dw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(dw->window), title); free(title); dw->bigvbox = gtk_vbox_new(FALSE, FALSE); gtk_container_add(GTK_CONTAINER(dw->window), dw->bigvbox); displaywindow_addmenubar(dw); dw->status_bar = gtk_statusbar_new(); gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(dw->status_bar), FALSE); gtk_box_pack_end(GTK_BOX(dw->bigvbox), dw->status_bar, FALSE, FALSE, 0); g_signal_connect(GTK_OBJECT(dw->window), "destroy", G_CALLBACK(displaywindow_closedown), dw); /* 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(dw->window), TRUE); dw->drawing_area = gtk_drawing_area_new(); gtk_widget_set_size_request(dw->drawing_area, 640, 640); gtk_widget_set_gl_capability(dw->drawing_area, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_box_pack_start(GTK_BOX(dw->bigvbox), dw->drawing_area, TRUE, TRUE, 0); gtk_widget_add_events(dw->drawing_area, GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_VISIBILITY_NOTIFY_MASK); g_signal_connect(GTK_OBJECT(dw->drawing_area), "configure_event", G_CALLBACK(displaywindow_gl_configure), dw); g_signal_connect(GTK_OBJECT(dw->drawing_area), "realize", G_CALLBACK(displaywindow_gl_realise), dw); g_signal_connect(GTK_OBJECT(dw->drawing_area), "expose_event", G_CALLBACK(displaywindow_gl_expose), dw); g_signal_connect(GTK_OBJECT(dw->drawing_area), "button_press_event", G_CALLBACK(displaywindow_gl_button_press), dw); g_signal_connect(GTK_OBJECT(dw->drawing_area), "motion_notify_event", G_CALLBACK(displaywindow_gl_motion_notify), dw); displaywindow_update_dirax(ctx, dw); gtk_widget_show_all(dw->window); return dw; } void displaywindow_update(DisplayWindow *dw) { displaywindow_gl_free_resources(dw); displaywindow_gl_prepare(dw); gdk_window_invalidate_rect(dw->drawing_area->window, &dw->drawing_area->allocation, FALSE); } /* Update the disabling of the menu for DirAx functions */ void displaywindow_update_dirax(ControlContext *ctx, DisplayWindow *dw) { GtkWidget *start; GtkWidget *stop; GtkWidget *rerun; start = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/tools/dirax"); stop = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/tools/diraxstop"); rerun = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/tools/diraxrerun"); if ( ctx->dirax ) { gtk_widget_set_sensitive(GTK_WIDGET(start), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(stop), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(rerun), TRUE); } else { gtk_widget_set_sensitive(GTK_WIDGET(start), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(stop), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(rerun), FALSE); } } void displaywindow_error(const char *msg, DisplayWindow *dw) { GtkWidget *window; window = gtk_message_dialog_new(GTK_WINDOW(dw->window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, msg); gtk_window_set_title(GTK_WINDOW(window), "Error"); g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window); gtk_widget_show(window); }