volmetrics

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