/* * 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 "ipr.h" #include "displaywindow.h" enum { DW_ORTHO, DW_PERSPECTIVE }; static void displaywindow_about() { 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() { gtk_exit(0); } static void displaywindow_gl_set_ortho(DisplayWindow *dw, GLfloat w, GLfloat h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( w > h ) { GLfloat aspect = w/h; glOrtho(-aspect*(dw->distance/2), aspect*(dw->distance/2), -(dw->distance/2), (dw->distance/2), 0.01, 1000.0); } else { GLfloat aspect = h/w; glOrtho(-(dw->distance/2), (dw->distance/2), -aspect*(dw->distance/2), aspect*(dw->distance/2), 0.01, 1000.0); } glMatrixMode(GL_MODELVIEW); } static void displaywindow_gl_set_perspective(DisplayWindow *dw, GLfloat w, GLfloat h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( w > h ) { GLfloat aspect = w/h; glFrustum(-aspect, aspect, -1.0, 1.0, 10.0, 1000.0); } else { GLfloat aspect = h/w; glFrustum(-1.0, 1.0, -aspect, aspect, 10.0, 1000.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 gint displaywindow_changefog(GtkWidget *widget, DisplayWindow *dw) { GdkGLContext *glcontext; GdkGLDrawable *gldrawable; glcontext = gtk_widget_get_gl_context(dw->drawing_area); gldrawable = gtk_widget_get_gl_drawable(dw->drawing_area); dw->fog = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget)); if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) { return 1; } if ( dw->fog ) { glEnable(GL_FOG); } else { glDisable(GL_FOG); } gdk_gl_drawable_gl_end(gldrawable); 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(DisplayWindow *dw) { 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 radios[] = { { "OrthoAction", NULL, "_Orthographic", NULL, NULL, DW_ORTHO }, { "PerspectiveAction", NULL, "_Perspective", NULL, NULL, DW_PERSPECTIVE }, }; guint n_radios = G_N_ELEMENTS(radios); GtkToggleActionEntry toggles[] = { { "FogAction", NULL, "_Fog", NULL, NULL, G_CALLBACK(displaywindow_changefog), FALSE }, }; 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); } 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->view == DW_ORTHO ) { displaywindow_gl_set_ortho(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.2; \ int is, js; \ for ( is=0; isctx; /* "Measured" reflections */ if ( dw->gl_use_buffers ) { glGenBuffersARB(1, &dw->gl_ref_vertex_buffer); } reflection = ctx->reflectionctx->reflections; i = 0; do { if ( reflection->type == REFLECTION_NORMAL ) i++; reflection = reflection->next; } while ( reflection != NULL ); dw->gl_ref_num_vertices = i; i = 0; reflection = ctx->reflectionctx->reflections; vertices = malloc(3*dw->gl_ref_num_vertices*sizeof(GLfloat)); do { 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; i++; } reflection = reflection->next; } while ( reflection != NULL ); 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); } else { dw->gl_ref_vertex_array = vertices; } /* Marker "reflections" */ if ( dw->gl_use_buffers ) { glGenBuffersARB(1, &dw->gl_marker_vertex_buffer); glGenBuffersARB(1, &dw->gl_marker_normal_buffer); } reflection = ctx->reflectionctx->reflections; i = 0; do { if ( reflection->type == REFLECTION_MARKER ) i++; reflection = reflection->next; } while ( reflection != NULL ); dw->gl_marker_num_vertices = i*VERTICES_IN_A_BLOB; i = 0; reflection = ctx->reflectionctx->reflections; vertices = malloc(3*dw->gl_marker_num_vertices*sizeof(GLfloat)); normals = malloc(3*dw->gl_marker_num_vertices*sizeof(GLfloat)); do { if ( reflection->type == REFLECTION_MARKER ) { DRAW_BLOB } reflection = reflection->next; } while ( reflection != NULL ); 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->reflectionctx->reflections; i = 0; do { if ( reflection->type == REFLECTION_GENERATED ) i++; reflection = reflection->next; } while ( reflection != NULL ); dw->gl_gen_num_vertices = i*VERTICES_IN_A_BLOB; i = 0; reflection = ctx->reflectionctx->reflections; vertices = malloc(3*dw->gl_gen_num_vertices*sizeof(GLfloat)); normals = malloc(3*dw->gl_gen_num_vertices*sizeof(GLfloat)); do { if ( reflection->type == REFLECTION_GENERATED ) { DRAW_BLOB } reflection = reflection->next; } while ( reflection != NULL ); 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_list_id = glGenLists(1); glNewList(dw->gl_list_id, GL_COMPILE); /* Bounding cube: 100 nm^-1 side length */ 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_LINE_LOOP); glVertex3f(50, 50, 50); glVertex3f(-50, 50, 50); glVertex3f(-50, -50, 50); glVertex3f(50, -50, 50); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(50, 50, -50); glVertex3f(-50, 50, -50); glVertex3f(-50, -50, -50); glVertex3f(50, -50, -50); glEnd(); glBegin(GL_LINES); 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 */ glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); glBegin(GL_LINES); 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); 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); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); 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(); glDisable(GL_POLYGON_OFFSET_LINE); /* Plot the other reflections */ reflection = ctx->reflectionctx->reflections; quadric = gluNewQuadric(); do { if ( reflection->type == REFLECTION_CENTRAL ) { glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); glMaterialfv(GL_FRONT, GL_SPECULAR, blue_spec); glMaterialf(GL_FRONT, GL_SHININESS, 50.0); glPushMatrix(); glTranslatef(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); gluSphere(quadric, 0.2, 32, 32); glPopMatrix(); } if ( reflection->type == REFLECTION_VECTOR_MARKER_1 ) { 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); glVertex3f(0.0, 0.0, 0.0); glVertex3f(reflection->x, reflection->y, reflection->z); glEnd(); } if ( reflection->type == REFLECTION_VECTOR_MARKER_2 ) { 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); glBegin(GL_LINES); glVertex3f(0.0, 0.0, 0.0); glVertex3f(reflection->x, reflection->y, reflection->z); glEnd(); } if ( reflection->type == REFLECTION_VECTOR_MARKER_3 ) { 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); glVertex3f(0.0, 0.0, 0.0); glVertex3f(reflection->x, reflection->y, reflection->z); glEnd(); } 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, red); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(ctx->ipr_basis->a.x/1e9, ctx->ipr_basis->a.y/1e9, ctx->ipr_basis->a.z/1e9); glVertex3f(ctx->ipr_basis->a.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->a.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->a.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->b.z/1e9); glVertex3f(0.0, 0.0, 0.0); glVertex3f(ctx->ipr_basis->c.x/1e9, ctx->ipr_basis->c.y/1e9, ctx->ipr_basis->c.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->a.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->a.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->a.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->a.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->a.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->a.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9, ctx->ipr_basis->c.y/1e9, ctx->ipr_basis->c.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->a.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->a.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->a.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->a.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->a.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->a.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->a.x/1e9 + ctx->ipr_basis->b.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->a.y/1e9 + ctx->ipr_basis->b.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->a.z/1e9 + ctx->ipr_basis->b.z/1e9); glVertex3f(ctx->ipr_basis->c.x/1e9 + ctx->ipr_basis->a.x/1e9, ctx->ipr_basis->c.y/1e9 + ctx->ipr_basis->a.y/1e9, ctx->ipr_basis->c.z/1e9 + ctx->ipr_basis->a.z/1e9); glVertex3f(ctx->ipr_basis->a.x/1e9, ctx->ipr_basis->a.y/1e9, ctx->ipr_basis->a.z/1e9); glEnd(); } /* Zero plane */ glBegin(GL_QUADS); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glass); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, glass_spec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0); glVertex3f(50, 50, 0.0); glVertex3f(50, -50, 0.0); glVertex3f(-50, -50, 0.0); glVertex3f(-50, 50, 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[] = { 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 }; if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) { return 0; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glLoadIdentity(); glTranslatef(dw->x_pos, -dw->y_pos, -dw->distance); build_rotmatrix(m, dw->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); /* Draw the "measured" reflections */ glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); 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); if ( dw->gl_use_buffers ) { glBindBufferARB(GL_ARRAY_BUFFER, dw->gl_ref_vertex_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glDrawArrays(GL_POINTS, 0, dw->gl_ref_num_vertices); } else { glVertexPointer(3, GL_FLOAT, 0, dw->gl_ref_vertex_array); glDrawArrays(GL_POINTS, 0, dw->gl_ref_num_vertices); } glPopClientAttrib(); /* Draw marker points */ glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); glMaterialfv(GL_FRONT, GL_SPECULAR, blue_spec); glMaterialf(GL_FRONT, GL_SHININESS, 50.0); glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_FILL); 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); } 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); } glDisable(GL_POLYGON_OFFSET_FILL); glPopClientAttrib(); /* Draw generated reflections */ glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gold); glMaterialfv(GL_FRONT, GL_SPECULAR, gold_spec); glMaterialf(GL_FRONT, 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); /* NOTE THIS PLZKTHX */ } 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); } 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 0; } 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_create_list(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_DEPTH_TEST); if ( dw->fog ) glEnable(GL_FOG); glFogf(GL_FOG_DENSITY, 0.005); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glShadeModel(GL_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 gint displaywindow_closedown(GtkWidget *widget, DisplayWindow *dw) { return 0; } 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->fog = 0; 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), NULL); g_signal_connect_after(GTK_OBJECT(dw->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(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); gtk_widget_show_all(dw->window); return dw; } void displaywindow_update(DisplayWindow *dw) { if ( dw->gl_use_buffers ) { glDeleteBuffersARB(1, &dw->gl_ref_vertex_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); } else { free(dw->gl_ref_vertex_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); } glDeleteLists(dw->gl_list_id, 1); displaywindow_gl_create_list(dw); gdk_window_invalidate_rect(dw->drawing_area->window, &dw->drawing_area->allocation, FALSE); }