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 +}