metasurf
diff examples/volume/src/volume.c @ 3:52664d3451ad
added volume rendering example
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 25 Oct 2011 13:30:03 +0300 |
parents | |
children | c1a60ab45bf7 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/examples/volume/src/volume.c Tue Oct 25 13:30:03 2011 +0300 1.3 @@ -0,0 +1,391 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <math.h> 1.7 +#include <assert.h> 1.8 + 1.9 +#ifndef NO_SHADERS 1.10 +#include <GL/glew.h> 1.11 +#include "sdr.h" 1.12 +#endif 1.13 + 1.14 +#ifndef __APPLE__ 1.15 +#include <GL/glut.h> 1.16 +#else 1.17 +#include <GLUT/glut.h> 1.18 +#endif 1.19 + 1.20 +#include <imago2.h> 1.21 + 1.22 +#include "cam.h" 1.23 +#include "metasurf.h" 1.24 + 1.25 +float eval(float x, float y, float z); 1.26 +void vertex(float x, float y, float z); 1.27 +void render(void); 1.28 +void disp(void); 1.29 +void reshape(int x, int y); 1.30 +void keyb(unsigned char key, int x, int y); 1.31 +void mouse(int bn, int state, int x, int y); 1.32 +void motion(int x, int y); 1.33 +int parse_args(int argc, char **argv); 1.34 + 1.35 +int stereo, fullscreen; 1.36 +int orig_xsz, orig_ysz; 1.37 + 1.38 +struct metasurface *msurf; 1.39 +float threshold = 0.5; 1.40 +#ifndef NO_SHADERS 1.41 +unsigned int sdr; 1.42 +#endif 1.43 + 1.44 +struct img_pixmap *volume; 1.45 +int xres, yres, num_slices; 1.46 + 1.47 +int dlist, need_update = 1; 1.48 + 1.49 +int main(int argc, char **argv) 1.50 +{ 1.51 + float amb[] = {0, 0, 0, 0}; 1.52 + float lpos[] = {-0.2, 0.2, 1, 0}; 1.53 + 1.54 + glutInitWindowSize(1280, 720); 1.55 + glutInit(&argc, argv); 1.56 + 1.57 + if(parse_args(argc, argv) == -1) { 1.58 + return 1; 1.59 + } 1.60 + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | (stereo ? GLUT_STEREO : 0)); 1.61 + glutCreateWindow("metasurf - volume rendering"); 1.62 + 1.63 + orig_xsz = glutGet(GLUT_WINDOW_WIDTH); 1.64 + orig_ysz = glutGet(GLUT_WINDOW_HEIGHT); 1.65 + 1.66 + if(fullscreen) { 1.67 + glutFullScreen(); 1.68 + } 1.69 + 1.70 + glutDisplayFunc(disp); 1.71 + glutReshapeFunc(reshape); 1.72 + glutKeyboardFunc(keyb); 1.73 + glutMouseFunc(mouse); 1.74 + glutMotionFunc(motion); 1.75 + 1.76 +#ifndef NO_SHADERS 1.77 + glewInit(); 1.78 + if(!(sdr = create_program_load("sdr/vert.glsl", "sdr/frag.glsl"))) { 1.79 + return 1; 1.80 + } 1.81 +#endif 1.82 + 1.83 + glEnable(GL_CULL_FACE); 1.84 + glEnable(GL_DEPTH_TEST); 1.85 + 1.86 + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb); 1.87 + 1.88 + glEnable(GL_LIGHTING); 1.89 + glEnable(GL_LIGHT0); 1.90 + glLightfv(GL_LIGHT0, GL_POSITION, lpos); 1.91 + 1.92 + glEnable(GL_NORMALIZE); 1.93 + 1.94 + cam_focus_dist(3.0); 1.95 + cam_clip(0.1, 200.0); 1.96 + cam_rotate(0, 0); 1.97 + cam_dolly(2); 1.98 + 1.99 + msurf = msurf_create(); 1.100 + msurf_eval_func(msurf, eval); 1.101 + msurf_vertex_func(msurf, vertex); 1.102 + msurf_threshold(msurf, threshold); 1.103 + msurf_resolution(msurf, xres, yres, num_slices); 1.104 + msurf_bounds(msurf, -1, -1, -1, 1, 1, 1); 1.105 + 1.106 + glClearColor(0.6, 0.6, 0.6, 1.0); 1.107 + 1.108 + dlist = glGenLists(1); 1.109 + 1.110 + glutMainLoop(); 1.111 + return 0; 1.112 +} 1.113 + 1.114 +float eval(float x, float y, float z) 1.115 +{ 1.116 + int px, py, slice; 1.117 + struct img_pixmap *img; 1.118 + 1.119 + px = round((x * 0.5 + 0.5) * xres); 1.120 + py = round((y * 0.5 + 0.5) * yres); 1.121 + slice = round((z * 0.5 + 0.5) * num_slices); 1.122 + 1.123 + if(px < 0) px = 0; 1.124 + if(px >= xres) px = xres - 1; 1.125 + 1.126 + if(py < 0) py = 0; 1.127 + if(py >= yres) py = yres - 1; 1.128 + 1.129 + if(slice < 0) slice = 0; 1.130 + if(slice >= num_slices) slice = num_slices - 1; 1.131 + 1.132 + img = volume + slice; 1.133 + return *((unsigned char*)img->pixels + py * img->width + px) / 255.0; 1.134 +} 1.135 + 1.136 +void vertex(float x, float y, float z) 1.137 +{ 1.138 + float dx = 1.0 / xres; 1.139 + float dy = 1.0 / yres; 1.140 + float dz = 1.0 / num_slices; 1.141 + float dfdx = eval(x - dx, y, z) - eval(x + dx, y, z); 1.142 + float dfdy = eval(x, y - dy, z) - eval(x, y + dy, z); 1.143 + float dfdz = eval(x, y, z - dz) - eval(x, y, z + dz); 1.144 + 1.145 + glNormal3f(dfdx, dfdy, dfdz); 1.146 + glVertex3f(x, y, z); 1.147 +} 1.148 + 1.149 +void render(void) 1.150 +{ 1.151 + float kd[] = {0.87, 0.82, 0.74, 1.0}; 1.152 + float ks[] = {0.9, 0.9, 0.9, 1.0}; 1.153 + 1.154 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, kd); 1.155 + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ks); 1.156 + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 60.0); 1.157 + 1.158 +#ifndef NO_SHADERS 1.159 + bind_program(sdr); 1.160 +#endif 1.161 + 1.162 + glMatrixMode(GL_MODELVIEW); 1.163 + glPushMatrix(); 1.164 + glRotatef(90, 1, 0, 0); 1.165 + 1.166 + if(need_update) { 1.167 + glNewList(dlist, GL_COMPILE); 1.168 + glBegin(GL_TRIANGLES); 1.169 + printf("generating mesh... "); 1.170 + fflush(stdout); 1.171 + msurf_polygonize(msurf); 1.172 + glEnd(); 1.173 + glEndList(); 1.174 + need_update = 0; 1.175 + printf("done\n"); 1.176 + } 1.177 + glCallList(dlist); 1.178 + 1.179 + glPopMatrix(); 1.180 + 1.181 + assert(glGetError() == GL_NO_ERROR); 1.182 +} 1.183 + 1.184 +void disp(void) 1.185 +{ 1.186 + if(stereo) { 1.187 + glDrawBuffer(GL_BACK_LEFT); 1.188 + } 1.189 + 1.190 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.191 + 1.192 + glMatrixMode(GL_PROJECTION); 1.193 + glLoadIdentity(); 1.194 + cam_stereo_proj_matrix(stereo ? CAM_LEFT : CAM_CENTER); 1.195 + 1.196 + glMatrixMode(GL_MODELVIEW); 1.197 + glLoadIdentity(); 1.198 + cam_stereo_view_matrix(stereo ? CAM_LEFT : CAM_CENTER); 1.199 + 1.200 + render(); 1.201 + 1.202 + if(stereo) { 1.203 + glDrawBuffer(GL_BACK_RIGHT); 1.204 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.205 + 1.206 + glMatrixMode(GL_PROJECTION); 1.207 + glLoadIdentity(); 1.208 + cam_stereo_proj_matrix(CAM_RIGHT); 1.209 + 1.210 + glMatrixMode(GL_MODELVIEW); 1.211 + glLoadIdentity(); 1.212 + cam_stereo_view_matrix(CAM_RIGHT); 1.213 + 1.214 + render(); 1.215 + } 1.216 + glutSwapBuffers(); 1.217 +} 1.218 + 1.219 +void reshape(int x, int y) 1.220 +{ 1.221 + glViewport(0, 0, x, y); 1.222 + cam_aspect((float)x / (float)y); 1.223 +} 1.224 + 1.225 +void keyb(unsigned char key, int x, int y) 1.226 +{ 1.227 + static int wire; 1.228 + 1.229 + switch(key) { 1.230 + case 27: 1.231 + exit(0); 1.232 + 1.233 + case 'f': 1.234 + fullscreen = !fullscreen; 1.235 + if(fullscreen) { 1.236 + glutFullScreen(); 1.237 + } else { 1.238 + glutReshapeWindow(orig_xsz, orig_ysz); 1.239 + } 1.240 + break; 1.241 + 1.242 + case 's': 1.243 + stereo = !stereo; 1.244 + glutPostRedisplay(); 1.245 + break; 1.246 + 1.247 + case 'w': 1.248 + wire = !wire; 1.249 + glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL); 1.250 + glutPostRedisplay(); 1.251 + break; 1.252 + 1.253 + case '=': 1.254 + threshold += 0.05; 1.255 + msurf_threshold(msurf, threshold); 1.256 + printf("threshold: %f\n", threshold); 1.257 + glutPostRedisplay(); 1.258 + need_update = 1; 1.259 + break; 1.260 + 1.261 + case '-': 1.262 + threshold -= 0.05; 1.263 + msurf_threshold(msurf, threshold); 1.264 + printf("threshold: %f\n", threshold); 1.265 + glutPostRedisplay(); 1.266 + need_update = 1; 1.267 + break; 1.268 + 1.269 + default: 1.270 + break; 1.271 + } 1.272 +} 1.273 + 1.274 +int bnstate[32]; 1.275 +int prev_x, prev_y; 1.276 + 1.277 +void mouse(int bn, int state, int x, int y) 1.278 +{ 1.279 + bnstate[bn] = state == GLUT_DOWN; 1.280 + prev_x = x; 1.281 + prev_y = y; 1.282 +} 1.283 + 1.284 +void motion(int x, int y) 1.285 +{ 1.286 + int dx, dy; 1.287 + 1.288 + dx = x - prev_x; 1.289 + dy = y - prev_y; 1.290 + prev_x = x; 1.291 + prev_y = y; 1.292 + 1.293 + if(bnstate[GLUT_LEFT_BUTTON]) { 1.294 + cam_inp_rotate(dx, dy); 1.295 + } 1.296 + if(bnstate[GLUT_RIGHT_BUTTON]) { 1.297 + cam_inp_zoom(dy); 1.298 + } 1.299 + glutPostRedisplay(); 1.300 +} 1.301 + 1.302 +struct list_node { 1.303 + struct img_pixmap img; 1.304 + struct list_node *next; 1.305 +}; 1.306 + 1.307 +int parse_args(int argc, char **argv) 1.308 +{ 1.309 + int i; 1.310 + struct list_node *head = 0, *tail = 0; 1.311 + 1.312 + for(i=1; i<argc; i++) { 1.313 + if(argv[i][0] == '-' && argv[i][2] == 0) { 1.314 + switch(argv[i][1]) { 1.315 + case 'f': 1.316 + fullscreen = !fullscreen; 1.317 + break; 1.318 + 1.319 + case 's': 1.320 + stereo = !stereo; 1.321 + break; 1.322 + 1.323 + case 'h': 1.324 + printf("usage: %s [opt]\n", argv[0]); 1.325 + printf("options:\n"); 1.326 + printf(" -f start in fullscreen\n"); 1.327 + printf(" -s enable stereoscopic rendering\n"); 1.328 + printf(" -h print usage and exit\n"); 1.329 + exit(0); 1.330 + 1.331 + default: 1.332 + fprintf(stderr, "unrecognized option: %s\n", argv[i]); 1.333 + return -1; 1.334 + } 1.335 + } else { 1.336 + struct list_node *slice; 1.337 + 1.338 + if(!(slice = malloc(sizeof *slice))) { 1.339 + fprintf(stderr, "failed to allocate volume slice: %d\n", num_slices); 1.340 + return -1; 1.341 + } 1.342 + slice->next = 0; 1.343 + 1.344 + img_init(&slice->img); 1.345 + if(img_load(&slice->img, argv[i]) == -1) { 1.346 + fprintf(stderr, "failed to load volume slice %d: %s\n", num_slices, argv[i]); 1.347 + free(slice); 1.348 + return -1; 1.349 + } 1.350 + img_convert(&slice->img, IMG_FMT_GREY8); 1.351 + 1.352 + if(num_slices > 0 && (xres != slice->img.width || yres != slice->img.height)) { 1.353 + fprintf(stderr, "error: slice %d (%s) is %dx%d, up to now we had %dx%d images\n", num_slices, argv[i], 1.354 + slice->img.width, slice->img.height, xres, yres); 1.355 + img_destroy(&slice->img); 1.356 + free(slice); 1.357 + return -1; 1.358 + } 1.359 + xres = slice->img.width; 1.360 + yres = slice->img.height; 1.361 + 1.362 + if(head) { 1.363 + tail->next = slice; 1.364 + tail = slice; 1.365 + } else { 1.366 + head = tail = slice; 1.367 + } 1.368 + printf("loaded volume slice %d: %s\n", num_slices++, argv[i]); 1.369 + } 1.370 + } 1.371 + 1.372 + if(!head) { 1.373 + fprintf(stderr, "you must specify a list of images for the volume data slices\n"); 1.374 + return -1; 1.375 + } 1.376 + 1.377 + if(!(volume = malloc(num_slices * sizeof *volume))) { 1.378 + fprintf(stderr, "failed to allocate volume data (%d slices)\n", num_slices); 1.379 + return -1; 1.380 + } 1.381 + 1.382 + for(i=0; i<num_slices; i++) { 1.383 + void *tmp; 1.384 + 1.385 + assert(head); 1.386 + volume[i] = head->img; 1.387 + 1.388 + tmp = head; 1.389 + head = head->next; 1.390 + free(tmp); 1.391 + } 1.392 + 1.393 + return 0; 1.394 +}