metasurf

view examples/volume/src/volume.c @ 11:430d8dde62aa

random changes
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 23 Aug 2015 07:17:56 +0300
parents c1a60ab45bf7
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <assert.h>
6 #ifndef NO_SHADERS
7 #include <GL/glew.h>
8 #include "sdr.h"
9 #endif
11 #ifndef __APPLE__
12 #include <GL/glut.h>
13 #else
14 #include <GLUT/glut.h>
15 #endif
17 #include <imago2.h>
19 #include "cam.h"
20 #include "metasurf.h"
22 float eval(float x, float y, float z);
23 void vertex(float x, float y, float z);
24 void render(void);
25 void disp(void);
26 void reshape(int x, int y);
27 void keyb(unsigned char key, int x, int y);
28 void keyb_up(unsigned char key, int x, int y);
29 void mouse(int bn, int state, int x, int y);
30 void motion(int x, int y);
31 int parse_args(int argc, char **argv);
33 int stereo, fullscreen;
34 int orig_xsz, orig_ysz;
36 struct metasurface *msurf;
37 float threshold = 0.5;
38 #ifndef NO_SHADERS
39 unsigned int sdr;
40 #endif
42 float yscale = 1.0;
44 struct img_pixmap *volume;
45 int xres, yres, num_slices;
47 int dlist, need_update = 1;
49 int main(int argc, char **argv)
50 {
51 float amb[] = {0, 0, 0, 0};
52 float lpos[] = {-0.2, 0.2, 1, 0};
54 glutInitWindowSize(1280, 720);
55 glutInit(&argc, argv);
57 if(parse_args(argc, argv) == -1) {
58 return 1;
59 }
60 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | (stereo ? GLUT_STEREO : 0));
61 glutCreateWindow("metasurf - volume rendering");
63 orig_xsz = glutGet(GLUT_WINDOW_WIDTH);
64 orig_ysz = glutGet(GLUT_WINDOW_HEIGHT);
66 if(fullscreen) {
67 glutFullScreen();
68 }
70 glutDisplayFunc(disp);
71 glutReshapeFunc(reshape);
72 glutKeyboardFunc(keyb);
73 glutKeyboardUpFunc(keyb_up);
74 glutMouseFunc(mouse);
75 glutMotionFunc(motion);
77 #ifndef NO_SHADERS
78 glewInit();
79 if(!(sdr = create_program_load("sdr/vert.glsl", "sdr/frag.glsl"))) {
80 return 1;
81 }
82 #endif
84 glEnable(GL_CULL_FACE);
85 glEnable(GL_DEPTH_TEST);
87 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
89 glEnable(GL_LIGHTING);
90 glEnable(GL_LIGHT0);
91 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
93 glEnable(GL_NORMALIZE);
95 cam_focus_dist(3.0);
96 cam_clip(0.1, 200.0);
97 cam_rotate(0, 0);
98 cam_dolly(2);
100 msurf = msurf_create();
101 msurf_eval_func(msurf, eval);
102 msurf_vertex_func(msurf, vertex);
103 msurf_threshold(msurf, threshold);
104 msurf_resolution(msurf, xres, yres, num_slices);
105 msurf_bounds(msurf, -1, -1, -1, 1, 1, 1);
107 glClearColor(0.6, 0.6, 0.6, 1.0);
109 dlist = glGenLists(1);
111 glutMainLoop();
112 return 0;
113 }
115 float eval(float x, float y, float z)
116 {
117 int px, py, slice;
118 struct img_pixmap *img;
120 px = round((x * 0.5 + 0.5) * xres);
121 py = round((y * 0.5 + 0.5) * yres);
122 slice = round((z * 0.5 + 0.5) * num_slices);
124 if(px < 0) px = 0;
125 if(px >= xres) px = xres - 1;
127 if(py < 0) py = 0;
128 if(py >= yres) py = yres - 1;
130 if(slice < 0) slice = 0;
131 if(slice >= num_slices) slice = num_slices - 1;
133 img = volume + slice;
134 return *((unsigned char*)img->pixels + py * img->width + px) / 255.0;
135 }
137 void vertex(float x, float y, float z)
138 {
139 float dx = 1.0 / xres;
140 float dy = 1.0 / yres;
141 float dz = 1.0 / num_slices;
142 float dfdx = eval(x - dx, y, z) - eval(x + dx, y, z);
143 float dfdy = eval(x, y - dy, z) - eval(x, y + dy, z);
144 float dfdz = eval(x, y, z - dz) - eval(x, y, z + dz);
146 glNormal3f(dfdx, dfdy, dfdz);
147 glVertex3f(x, y, z);
148 }
150 void render(void)
151 {
152 float kd[] = {0.87, 0.82, 0.74, 1.0};
153 float ks[] = {0.9, 0.9, 0.9, 1.0};
155 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, kd);
156 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ks);
157 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 60.0);
159 #ifndef NO_SHADERS
160 bind_program(sdr);
161 #endif
163 glMatrixMode(GL_MODELVIEW);
164 glPushMatrix();
165 glScalef(1.0, yscale, 1.0);
166 glRotatef(90, 1, 0, 0);
168 if(need_update) {
169 glNewList(dlist, GL_COMPILE);
170 glBegin(GL_TRIANGLES);
171 printf("generating mesh... ");
172 fflush(stdout);
173 msurf_polygonize(msurf);
174 glEnd();
175 glEndList();
176 need_update = 0;
177 printf("done\n");
178 }
179 glCallList(dlist);
181 glPopMatrix();
183 assert(glGetError() == GL_NO_ERROR);
184 }
186 void disp(void)
187 {
188 if(stereo) {
189 glDrawBuffer(GL_BACK_LEFT);
190 }
192 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
194 glMatrixMode(GL_PROJECTION);
195 glLoadIdentity();
196 cam_stereo_proj_matrix(stereo ? CAM_LEFT : CAM_CENTER);
198 glMatrixMode(GL_MODELVIEW);
199 glLoadIdentity();
200 cam_stereo_view_matrix(stereo ? CAM_LEFT : CAM_CENTER);
202 render();
204 if(stereo) {
205 glDrawBuffer(GL_BACK_RIGHT);
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
208 glMatrixMode(GL_PROJECTION);
209 glLoadIdentity();
210 cam_stereo_proj_matrix(CAM_RIGHT);
212 glMatrixMode(GL_MODELVIEW);
213 glLoadIdentity();
214 cam_stereo_view_matrix(CAM_RIGHT);
216 render();
217 }
218 glutSwapBuffers();
219 }
221 void reshape(int x, int y)
222 {
223 glViewport(0, 0, x, y);
224 cam_aspect((float)x / (float)y);
225 }
227 int mode_scale;
229 void keyb(unsigned char key, int x, int y)
230 {
231 static int wire;
233 switch(key) {
234 case 27:
235 exit(0);
237 case 'f':
238 fullscreen = !fullscreen;
239 if(fullscreen) {
240 glutFullScreen();
241 } else {
242 glutReshapeWindow(orig_xsz, orig_ysz);
243 }
244 break;
246 case 's':
247 stereo = !stereo;
248 glutPostRedisplay();
249 break;
251 case 'w':
252 wire = !wire;
253 glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL);
254 glutPostRedisplay();
255 break;
257 case '=':
258 threshold += 0.05;
259 msurf_threshold(msurf, threshold);
260 printf("threshold: %f\n", threshold);
261 glutPostRedisplay();
262 need_update = 1;
263 break;
265 case '-':
266 threshold -= 0.05;
267 msurf_threshold(msurf, threshold);
268 printf("threshold: %f\n", threshold);
269 glutPostRedisplay();
270 need_update = 1;
271 break;
273 case 'y':
274 mode_scale = 1;
275 break;
277 default:
278 break;
279 }
280 }
282 void keyb_up(unsigned char key, int x, int y)
283 {
284 switch(key) {
285 case 'y':
286 mode_scale = 0;
287 break;
288 }
289 }
291 int bnstate[32];
292 int prev_x, prev_y;
294 void mouse(int bn, int state, int x, int y)
295 {
296 bnstate[bn] = state == GLUT_DOWN;
297 prev_x = x;
298 prev_y = y;
299 }
301 void motion(int x, int y)
302 {
303 int dx, dy;
305 dx = x - prev_x;
306 dy = y - prev_y;
307 prev_x = x;
308 prev_y = y;
310 if(mode_scale) {
311 yscale += dy * 0.001;
312 } else {
313 if(bnstate[GLUT_LEFT_BUTTON]) {
314 cam_inp_rotate(dx, dy);
315 }
316 if(bnstate[GLUT_RIGHT_BUTTON]) {
317 cam_inp_zoom(dy);
318 }
319 }
320 glutPostRedisplay();
321 }
323 struct list_node {
324 struct img_pixmap img;
325 struct list_node *next;
326 };
328 int parse_args(int argc, char **argv)
329 {
330 int i;
331 char *endp;
332 struct list_node *head = 0, *tail = 0;
334 for(i=1; i<argc; i++) {
335 if(argv[i][0] == '-' && argv[i][2] == 0) {
336 switch(argv[i][1]) {
337 case 'f':
338 fullscreen = !fullscreen;
339 break;
341 case 's':
342 stereo = !stereo;
343 break;
345 case 't':
346 threshold = strtod(argv[++i], &endp);
347 if(endp == argv[i]) {
348 fprintf(stderr, "-t must be followed by a number\n");
349 return -1;
350 }
351 break;
353 case 'h':
354 printf("usage: %s [opt]\n", argv[0]);
355 printf("options:\n");
356 printf(" -f start in fullscreen\n");
357 printf(" -s enable stereoscopic rendering\n");
358 printf(" -h print usage and exit\n");
359 exit(0);
361 default:
362 fprintf(stderr, "unrecognized option: %s\n", argv[i]);
363 return -1;
364 }
365 } else {
366 struct list_node *slice;
368 if(!(slice = malloc(sizeof *slice))) {
369 fprintf(stderr, "failed to allocate volume slice: %d\n", num_slices);
370 return -1;
371 }
372 slice->next = 0;
374 img_init(&slice->img);
375 if(img_load(&slice->img, argv[i]) == -1) {
376 fprintf(stderr, "failed to load volume slice %d: %s\n", num_slices, argv[i]);
377 free(slice);
378 return -1;
379 }
380 img_convert(&slice->img, IMG_FMT_GREY8);
382 if(num_slices > 0 && (xres != slice->img.width || yres != slice->img.height)) {
383 fprintf(stderr, "error: slice %d (%s) is %dx%d, up to now we had %dx%d images\n", num_slices, argv[i],
384 slice->img.width, slice->img.height, xres, yres);
385 img_destroy(&slice->img);
386 free(slice);
387 return -1;
388 }
389 xres = slice->img.width;
390 yres = slice->img.height;
392 if(head) {
393 tail->next = slice;
394 tail = slice;
395 } else {
396 head = tail = slice;
397 }
398 printf("loaded volume slice %d: %s\n", num_slices++, argv[i]);
399 }
400 }
402 if(!head) {
403 fprintf(stderr, "you must specify a list of images for the volume data slices\n");
404 return -1;
405 }
407 if(!(volume = malloc(num_slices * sizeof *volume))) {
408 fprintf(stderr, "failed to allocate volume data (%d slices)\n", num_slices);
409 return -1;
410 }
412 for(i=0; i<num_slices; i++) {
413 void *tmp;
415 assert(head);
416 volume[i] = head->img;
418 tmp = head;
419 head = head->next;
420 free(tmp);
421 }
423 return 0;
424 }