volmetrics

annotate src/main.cc @ 18:4e02e18e70ef

quick backup - shaders 4 transfer function preview
author Eleni Maria Stea <elene.mst@gmail.com>
date Mon, 24 Mar 2014 23:28:08 +0200
parents 0f4fff558737
children 21bc62bb3e14
rev   line source
eleni@0 1 #include <GL/glew.h>
eleni@0 2 #include <GL/glut.h>
elene@9 3 #include <GL/glui.h>
eleni@0 4
elene@17 5 #include <math.h>
eleni@0 6 #include <stdio.h>
eleni@0 7 #include <assert.h>
eleni@0 8
elene@9 9 #include <vector>
elene@9 10
elene@9 11 #include "mesh.h"
elene@6 12 #include "volume.h"
eleni@1 13
elene@10 14 static bool init(void);
elene@10 15 static GLUI *create_ui(void);
elene@10 16 static void display(void);
elene@10 17 static void reshape(int x, int y);
elene@10 18 static void keyboard(unsigned char key, int x, int y);
elene@10 19 static void keyboard_up(unsigned char key, int x, int y);
elene@10 20 static void mouse(int button, int state, int x, int y);
elene@10 21 static void motion(int x, int y);
elene@16 22 static bool init_xfer(void);
elene@16 23 static void display_xfer(void);
elene@16 24 static void reshape_xfer(int x, int y);
elene@17 25 static void mouse_xfer(int button, int state, int x, int y);
elene@16 26 static void motion_xfer(int x, int y);
elene@18 27 static void volume_preview ();
elene@16 28
elene@16 29 static int mainwin_id, xferwin_id;
elene@18 30 //todo keyb esc
elene@16 31
eleni@0 32 static int win_xsz, win_ysz;
elene@9 33 static float cam_phi, cam_theta, cam_dist = 6;
elene@9 34 static std::vector<bool> key_state(256);
eleni@0 35
elene@11 36 static const char *vol_fname = "data/test1.vol";
elene@6 37
elene@6 38 static Volume *vol;
elene@9 39 static Mesh *mesh;
elene@12 40 static float cur_z, thres = 0.5, thres2 = 1.0;
elene@9 41
elene@9 42 static int use_orig_vol_res = 1;
elene@9 43 static int vol_res[3]; // volume sampling resolution x/y/z
elene@9 44
elene@9 45 static GLUI *ui;
eleni@1 46
eleni@0 47 int main(int argc, char **argv)
eleni@0 48 {
eleni@0 49 glutInit(&argc, argv);
elene@16 50 if(argv[1])
elene@16 51 vol_fname = argv[1];
elene@16 52
elene@16 53 if(!init()) {
elene@16 54 fprintf(stderr, "Failed to initialize program.\n");
elene@16 55 return 1;
elene@16 56 }
elene@16 57
elene@16 58 init_xfer();
elene@16 59
elene@16 60 glutMainLoop();
elene@16 61 return 0;
elene@16 62 }
elene@16 63
elene@16 64 static bool init()
elene@16 65 {
elene@7 66 glutInitWindowSize(512, 512);
elene@11 67 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
eleni@0 68
elene@16 69 mainwin_id = glutCreateWindow("CT scan");
eleni@0 70 glutDisplayFunc(display);
eleni@0 71 glutReshapeFunc(reshape);
eleni@0 72 glutKeyboardFunc(keyboard);
elene@9 73 glutKeyboardUpFunc(keyboard_up);
eleni@0 74 glutMouseFunc(mouse);
eleni@0 75 glutMotionFunc(motion);
eleni@0 76
eleni@0 77 glewInit();
eleni@0 78
elene@11 79 glEnable(GL_DEPTH_TEST);
elene@11 80 glEnable(GL_NORMALIZE);
elene@11 81
elene@11 82 glEnable(GL_LIGHTING); //TODO: shaders
elene@11 83 glEnable(GL_LIGHT0);
elene@11 84 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
elene@11 85
elene@9 86 vol = new Volume;
elene@11 87 if(!vol->load(vol_fname)) {
elene@11 88 fprintf(stderr, "Failed to load %s", vol_fname);
elene@9 89 return false;
elene@9 90 }
elene@9 91 mesh = new Mesh;
elene@9 92 cur_z = 0.5;
elene@9 93
elene@9 94 vol_res[0] = vol->get_slice(0)->get_width();
elene@9 95 vol_res[1] = vol->get_slice(0)->get_height();
elene@9 96 vol_res[2] = vol->get_slice_count();
elene@9 97
elene@9 98 if(!(ui = create_ui())) {
elene@9 99 return false;
elene@9 100 }
elene@9 101
elene@9 102 return true;
elene@9 103 }
elene@9 104
elene@9 105 static GLUI_Spinner *res_spin[3];
elene@9 106 static void toggle_use_orig(int id)
elene@9 107 {
elene@9 108 for(int i=0; i<3; i++) {
elene@9 109 if(use_orig_vol_res) {
elene@9 110 res_spin[i]->disable();
elene@9 111 } else {
elene@9 112 res_spin[i]->enable();
elene@9 113 }
elene@9 114 }
elene@9 115 }
elene@9 116 static void thres_change(int id)
elene@9 117 {
elene@9 118 static float prev_thres = thres;
elene@12 119 static float prev_thres2 = thres2;
elene@9 120
elene@12 121 if(prev_thres != thres || prev_thres2 != thres2) {
elene@9 122 prev_thres = thres;
elene@12 123 prev_thres2 = thres2;
elene@12 124 mesh->clear();
elene@12 125 }
elene@16 126
elene@16 127 glutSetWindow(xferwin_id);
elene@16 128 glutPostRedisplay();
elene@16 129 glutSetWindow(mainwin_id);
elene@16 130 glutPostRedisplay();
elene@12 131 }
elene@12 132 static void res_change(int id)
elene@12 133 {
elene@12 134 static float prev_resx = vol_res[0];
elene@12 135 static float prev_resy = vol_res[1];
elene@12 136 static float prev_resz = vol_res[2];
elene@12 137
elene@12 138 if(prev_resx != vol_res[0] || prev_resy != vol_res[1] || prev_resz != vol_res[2]) {
elene@12 139 prev_resx = vol_res[0];
elene@12 140 prev_resy = vol_res[1];
elene@12 141 prev_resz = vol_res[2];
elene@9 142 mesh->clear();
elene@9 143 }
elene@9 144 }
elene@10 145 static GLUI *create_ui()
elene@9 146 {
elene@9 147 GLUI *ui = GLUI_Master.create_glui("ui");
elene@9 148 assert(ui);
elene@9 149
elene@9 150 ui->set_main_gfx_window(glutGetWindow());
elene@9 151
elene@12 152 GLUI_Panel *thres_panel = ui->add_panel("iso thresholds");
elene@12 153
elene@12 154 GLUI_Spinner *thres_spin = ui->add_spinner_to_panel(thres_panel, "T1", GLUI_SPINNER_FLOAT, &thres, 0, thres_change);
elene@9 155 thres_spin->set_float_limits(0, 1);
elene@9 156
elene@12 157 GLUI_Spinner *thres2_spin = ui->add_spinner_to_panel(thres_panel, "T2", GLUI_SPINNER_FLOAT, &thres2, 0, thres_change);
elene@12 158 thres2_spin->set_float_limits(0, 1);
elene@12 159
elene@9 160 GLUI_Panel *res_panel = ui->add_panel("volume resolution");
elene@9 161
elene@9 162 ui->add_checkbox_to_panel(res_panel, "original resolution", &use_orig_vol_res, 0, toggle_use_orig);
elene@9 163
elene@9 164 static const char *res_spin_name[] = {"x", "y", "z"};
elene@9 165 for(int i=0; i<3; i++) {
elene@12 166 res_spin[i] = ui->add_spinner_to_panel(res_panel, res_spin_name[i], GLUI_SPINNER_INT, vol_res + i, 0, res_change);
elene@9 167 res_spin[i]->set_int_limits(8, 256); // TODO limits as arguments or config
elene@9 168 res_spin[i]->disable();
elene@9 169 }
elene@9 170
elene@9 171 return ui;
elene@9 172 }
elene@9 173
elene@18 174 static void volume_preview ()
elene@18 175 {
elene@18 176 float aspect = win_xsz / win_ysz;
elene@18 177 float z = 0.0;
elene@18 178
elene@18 179 glDisable(GL_LIGHTING);
elene@18 180
elene@18 181 glMatrixMode(GL_MODELVIEW);
elene@18 182 glPushMatrix();
elene@18 183 glLoadIdentity();
elene@18 184
elene@18 185 glMatrixMode(GL_PROJECTION);
elene@18 186 glPushMatrix();
elene@18 187 glLoadIdentity();
elene@18 188 glOrtho(-aspect, aspect, -1.0, 1.0, -1.0, 1.0);
elene@18 189
elene@18 190 glBindTexture(GL_TEXTURE_3D, vol->get_texture());
elene@18 191 glEnable(GL_TEXTURE_3D);
elene@18 192 glBegin(GL_QUADS);
elene@18 193 glColor3f(1.0, 0.0, 0.0);
elene@18 194 glTexCoord3f(0, 0, z); glVertex3f(-1.0, 1.0, 0.0);
elene@18 195 glTexCoord3f(0, 1, z); glVertex3f(-1.0, 0.5, 0.0);
elene@18 196 glTexCoord3f(1, 1, z); glVertex3f(-0.5, 0.5, 0.0);
elene@18 197 glTexCoord3f(1, 0, z); glVertex3f(-0.5, 1.0, 0.0);
elene@18 198 glEnd();
elene@18 199 glDisable(GL_TEXTURE_3D);
elene@18 200
elene@18 201 glMatrixMode(GL_PROJECTION);
elene@18 202 glPopMatrix();
elene@18 203
elene@18 204 glMatrixMode(GL_MODELVIEW);
elene@18 205 glPopMatrix();
elene@18 206
elene@18 207 glEnable(GL_LIGHTING);
elene@18 208 }
elene@18 209
elene@10 210 static void display(void)
eleni@0 211 {
elene@9 212 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
elene@9 213
elene@9 214 glMatrixMode(GL_MODELVIEW);
elene@9 215 glLoadIdentity();
elene@9 216 glTranslatef(0, 0, -cam_dist);
elene@9 217 glRotatef(cam_phi, 1, 0, 0);
elene@9 218 glRotatef(cam_theta, 0, 1, 0);
elene@9 219
elene@9 220 /*
elene@6 221 glBindTexture(GL_TEXTURE_3D, vol->get_texture());
elene@6 222 glEnable(GL_TEXTURE_3D);
eleni@1 223 glBegin(GL_QUADS);
elene@6 224 glTexCoord3f(0, 0, cur_z); glVertex3f(-1, -1, 0);
elene@6 225 glTexCoord3f(0, 1, cur_z); glVertex3f(-1, 1, 0);
elene@6 226 glTexCoord3f(1, 1, cur_z); glVertex3f(1, 1, 0);
elene@6 227 glTexCoord3f(1, 0, cur_z); glVertex3f(1, -1, 0);
eleni@1 228 glEnd();
elene@6 229 glDisable(GL_TEXTURE_3D);
elene@9 230 */
eleni@0 231
elene@9 232 if(mesh->is_empty()) {
elene@9 233 printf("recalculating isosurface ... ");
elene@9 234 fflush(stdout);
elene@12 235 vol->create_mesh(mesh, thres, thres2, vol_res[0], vol_res[1], vol_res[2]);
elene@9 236 printf("done.\n");
elene@9 237 }
elene@9 238 mesh->draw();
elene@9 239
elene@18 240 volume_preview();
eleni@0 241 glutSwapBuffers();
eleni@0 242 assert(glGetError() == GL_NO_ERROR);
eleni@0 243 }
eleni@0 244
elene@10 245 static void reshape(int x, int y)
eleni@0 246 {
eleni@0 247 glViewport(0, 0, x, y);
elene@9 248 glMatrixMode(GL_PROJECTION);
elene@9 249 glLoadIdentity();
elene@9 250 gluPerspective(45, (float)x / (float)y, 0.5, 500);
elene@9 251
eleni@0 252 if(x != win_xsz || y != win_ysz) {
eleni@0 253 win_xsz = x;
eleni@0 254 win_ysz = y;
eleni@0 255 }
eleni@0 256 }
eleni@0 257
elene@10 258 static void keyboard(unsigned char key, int x, int y)
eleni@0 259 {
elene@9 260 key_state[(int)key] = true;
elene@9 261
eleni@0 262 switch(key) {
eleni@0 263 case 27:
eleni@0 264 exit(0);
elene@9 265 case 'w':
elene@9 266 {
elene@9 267 static bool wire;
elene@9 268 wire = !wire;
elene@9 269 glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL);
elene@9 270 }
elene@9 271 break;
eleni@0 272 default:
eleni@0 273 break;
eleni@0 274 }
eleni@0 275 }
eleni@0 276
elene@10 277 static void keyboard_up(unsigned char key, int x, int y)
elene@9 278 {
elene@9 279 key_state[(int) key] = false;
elene@9 280 }
elene@9 281
eleni@0 282 static int prev_x, prev_y;
elene@9 283 static bool bn_state[32];
elene@12 284 static float prev_thres, prev_thres2;
elene@9 285
elene@10 286 static void mouse(int bn, int state, int x, int y)
eleni@0 287 {
eleni@0 288 prev_x = x;
eleni@0 289 prev_y = y;
elene@9 290
elene@9 291 bn_state[bn - GLUT_LEFT_BUTTON] = (state == GLUT_DOWN);
elene@9 292
elene@9 293 if(state == GLUT_DOWN) {
elene@9 294 prev_thres = thres;
elene@12 295 prev_thres2 = thres2;
elene@9 296 }
elene@9 297 else {
elene@12 298 if(thres != prev_thres || thres2 != prev_thres2) {
elene@9 299 mesh->clear();
elene@9 300 }
elene@9 301 }
eleni@0 302 }
eleni@0 303
elene@10 304 static void motion(int x, int y)
eleni@0 305 {
eleni@0 306 int dx = x - prev_x;
eleni@0 307 int dy = y - prev_y;
elene@9 308
elene@9 309 if(!dx && !dy)
elene@9 310 return;
elene@9 311
eleni@0 312 prev_x = x;
eleni@0 313 prev_y = y;
elene@6 314
elene@9 315 if(key_state[(int)'t']) {
elene@9 316 thres = (float)x / (float)win_xsz;
elene@9 317 printf("threshold: %f\n", thres);
elene@9 318
elene@9 319 glutPostRedisplay();
elene@9 320 return;
elene@9 321 }
elene@9 322
elene@9 323 // camera
elene@9 324 if(bn_state[0]) {
elene@9 325 if(key_state[(int)'z']) {
elene@9 326 //zoom the camera
elene@9 327
elene@9 328 cam_dist += dy * 0.1;
elene@9 329
elene@9 330 if(cam_dist < 0)
elene@9 331 cam_dist = 0;
elene@9 332 }
elene@9 333 else {
elene@9 334 //rotate the camera
elene@9 335
elene@9 336 cam_phi += dy * 0.5;
elene@9 337 cam_theta += dx * 0.5;
elene@9 338
elene@9 339 if(cam_phi > 90)
elene@9 340 cam_phi = 90;
elene@9 341 if(cam_phi < -90)
elene@9 342 cam_phi = -90;
elene@9 343 }
elene@9 344
elene@6 345 glutPostRedisplay();
elene@6 346 }
eleni@0 347 }
elene@16 348
elene@16 349 static bool init_xfer(void)
elene@16 350 {
elene@16 351 glutSetWindow(mainwin_id);
elene@16 352 int x = glutGet(GLUT_WINDOW_X);
elene@16 353 int y = glutGet(GLUT_WINDOW_Y) + glutGet(GLUT_WINDOW_HEIGHT);
elene@16 354
elene@16 355 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
elene@16 356 glutInitWindowSize(512, 100);
elene@16 357 glutInitWindowPosition(x, y);
elene@16 358
elene@16 359 xferwin_id = glutCreateWindow("Transfer Function");
elene@16 360 glutDisplayFunc(display_xfer);
elene@16 361 glutReshapeFunc(reshape_xfer);
elene@17 362 glutMouseFunc(mouse_xfer);
elene@16 363 glutMotionFunc(motion_xfer);
elene@16 364
elene@16 365 return true;
elene@16 366 }
elene@16 367
elene@16 368 static void display_xfer(void)
elene@16 369 {
elene@16 370 glClear(GL_COLOR_BUFFER_BIT);
elene@16 371
elene@16 372 int num_val = glutGet(GLUT_WINDOW_WIDTH) / 4.0;
elene@16 373 float x = 0;
elene@16 374 float dx = 1.0 / num_val;
elene@16 375 float low, high;
elene@16 376 if(thres < thres2) {
elene@16 377 low = thres;
elene@16 378 high = thres2;
elene@16 379 }
elene@16 380 else {
elene@16 381 low = thres2;
elene@16 382 high = thres;
elene@16 383 }
elene@16 384
elene@17 385 //drawing the transfer function curve
elene@17 386
elene@17 387 glLineWidth(3);
elene@17 388 glBegin(GL_LINE_STRIP);
elene@17 389 glColor3f(0.8, 0.3, 0.8);
elene@17 390 for(int i=0; i<num_val; i++) {
elene@17 391 float val = transfer_function(x, low, high);
elene@17 392 glVertex2f(x, val);
elene@17 393 x += dx;
elene@17 394 }
elene@17 395 glEnd();
elene@17 396
elene@17 397 //threshold bars
elene@17 398
elene@17 399 glLineWidth(2);
elene@17 400 glBegin(GL_LINES);
elene@17 401 glColor3f(0.4, 0.4, 0.8);
elene@17 402 glVertex2f(low, 0);
elene@17 403 glVertex2f(low, 1);
elene@17 404 glColor3f(0.4, 0.8, 0.4);
elene@17 405 glVertex2f(high, 0);
elene@17 406 glVertex2f(high, 1);
elene@17 407 glEnd();
elene@17 408
elene@17 409 /*
elene@17 410 * gradient
elene@17 411 */
elene@17 412 /* glBegin(GL_QUADS);
elene@16 413 for(int i=0; i<num_val; i++) {
elene@16 414 float val = transfer_function(x, low, high);
elene@16 415 glColor3f(val, val, val);
elene@16 416 glVertex3f(x, 1.0, 0.0);
elene@16 417 glVertex3f(x, 0.0, 0.0);
elene@16 418
elene@16 419 val = transfer_function(x + dx, low, high);
elene@16 420 glColor3f(val, val, val);
elene@16 421 glVertex3f(x + dx, 0.0, 0.0);
elene@16 422 glVertex3f(x + dx, 1.0, 0.0);
elene@16 423 x += dx;
elene@16 424 }
elene@17 425 glEnd(); */
elene@16 426
elene@16 427 glutSwapBuffers();
elene@16 428 assert(glGetError() == GL_NO_ERROR);
elene@16 429 }
elene@16 430
elene@16 431 static void reshape_xfer(int x, int y)
elene@16 432 {
elene@16 433 glViewport(0.0, 0.0, x, y);
elene@16 434 glMatrixMode(GL_PROJECTION);
elene@16 435 glLoadIdentity();
elene@16 436 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
elene@16 437 }
elene@16 438
elene@17 439 static float *select_thres;
elene@17 440 static float prev_select_thres;
elene@17 441 static void mouse_xfer(int button, int state, int x, int y)
elene@17 442 {
elene@17 443 if(button == GLUT_LEFT_BUTTON) {
elene@17 444 if(state == GLUT_DOWN) {
elene@17 445 int width = glutGet(GLUT_WINDOW_WIDTH);
elene@17 446 float xpos = (float)x / (float)width;
elene@17 447 if(fabs(xpos - thres) <= fabs(xpos - thres2)) {
elene@17 448 select_thres = &thres;
elene@17 449 }
elene@17 450 else {
elene@17 451 select_thres = &thres2;
elene@17 452 }
elene@17 453 prev_select_thres = *select_thres;
elene@17 454 }
elene@17 455 else {
elene@17 456 if(fabs(*select_thres - prev_select_thres) > 0.001) {
elene@17 457 mesh->clear();
elene@17 458 ui->sync_live();
elene@17 459 }
elene@17 460 select_thres = 0;
elene@17 461 }
elene@17 462 }
elene@17 463 }
elene@17 464
elene@16 465 static void motion_xfer(int x, int y)
elene@16 466 {
elene@17 467 if(!select_thres)
elene@17 468 return;
elene@17 469
elene@17 470 int width = glutGet(GLUT_WINDOW_WIDTH);
elene@17 471 float xpos = (float)x / (float)width;
elene@17 472
elene@17 473 *select_thres = xpos;
elene@17 474
elene@17 475 glutPostRedisplay();
elene@17 476 glutSetWindow(mainwin_id);
elene@17 477 glutPostRedisplay();
elene@16 478 }