volmetrics

view src/main.cc @ 17:0f4fff558737

transfer function
author Eleni Maria Stea <elene.mst@gmail.com>
date Mon, 03 Mar 2014 23:12:13 +0200
parents add30e2d5253
children 4e02e18e70ef
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);
23 static bool init_xfer(void);
24 static void display_xfer(void);
25 static void reshape_xfer(int x, int y);
26 static void mouse_xfer(int button, int state, int x, int y);
27 static void motion_xfer(int x, int y);
28 //todo keyb esc
30 static int mainwin_id, xferwin_id;
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 display(void)
175 {
176 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
178 glMatrixMode(GL_MODELVIEW);
179 glLoadIdentity();
180 glTranslatef(0, 0, -cam_dist);
181 glRotatef(cam_phi, 1, 0, 0);
182 glRotatef(cam_theta, 0, 1, 0);
184 /*
185 glBindTexture(GL_TEXTURE_3D, vol->get_texture());
186 glEnable(GL_TEXTURE_3D);
187 glBegin(GL_QUADS);
188 glTexCoord3f(0, 0, cur_z); glVertex3f(-1, -1, 0);
189 glTexCoord3f(0, 1, cur_z); glVertex3f(-1, 1, 0);
190 glTexCoord3f(1, 1, cur_z); glVertex3f(1, 1, 0);
191 glTexCoord3f(1, 0, cur_z); glVertex3f(1, -1, 0);
192 glEnd();
193 glDisable(GL_TEXTURE_3D);
194 */
196 if(mesh->is_empty()) {
197 printf("recalculating isosurface ... ");
198 fflush(stdout);
199 vol->create_mesh(mesh, thres, thres2, vol_res[0], vol_res[1], vol_res[2]);
200 printf("done.\n");
201 }
202 mesh->draw();
204 //TODO: draw threshold
205 glutSwapBuffers();
206 assert(glGetError() == GL_NO_ERROR);
207 }
209 static void reshape(int x, int y)
210 {
211 glViewport(0, 0, x, y);
212 glMatrixMode(GL_PROJECTION);
213 glLoadIdentity();
214 gluPerspective(45, (float)x / (float)y, 0.5, 500);
216 if(x != win_xsz || y != win_ysz) {
217 win_xsz = x;
218 win_ysz = y;
219 }
220 }
222 static void keyboard(unsigned char key, int x, int y)
223 {
224 key_state[(int)key] = true;
226 switch(key) {
227 case 27:
228 exit(0);
229 case 'w':
230 {
231 static bool wire;
232 wire = !wire;
233 glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL);
234 }
235 break;
236 default:
237 break;
238 }
239 }
241 static void keyboard_up(unsigned char key, int x, int y)
242 {
243 key_state[(int) key] = false;
244 }
246 static int prev_x, prev_y;
247 static bool bn_state[32];
248 static float prev_thres, prev_thres2;
250 static void mouse(int bn, int state, int x, int y)
251 {
252 prev_x = x;
253 prev_y = y;
255 bn_state[bn - GLUT_LEFT_BUTTON] = (state == GLUT_DOWN);
257 if(state == GLUT_DOWN) {
258 prev_thres = thres;
259 prev_thres2 = thres2;
260 }
261 else {
262 if(thres != prev_thres || thres2 != prev_thres2) {
263 mesh->clear();
264 }
265 }
266 }
268 static void motion(int x, int y)
269 {
270 int dx = x - prev_x;
271 int dy = y - prev_y;
273 if(!dx && !dy)
274 return;
276 prev_x = x;
277 prev_y = y;
279 if(key_state[(int)'t']) {
280 thres = (float)x / (float)win_xsz;
281 printf("threshold: %f\n", thres);
283 glutPostRedisplay();
284 return;
285 }
287 // camera
288 if(bn_state[0]) {
289 if(key_state[(int)'z']) {
290 //zoom the camera
292 cam_dist += dy * 0.1;
294 if(cam_dist < 0)
295 cam_dist = 0;
296 }
297 else {
298 //rotate the camera
300 cam_phi += dy * 0.5;
301 cam_theta += dx * 0.5;
303 if(cam_phi > 90)
304 cam_phi = 90;
305 if(cam_phi < -90)
306 cam_phi = -90;
307 }
309 glutPostRedisplay();
310 }
311 }
313 static bool init_xfer(void)
314 {
315 glutSetWindow(mainwin_id);
316 int x = glutGet(GLUT_WINDOW_X);
317 int y = glutGet(GLUT_WINDOW_Y) + glutGet(GLUT_WINDOW_HEIGHT);
319 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
320 glutInitWindowSize(512, 100);
321 glutInitWindowPosition(x, y);
323 xferwin_id = glutCreateWindow("Transfer Function");
324 glutDisplayFunc(display_xfer);
325 glutReshapeFunc(reshape_xfer);
326 glutMouseFunc(mouse_xfer);
327 glutMotionFunc(motion_xfer);
329 return true;
330 }
332 static void display_xfer(void)
333 {
334 glClear(GL_COLOR_BUFFER_BIT);
336 int num_val = glutGet(GLUT_WINDOW_WIDTH) / 4.0;
337 float x = 0;
338 float dx = 1.0 / num_val;
339 float low, high;
340 if(thres < thres2) {
341 low = thres;
342 high = thres2;
343 }
344 else {
345 low = thres2;
346 high = thres;
347 }
349 //drawing the transfer function curve
351 glLineWidth(3);
352 glBegin(GL_LINE_STRIP);
353 glColor3f(0.8, 0.3, 0.8);
354 for(int i=0; i<num_val; i++) {
355 float val = transfer_function(x, low, high);
356 glVertex2f(x, val);
357 x += dx;
358 }
359 glEnd();
361 //threshold bars
363 glLineWidth(2);
364 glBegin(GL_LINES);
365 glColor3f(0.4, 0.4, 0.8);
366 glVertex2f(low, 0);
367 glVertex2f(low, 1);
368 glColor3f(0.4, 0.8, 0.4);
369 glVertex2f(high, 0);
370 glVertex2f(high, 1);
371 glEnd();
373 /*
374 * gradient
375 */
376 /* glBegin(GL_QUADS);
377 for(int i=0; i<num_val; i++) {
378 float val = transfer_function(x, low, high);
379 glColor3f(val, val, val);
380 glVertex3f(x, 1.0, 0.0);
381 glVertex3f(x, 0.0, 0.0);
383 val = transfer_function(x + dx, low, high);
384 glColor3f(val, val, val);
385 glVertex3f(x + dx, 0.0, 0.0);
386 glVertex3f(x + dx, 1.0, 0.0);
387 x += dx;
388 }
389 glEnd(); */
391 glutSwapBuffers();
392 assert(glGetError() == GL_NO_ERROR);
393 }
395 static void reshape_xfer(int x, int y)
396 {
397 glViewport(0.0, 0.0, x, y);
398 glMatrixMode(GL_PROJECTION);
399 glLoadIdentity();
400 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
401 }
403 static float *select_thres;
404 static float prev_select_thres;
405 static void mouse_xfer(int button, int state, int x, int y)
406 {
407 if(button == GLUT_LEFT_BUTTON) {
408 if(state == GLUT_DOWN) {
409 int width = glutGet(GLUT_WINDOW_WIDTH);
410 float xpos = (float)x / (float)width;
411 if(fabs(xpos - thres) <= fabs(xpos - thres2)) {
412 select_thres = &thres;
413 }
414 else {
415 select_thres = &thres2;
416 }
417 prev_select_thres = *select_thres;
418 }
419 else {
420 if(fabs(*select_thres - prev_select_thres) > 0.001) {
421 mesh->clear();
422 ui->sync_live();
423 }
424 select_thres = 0;
425 }
426 }
427 }
429 static void motion_xfer(int x, int y)
430 {
431 if(!select_thres)
432 return;
434 int width = glutGet(GLUT_WINDOW_WIDTH);
435 float xpos = (float)x / (float)width;
437 *select_thres = xpos;
439 glutPostRedisplay();
440 glutSetWindow(mainwin_id);
441 glutPostRedisplay();
442 }