eleni@0: #include eleni@0: #include elene@9: #include eleni@0: eleni@0: #include eleni@0: #include eleni@0: elene@9: #include elene@9: elene@9: #include "mesh.h" elene@6: #include "volume.h" eleni@1: elene@10: static bool init(void); elene@10: static GLUI *create_ui(void); elene@10: static void display(void); elene@10: static void reshape(int x, int y); elene@10: static void keyboard(unsigned char key, int x, int y); elene@10: static void keyboard_up(unsigned char key, int x, int y); elene@10: static void mouse(int button, int state, int x, int y); elene@10: static void motion(int x, int y); eleni@0: eleni@0: static int win_xsz, win_ysz; elene@9: static float cam_phi, cam_theta, cam_dist = 6; elene@9: static std::vector key_state(256); eleni@0: elene@11: static const char *vol_fname = "data/test1.vol"; elene@6: elene@6: static Volume *vol; elene@9: static Mesh *mesh; elene@9: static float cur_z, thres = 0.5; elene@9: elene@9: static int use_orig_vol_res = 1; elene@9: static int vol_res[3]; // volume sampling resolution x/y/z elene@9: elene@9: static GLUI *ui; eleni@1: eleni@0: int main(int argc, char **argv) eleni@0: { eleni@0: glutInit(&argc, argv); elene@7: glutInitWindowSize(512, 512); elene@11: glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); eleni@0: elene@11: if(argv[1]) elene@11: vol_fname = argv[1]; eleni@0: eleni@0: glutCreateWindow("My Colonoscopie OEO!"); eleni@0: eleni@0: glutDisplayFunc(display); eleni@0: glutReshapeFunc(reshape); eleni@0: glutKeyboardFunc(keyboard); elene@9: glutKeyboardUpFunc(keyboard_up); eleni@0: glutMouseFunc(mouse); eleni@0: glutMotionFunc(motion); eleni@0: eleni@0: glewInit(); eleni@1: if(!init()) { eleni@1: fprintf(stderr, "Failed to initialize La votre Colonoscopie\n"); eleni@1: return 1; eleni@1: } eleni@0: eleni@0: //call init eleni@0: eleni@0: glutMainLoop(); eleni@0: return 0; eleni@0: } eleni@0: elene@10: static bool init() elene@9: { elene@11: glEnable(GL_DEPTH_TEST); elene@11: glEnable(GL_NORMALIZE); elene@11: elene@11: glEnable(GL_LIGHTING); //TODO: shaders elene@11: glEnable(GL_LIGHT0); elene@11: glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); elene@11: elene@9: vol = new Volume; elene@11: if(!vol->load(vol_fname)) { elene@11: fprintf(stderr, "Failed to load %s", vol_fname); elene@9: return false; elene@9: } elene@9: mesh = new Mesh; elene@9: cur_z = 0.5; elene@9: elene@9: vol_res[0] = vol->get_slice(0)->get_width(); elene@9: vol_res[1] = vol->get_slice(0)->get_height(); elene@9: vol_res[2] = vol->get_slice_count(); elene@9: elene@9: if(!(ui = create_ui())) { elene@9: return false; elene@9: } elene@9: elene@9: return true; elene@9: } elene@9: elene@9: static GLUI_Spinner *res_spin[3]; elene@9: static void toggle_use_orig(int id) elene@9: { elene@9: for(int i=0; i<3; i++) { elene@9: if(use_orig_vol_res) { elene@9: res_spin[i]->disable(); elene@9: } else { elene@9: res_spin[i]->enable(); elene@9: } elene@9: } elene@9: } elene@9: static void thres_change(int id) elene@9: { elene@9: static float prev_thres = thres; elene@9: elene@9: if(prev_thres != thres) { elene@9: prev_thres = thres; elene@9: mesh->clear(); elene@9: } elene@9: } elene@10: static GLUI *create_ui() elene@9: { elene@9: GLUI *ui = GLUI_Master.create_glui("ui"); elene@9: assert(ui); elene@9: elene@9: ui->set_main_gfx_window(glutGetWindow()); elene@9: elene@9: GLUI_Spinner *thres_spin = ui->add_spinner("iso threshold", GLUI_SPINNER_FLOAT, &thres, 0, thres_change); elene@9: thres_spin->set_float_limits(0, 1); elene@9: elene@9: GLUI_Panel *res_panel = ui->add_panel("volume resolution"); elene@9: elene@9: ui->add_checkbox_to_panel(res_panel, "original resolution", &use_orig_vol_res, 0, toggle_use_orig); elene@9: elene@9: static const char *res_spin_name[] = {"x", "y", "z"}; elene@9: for(int i=0; i<3; i++) { elene@9: res_spin[i] = ui->add_spinner_to_panel(res_panel, res_spin_name[i], GLUI_SPINNER_INT, vol_res + i); elene@9: res_spin[i]->set_int_limits(8, 256); // TODO limits as arguments or config elene@9: res_spin[i]->disable(); elene@9: } elene@9: elene@9: return ui; elene@9: } elene@9: elene@10: static void display(void) eleni@0: { elene@9: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); elene@9: elene@9: glMatrixMode(GL_MODELVIEW); elene@9: glLoadIdentity(); elene@9: glTranslatef(0, 0, -cam_dist); elene@9: glRotatef(cam_phi, 1, 0, 0); elene@9: glRotatef(cam_theta, 0, 1, 0); elene@9: elene@9: /* elene@6: glBindTexture(GL_TEXTURE_3D, vol->get_texture()); elene@6: glEnable(GL_TEXTURE_3D); eleni@1: glBegin(GL_QUADS); elene@6: glTexCoord3f(0, 0, cur_z); glVertex3f(-1, -1, 0); elene@6: glTexCoord3f(0, 1, cur_z); glVertex3f(-1, 1, 0); elene@6: glTexCoord3f(1, 1, cur_z); glVertex3f(1, 1, 0); elene@6: glTexCoord3f(1, 0, cur_z); glVertex3f(1, -1, 0); eleni@1: glEnd(); elene@6: glDisable(GL_TEXTURE_3D); elene@9: */ eleni@0: elene@9: if(mesh->is_empty()) { elene@9: printf("recalculating isosurface ... "); elene@9: fflush(stdout); elene@9: vol->create_mesh(mesh, thres); elene@9: printf("done.\n"); elene@9: } elene@9: mesh->draw(); elene@9: elene@9: //TODO: draw threshold eleni@0: glutSwapBuffers(); eleni@0: assert(glGetError() == GL_NO_ERROR); eleni@0: } eleni@0: elene@10: static void reshape(int x, int y) eleni@0: { eleni@0: glViewport(0, 0, x, y); elene@9: glMatrixMode(GL_PROJECTION); elene@9: glLoadIdentity(); elene@9: gluPerspective(45, (float)x / (float)y, 0.5, 500); elene@9: eleni@0: if(x != win_xsz || y != win_ysz) { eleni@0: win_xsz = x; eleni@0: win_ysz = y; eleni@0: } eleni@0: } eleni@0: elene@10: static void keyboard(unsigned char key, int x, int y) eleni@0: { elene@9: key_state[(int)key] = true; elene@9: eleni@0: switch(key) { eleni@0: case 27: eleni@0: exit(0); elene@9: case 'w': elene@9: { elene@9: static bool wire; elene@9: wire = !wire; elene@9: glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL); elene@9: } elene@9: break; eleni@0: default: eleni@0: break; eleni@0: } eleni@0: } eleni@0: elene@10: static void keyboard_up(unsigned char key, int x, int y) elene@9: { elene@9: key_state[(int) key] = false; elene@9: } elene@9: eleni@0: static int prev_x, prev_y; elene@9: static bool bn_state[32]; elene@9: static float prev_thres; elene@9: elene@10: static void mouse(int bn, int state, int x, int y) eleni@0: { eleni@0: prev_x = x; eleni@0: prev_y = y; elene@9: elene@9: bn_state[bn - GLUT_LEFT_BUTTON] = (state == GLUT_DOWN); elene@9: elene@9: if(state == GLUT_DOWN) { elene@9: prev_thres = thres; elene@9: } elene@9: else { elene@9: if(thres != prev_thres) { elene@9: mesh->clear(); elene@9: } elene@9: } eleni@0: } eleni@0: elene@10: static void motion(int x, int y) eleni@0: { eleni@0: int dx = x - prev_x; eleni@0: int dy = y - prev_y; elene@9: elene@9: if(!dx && !dy) elene@9: return; elene@9: eleni@0: prev_x = x; eleni@0: prev_y = y; elene@6: elene@9: if(key_state[(int)'t']) { elene@9: thres = (float)x / (float)win_xsz; elene@9: printf("threshold: %f\n", thres); elene@9: elene@9: glutPostRedisplay(); elene@9: return; elene@9: } elene@9: elene@9: // camera elene@9: if(bn_state[0]) { elene@9: if(key_state[(int)'z']) { elene@9: //zoom the camera elene@9: elene@9: cam_dist += dy * 0.1; elene@9: elene@9: if(cam_dist < 0) elene@9: cam_dist = 0; elene@9: } elene@9: else { elene@9: //rotate the camera elene@9: elene@9: cam_phi += dy * 0.5; elene@9: cam_theta += dx * 0.5; elene@9: elene@9: if(cam_phi > 90) elene@9: cam_phi = 90; elene@9: if(cam_phi < -90) elene@9: cam_phi = -90; elene@9: } elene@9: elene@6: glutPostRedisplay(); elene@6: } eleni@0: }