volmetrics

annotate src/main.cc @ 25:4b6c952a83bd

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