volmetrics

annotate src/main.cc @ 35:df4a277adb82

port to macosx
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 06 Feb 2015 21:15:23 +0200
parents eb87d4a12bd3
children 1df14c5ffa71
rev   line source
nuclear@35 1 #include "opengl.h"
eleni@0 2
elene@17 3 #include <math.h>
eleni@0 4 #include <stdio.h>
eleni@0 5 #include <assert.h>
eleni@0 6
elene@9 7 #include <vector>
elene@9 8
elene@9 9 #include "mesh.h"
elene@22 10 #include "sdr.h"
elene@6 11 #include "volume.h"
eleni@1 12
elene@10 13 static bool init(void);
elene@10 14 static GLUI *create_ui(void);
elene@10 15 static void display(void);
elene@10 16 static void reshape(int x, int y);
elene@10 17 static void keyboard(unsigned char key, int x, int y);
elene@10 18 static void keyboard_up(unsigned char key, int x, int y);
elene@10 19 static void mouse(int button, int state, int x, int y);
elene@10 20 static void motion(int x, int y);
elene@16 21 static bool init_xfer(void);
elene@16 22 static void display_xfer(void);
elene@16 23 static void reshape_xfer(int x, int y);
elene@17 24 static void mouse_xfer(int button, int state, int x, int y);
elene@16 25 static void motion_xfer(int x, int y);
elene@25 26 static void volume_preview();
elene@25 27 static void draw_iso();
elene@25 28 static void draw_volume();
elene@16 29
elene@16 30 static int mainwin_id, xferwin_id;
elene@18 31 //todo keyb esc
elene@16 32
eleni@0 33 static int win_xsz, win_ysz;
elene@9 34 static float cam_phi, cam_theta, cam_dist = 6;
elene@9 35 static std::vector<bool> key_state(256);
eleni@0 36
elene@11 37 static const char *vol_fname = "data/test1.vol";
elene@22 38 static const char *vsdr_path = "data/shaders/transfer.v.glsl";
elene@22 39 static const char *fsdr_path = "data/shaders/transfer.f.glsl";
elene@25 40 static const char *vsdr_vol_path = "data/shaders/vol.v.glsl";
elene@25 41 static const char *fsdr_vol_path = "data/shaders/vol.f.glsl";
elene@25 42
elene@25 43 static unsigned int sprog;
elene@25 44 static unsigned int sprog_vol;
elene@6 45
elene@6 46 static Volume *vol;
elene@9 47 static Mesh *mesh;
elene@12 48 static float cur_z, thres = 0.5, thres2 = 1.0;
elene@25 49 static float slice_z = 0.5;
elene@9 50
elene@9 51 static int use_orig_vol_res = 1;
elene@9 52 static int vol_res[3]; // volume sampling resolution x/y/z
elene@26 53 static float bound_scale = 1.42;
elene@9 54
elene@9 55 static GLUI *ui;
eleni@1 56
elene@25 57 static int num_poly = 128;
elene@22 58
eleni@0 59 int main(int argc, char **argv)
eleni@0 60 {
elene@31 61 glutInitWindowSize(512, 512);
eleni@0 62 glutInit(&argc, argv);
elene@16 63 if(argv[1])
elene@16 64 vol_fname = argv[1];
elene@16 65
elene@16 66 if(!init()) {
elene@16 67 fprintf(stderr, "Failed to initialize program.\n");
elene@16 68 return 1;
elene@16 69 }
elene@16 70
elene@16 71 init_xfer();
elene@16 72
elene@16 73 glutMainLoop();
elene@16 74 return 0;
elene@16 75 }
elene@16 76
elene@16 77 static bool init()
elene@16 78 {
elene@11 79 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
eleni@0 80
elene@16 81 mainwin_id = glutCreateWindow("CT scan");
eleni@0 82 glutDisplayFunc(display);
eleni@0 83 glutReshapeFunc(reshape);
eleni@0 84 glutKeyboardFunc(keyboard);
elene@9 85 glutKeyboardUpFunc(keyboard_up);
eleni@0 86 glutMouseFunc(mouse);
eleni@0 87 glutMotionFunc(motion);
eleni@0 88
eleni@0 89 glewInit();
eleni@0 90
elene@11 91 glEnable(GL_DEPTH_TEST);
elene@11 92 glEnable(GL_NORMALIZE);
elene@11 93
elene@25 94 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
elene@25 95
elene@22 96 //FIXME shaders setup
elene@22 97 if(!(sprog = sdr_getprog(vsdr_path, fsdr_path)))
elene@22 98 {
elene@22 99 fprintf(stderr, "Failed to create shader program!\n");
elene@22 100 return false;
elene@22 101 }
elene@22 102
elene@25 103 if(!(sprog_vol = sdr_getprog(vsdr_vol_path, fsdr_vol_path)))
elene@25 104 {
elene@25 105 fprintf(stderr, "Failed to create shader program!\n");
elene@25 106 return false;
elene@25 107 }
elene@25 108
elene@9 109 vol = new Volume;
elene@11 110 if(!vol->load(vol_fname)) {
elene@11 111 fprintf(stderr, "Failed to load %s", vol_fname);
elene@9 112 return false;
elene@9 113 }
elene@9 114 mesh = new Mesh;
elene@9 115 cur_z = 0.5;
elene@9 116
elene@9 117 vol_res[0] = vol->get_slice(0)->get_width();
elene@9 118 vol_res[1] = vol->get_slice(0)->get_height();
elene@9 119 vol_res[2] = vol->get_slice_count();
elene@9 120
elene@26 121 num_poly = std::max(vol_res[0], std::max(vol_res[1], vol_res[2])) * bound_scale;
elene@26 122
elene@9 123 if(!(ui = create_ui())) {
elene@9 124 return false;
elene@9 125 }
elene@9 126
elene@9 127 return true;
elene@9 128 }
elene@9 129
elene@9 130 static GLUI_Spinner *res_spin[3];
elene@9 131 static void toggle_use_orig(int id)
elene@9 132 {
elene@9 133 for(int i=0; i<3; i++) {
elene@9 134 if(use_orig_vol_res) {
elene@9 135 res_spin[i]->disable();
elene@9 136 } else {
elene@9 137 res_spin[i]->enable();
elene@9 138 }
elene@9 139 }
elene@9 140 }
elene@9 141 static void thres_change(int id)
elene@9 142 {
elene@9 143 static float prev_thres = thres;
elene@12 144 static float prev_thres2 = thres2;
elene@9 145
elene@12 146 if(prev_thres != thres || prev_thres2 != thres2) {
elene@9 147 prev_thres = thres;
elene@12 148 prev_thres2 = thres2;
elene@23 149
elene@12 150 mesh->clear();
elene@23 151
elene@23 152 glutSetWindow(xferwin_id);
elene@23 153 glutPostRedisplay();
elene@23 154 glutSetWindow(mainwin_id);
elene@23 155 glutPostRedisplay();
elene@12 156 }
elene@23 157 }
elene@16 158
elene@12 159 static void res_change(int id)
elene@12 160 {
elene@12 161 static float prev_resx = vol_res[0];
elene@12 162 static float prev_resy = vol_res[1];
elene@12 163 static float prev_resz = vol_res[2];
elene@12 164
elene@12 165 if(prev_resx != vol_res[0] || prev_resy != vol_res[1] || prev_resz != vol_res[2]) {
elene@12 166 prev_resx = vol_res[0];
elene@12 167 prev_resy = vol_res[1];
elene@12 168 prev_resz = vol_res[2];
elene@9 169 mesh->clear();
elene@9 170 }
elene@9 171 }
elene@10 172 static GLUI *create_ui()
elene@9 173 {
elene@9 174 GLUI *ui = GLUI_Master.create_glui("ui");
elene@9 175 assert(ui);
elene@9 176
elene@9 177 ui->set_main_gfx_window(glutGetWindow());
elene@9 178
elene@12 179 GLUI_Panel *thres_panel = ui->add_panel("iso thresholds");
elene@12 180
elene@12 181 GLUI_Spinner *thres_spin = ui->add_spinner_to_panel(thres_panel, "T1", GLUI_SPINNER_FLOAT, &thres, 0, thres_change);
elene@9 182 thres_spin->set_float_limits(0, 1);
elene@9 183
elene@12 184 GLUI_Spinner *thres2_spin = ui->add_spinner_to_panel(thres_panel, "T2", GLUI_SPINNER_FLOAT, &thres2, 0, thres_change);
elene@12 185 thres2_spin->set_float_limits(0, 1);
elene@12 186
elene@29 187 #ifdef ISO
elene@9 188 GLUI_Panel *res_panel = ui->add_panel("volume resolution");
elene@9 189
elene@9 190 ui->add_checkbox_to_panel(res_panel, "original resolution", &use_orig_vol_res, 0, toggle_use_orig);
elene@9 191
elene@9 192 static const char *res_spin_name[] = {"x", "y", "z"};
elene@9 193 for(int i=0; i<3; i++) {
elene@12 194 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 195 res_spin[i]->set_int_limits(8, 256); // TODO limits as arguments or config
elene@9 196 res_spin[i]->disable();
elene@9 197 }
elene@29 198 #endif
elene@20 199 GLUI_Panel *preview_panel = ui->add_panel("volume preview");
elene@20 200
elene@22 201 GLUI_Spinner *preview_spin = ui->add_spinner_to_panel(preview_panel, "slice z", GLUI_SPINNER_FLOAT, &slice_z, 0);
elene@20 202 preview_spin->set_float_limits(0, 1);
elene@20 203
elene@9 204 return ui;
elene@9 205 }
elene@9 206
elene@18 207 static void volume_preview ()
elene@18 208 {
elene@18 209 float aspect = win_xsz / win_ysz;
elene@18 210
elene@21 211 glDisable(GL_DEPTH_TEST);
elene@18 212
elene@22 213 glUseProgram(sprog);
elene@23 214 int tmin_loc = glGetUniformLocation(sprog, "tmin");
elene@23 215 if(tmin_loc != -1)
elene@23 216 glUniform1f(tmin_loc, std::min(thres, thres2));
elene@23 217 int tmax_loc = glGetUniformLocation(sprog, "tmax");
elene@23 218 if(tmax_loc != -1)
elene@23 219 glUniform1f(tmax_loc, std::max(thres, thres2));
elene@22 220
elene@18 221 glMatrixMode(GL_MODELVIEW);
elene@18 222 glPushMatrix();
elene@18 223 glLoadIdentity();
elene@18 224
elene@18 225 glMatrixMode(GL_PROJECTION);
elene@18 226 glPushMatrix();
elene@18 227 glLoadIdentity();
elene@25 228 glOrtho(0, aspect, 0, 1, -1, 1);
elene@18 229
elene@18 230 glBindTexture(GL_TEXTURE_3D, vol->get_texture());
elene@18 231 glEnable(GL_TEXTURE_3D);
elene@18 232 glBegin(GL_QUADS);
elene@21 233 glColor3f(1.0, 1.0, 1.0);
elene@25 234 glTexCoord3f(0, 0, slice_z); glVertex3f(0, 1, 0);
elene@25 235 glTexCoord3f(0, 1, slice_z); glVertex3f(0, 0.75, 0);
elene@25 236 glTexCoord3f(1, 1, slice_z); glVertex3f(0.25, 0.75, 0);
elene@25 237 glTexCoord3f(1, 0, slice_z); glVertex3f(0.25, 1, 0);
elene@18 238 glEnd();
elene@18 239 glDisable(GL_TEXTURE_3D);
elene@18 240
elene@30 241 glUseProgram(0);
elene@30 242
elene@32 243 glLineWidth(2);
elene@21 244 glBegin(GL_LINE_LOOP);
elene@32 245 glColor3f(0.8, 0.3, 0.8);
elene@30 246 glVertex3f(0, 1, 0);
elene@30 247 glVertex3f(0, 0.75, 0);
elene@30 248 glVertex3f(0.25, 0.75, 0);
elene@30 249 glVertex3f(0.25, 1, 0);
elene@21 250 glEnd();
elene@21 251
elene@18 252 glMatrixMode(GL_PROJECTION);
elene@18 253 glPopMatrix();
elene@18 254
elene@18 255 glMatrixMode(GL_MODELVIEW);
elene@18 256 glPopMatrix();
elene@18 257
elene@21 258 glEnable(GL_DEPTH_TEST);
elene@25 259 }
elene@25 260
elene@25 261 static void draw_iso()
elene@25 262 {
elene@25 263 if(mesh->is_empty()) {
elene@25 264 printf("recalculating isosurface ... ");
elene@25 265 fflush(stdout);
elene@25 266 vol->create_mesh(mesh, thres, thres2, vol_res[0], vol_res[1], vol_res[2]);
elene@25 267 printf("done.\n");
elene@25 268 }
elene@25 269 mesh->draw();
elene@25 270 }
elene@25 271
elene@25 272 static void draw_volume()
elene@25 273 {
elene@25 274 glUseProgram(sprog_vol);
elene@25 275
elene@25 276 int tmin_loc = glGetUniformLocation(sprog_vol, "tmin");
elene@25 277 if(tmin_loc != -1)
elene@25 278 glUniform1f(tmin_loc, std::min(thres, thres2));
elene@25 279 int tmax_loc = glGetUniformLocation(sprog_vol, "tmax");
elene@25 280 if(tmax_loc != -1)
elene@25 281 glUniform1f(tmax_loc, std::max(thres, thres2));
elene@25 282
elene@25 283 int res_loc = glGetUniformLocation(sprog_vol, "res");
elene@25 284 if(res_loc != -1)
elene@26 285 glUniform3f(res_loc, (float)vol_res[0], (float)vol_res[1], (float)vol_res[2]);
elene@25 286
elene@30 287 glRotatef(-vol->get_volume_rotation(), 1, 0, 0);
elene@30 288
elene@25 289 glDisable(GL_DEPTH_TEST);
elene@25 290 glBindTexture(GL_TEXTURE_3D, vol->get_texture());
elene@25 291 glEnable(GL_TEXTURE_3D);
elene@25 292 glEnable(GL_BLEND);
elene@25 293 glBegin(GL_QUADS);
elene@25 294 for(int i=0; i<num_poly; i++)
elene@25 295 {
elene@25 296 float tex_z = (float)i / (float)num_poly;
elene@25 297 float z = 2 * tex_z - 1;
elene@25 298
elene@26 299 glTexCoord3f(0, 0, tex_z); glVertex3f(-bound_scale, -bound_scale, z * bound_scale);
elene@26 300 glTexCoord3f(0, 1, tex_z); glVertex3f(-bound_scale, bound_scale, z * bound_scale);
elene@26 301 glTexCoord3f(1, 1, tex_z); glVertex3f(bound_scale, bound_scale, z * bound_scale);
elene@26 302 glTexCoord3f(1, 0, tex_z); glVertex3f(bound_scale, -bound_scale, z * bound_scale);
elene@25 303 }
elene@25 304 glEnd();
elene@25 305 glDisable(GL_BLEND);
elene@25 306 glDisable(GL_TEXTURE_3D);
elene@25 307 glEnable(GL_DEPTH_TEST);
elene@25 308
elene@25 309 glUseProgram(0);
elene@18 310 }
elene@18 311
elene@10 312 static void display(void)
eleni@0 313 {
elene@9 314 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
elene@9 315
elene@9 316 glMatrixMode(GL_MODELVIEW);
elene@9 317 glLoadIdentity();
elene@9 318 glTranslatef(0, 0, -cam_dist);
elene@9 319 glRotatef(cam_phi, 1, 0, 0);
elene@9 320 glRotatef(cam_theta, 0, 1, 0);
elene@9 321
elene@25 322 //draw_slices();
elene@25 323 //draw_iso();
elene@25 324 draw_volume();
elene@9 325
elene@18 326 volume_preview();
eleni@0 327 glutSwapBuffers();
eleni@0 328 assert(glGetError() == GL_NO_ERROR);
eleni@0 329 }
eleni@0 330
elene@10 331 static void reshape(int x, int y)
eleni@0 332 {
eleni@0 333 glViewport(0, 0, x, y);
elene@9 334 glMatrixMode(GL_PROJECTION);
elene@9 335 glLoadIdentity();
elene@9 336 gluPerspective(45, (float)x / (float)y, 0.5, 500);
elene@9 337
elene@25 338 win_xsz = x;
elene@25 339 win_ysz = y;
eleni@0 340 }
eleni@0 341
elene@10 342 static void keyboard(unsigned char key, int x, int y)
eleni@0 343 {
elene@9 344 key_state[(int)key] = true;
elene@9 345
eleni@0 346 switch(key) {
eleni@0 347 case 27:
eleni@0 348 exit(0);
elene@9 349 case 'w':
elene@9 350 {
elene@9 351 static bool wire;
elene@9 352 wire = !wire;
elene@9 353 glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL);
elene@9 354 }
elene@9 355 break;
eleni@0 356 default:
eleni@0 357 break;
eleni@0 358 }
eleni@0 359 }
eleni@0 360
elene@10 361 static void keyboard_up(unsigned char key, int x, int y)
elene@9 362 {
elene@9 363 key_state[(int) key] = false;
elene@9 364 }
elene@9 365
eleni@0 366 static int prev_x, prev_y;
elene@9 367 static bool bn_state[32];
elene@12 368 static float prev_thres, prev_thres2;
elene@9 369
elene@10 370 static void mouse(int bn, int state, int x, int y)
eleni@0 371 {
eleni@0 372 prev_x = x;
eleni@0 373 prev_y = y;
elene@9 374
elene@9 375 bn_state[bn - GLUT_LEFT_BUTTON] = (state == GLUT_DOWN);
elene@9 376
elene@9 377 if(state == GLUT_DOWN) {
elene@9 378 prev_thres = thres;
elene@12 379 prev_thres2 = thres2;
elene@9 380 }
elene@9 381 else {
elene@12 382 if(thres != prev_thres || thres2 != prev_thres2) {
elene@9 383 mesh->clear();
elene@9 384 }
elene@9 385 }
eleni@0 386 }
eleni@0 387
elene@10 388 static void motion(int x, int y)
eleni@0 389 {
eleni@0 390 int dx = x - prev_x;
eleni@0 391 int dy = y - prev_y;
elene@9 392
elene@9 393 if(!dx && !dy)
elene@9 394 return;
elene@9 395
eleni@0 396 prev_x = x;
eleni@0 397 prev_y = y;
elene@6 398
elene@9 399 if(key_state[(int)'t']) {
elene@9 400 thres = (float)x / (float)win_xsz;
elene@9 401 printf("threshold: %f\n", thres);
elene@9 402
elene@9 403 glutPostRedisplay();
elene@9 404 return;
elene@9 405 }
elene@9 406
elene@9 407 // camera
elene@9 408 if(bn_state[0]) {
elene@9 409 if(key_state[(int)'z']) {
elene@9 410 //zoom the camera
elene@9 411
elene@9 412 cam_dist += dy * 0.1;
elene@9 413
elene@9 414 if(cam_dist < 0)
elene@9 415 cam_dist = 0;
elene@9 416 }
elene@9 417 else {
elene@9 418 //rotate the camera
elene@9 419
elene@9 420 cam_phi += dy * 0.5;
elene@9 421 cam_theta += dx * 0.5;
elene@9 422
elene@9 423 if(cam_phi > 90)
elene@9 424 cam_phi = 90;
elene@9 425 if(cam_phi < -90)
elene@9 426 cam_phi = -90;
elene@9 427 }
elene@9 428
elene@6 429 glutPostRedisplay();
elene@6 430 }
eleni@0 431 }
elene@16 432
elene@16 433 static bool init_xfer(void)
elene@16 434 {
elene@16 435 glutSetWindow(mainwin_id);
elene@16 436 int x = glutGet(GLUT_WINDOW_X);
elene@16 437 int y = glutGet(GLUT_WINDOW_Y) + glutGet(GLUT_WINDOW_HEIGHT);
elene@16 438
elene@16 439 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
elene@16 440 glutInitWindowSize(512, 100);
elene@16 441 glutInitWindowPosition(x, y);
elene@16 442
elene@16 443 xferwin_id = glutCreateWindow("Transfer Function");
elene@16 444 glutDisplayFunc(display_xfer);
elene@16 445 glutReshapeFunc(reshape_xfer);
elene@17 446 glutMouseFunc(mouse_xfer);
elene@16 447 glutMotionFunc(motion_xfer);
elene@16 448
elene@16 449 return true;
elene@16 450 }
elene@16 451
elene@16 452 static void display_xfer(void)
elene@16 453 {
elene@16 454 glClear(GL_COLOR_BUFFER_BIT);
elene@16 455
elene@16 456 int num_val = glutGet(GLUT_WINDOW_WIDTH) / 4.0;
elene@16 457 float x = 0;
elene@16 458 float dx = 1.0 / num_val;
elene@16 459 float low, high;
elene@16 460 if(thres < thres2) {
elene@16 461 low = thres;
elene@16 462 high = thres2;
elene@16 463 }
elene@16 464 else {
elene@16 465 low = thres2;
elene@16 466 high = thres;
elene@16 467 }
elene@16 468
elene@34 469
elene@34 470 //drawing the histogram
elene@34 471 float hmax = 1 / (float)vol->max_histogram_value;
elene@34 472
elene@34 473 glBegin(GL_QUADS);
elene@34 474 for (int i=0; i<HIST_SIZE; i++) {
elene@34 475 float x0 = (float)i / HIST_SIZE;
elene@34 476 float x1 = (float)(i + 1) / HIST_SIZE;
elene@34 477
elene@34 478 glColor3f(0.3, 0.3, 0.3);
elene@34 479 glVertex3f(x0, 0, 0);
elene@34 480 glVertex3f(x1, 0, 0);
elene@34 481 glVertex3f(x1, hmax * vol->histogram[i + 1], 0);
elene@34 482 glVertex3f(x0, hmax * vol->histogram[i], 0);
elene@34 483 }
elene@34 484 glEnd();
elene@34 485
elene@17 486 //drawing the transfer function curve
elene@17 487
elene@17 488 glLineWidth(3);
elene@17 489 glBegin(GL_LINE_STRIP);
elene@17 490 glColor3f(0.8, 0.3, 0.8);
elene@17 491 for(int i=0; i<num_val; i++) {
elene@17 492 float val = transfer_function(x, low, high);
elene@17 493 glVertex2f(x, val);
elene@17 494 x += dx;
elene@17 495 }
elene@17 496 glEnd();
elene@17 497
elene@17 498 //threshold bars
elene@17 499
elene@17 500 glLineWidth(2);
elene@17 501 glBegin(GL_LINES);
elene@17 502 glColor3f(0.4, 0.4, 0.8);
elene@17 503 glVertex2f(low, 0);
elene@17 504 glVertex2f(low, 1);
elene@17 505 glColor3f(0.4, 0.8, 0.4);
elene@17 506 glVertex2f(high, 0);
elene@17 507 glVertex2f(high, 1);
elene@17 508 glEnd();
elene@17 509
elene@17 510 /*
elene@17 511 * gradient
elene@17 512 */
elene@17 513 /* glBegin(GL_QUADS);
elene@16 514 for(int i=0; i<num_val; i++) {
elene@16 515 float val = transfer_function(x, low, high);
elene@16 516 glColor3f(val, val, val);
elene@16 517 glVertex3f(x, 1.0, 0.0);
elene@16 518 glVertex3f(x, 0.0, 0.0);
elene@16 519
elene@16 520 val = transfer_function(x + dx, low, high);
elene@16 521 glColor3f(val, val, val);
elene@16 522 glVertex3f(x + dx, 0.0, 0.0);
elene@16 523 glVertex3f(x + dx, 1.0, 0.0);
elene@16 524 x += dx;
elene@16 525 }
elene@17 526 glEnd(); */
elene@16 527
elene@16 528 glutSwapBuffers();
elene@16 529 assert(glGetError() == GL_NO_ERROR);
elene@16 530 }
elene@16 531
elene@16 532 static void reshape_xfer(int x, int y)
elene@16 533 {
elene@16 534 glViewport(0.0, 0.0, x, y);
elene@16 535 glMatrixMode(GL_PROJECTION);
elene@16 536 glLoadIdentity();
elene@16 537 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
elene@16 538 }
elene@16 539
elene@17 540 static float *select_thres;
elene@17 541 static float prev_select_thres;
elene@17 542 static void mouse_xfer(int button, int state, int x, int y)
elene@17 543 {
elene@17 544 if(button == GLUT_LEFT_BUTTON) {
elene@17 545 if(state == GLUT_DOWN) {
elene@17 546 int width = glutGet(GLUT_WINDOW_WIDTH);
elene@17 547 float xpos = (float)x / (float)width;
elene@33 548 if(fabs(xpos - thres) <= fabs(xpos - thres2) && fabs(xpos - thres) < 0.1) {
elene@17 549 select_thres = &thres;
elene@17 550 }
elene@33 551 else if (fabs(xpos - thres2) < 0.1) {
elene@17 552 select_thres = &thres2;
elene@17 553 }
elene@33 554 else
elene@33 555 select_thres = 0;
elene@33 556
elene@33 557 if (select_thres)
elene@33 558 prev_select_thres = *select_thres;
elene@17 559 }
elene@17 560 else {
elene@33 561 if(!prev_select_thres || !select_thres) {
elene@33 562 select_thres = 0;
elene@33 563 return;
elene@33 564 }
elene@17 565 if(fabs(*select_thres - prev_select_thres) > 0.001) {
elene@17 566 mesh->clear();
elene@17 567 ui->sync_live();
elene@17 568 }
elene@17 569 select_thres = 0;
elene@17 570 }
elene@17 571 }
elene@17 572 }
elene@17 573
elene@16 574 static void motion_xfer(int x, int y)
elene@16 575 {
elene@17 576 if(!select_thres)
elene@17 577 return;
elene@17 578
elene@17 579 int width = glutGet(GLUT_WINDOW_WIDTH);
elene@17 580 float xpos = (float)x / (float)width;
elene@17 581
elene@17 582 *select_thres = xpos;
elene@23 583 thres_change(0);
elene@17 584
elene@17 585 glutPostRedisplay();
elene@17 586 glutSetWindow(mainwin_id);
elene@17 587 glutPostRedisplay();
elene@16 588 }