qvolray

view src/volray.cc @ 18:3d05c261a2f4

demo metaballs crash & burn
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 11 Apr 2012 06:08:59 +0300
parents 17d9dc2edc91
children 784d3d321caa
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
5 #include <GL/glew.h>
6 #ifndef __APPLE__
7 #include <GL/glut.h>
8 #else
9 #include <GLUT/glut.h>
10 #endif
12 #include <vmath/vmath.h>
13 #include <imago2.h>
14 #include "sdr.h"
15 #include "volume.h"
16 #include "ui.h"
17 #include "demo.h"
19 #define XFER_MAP_SZ 512
21 static void render_volume();
22 static void draw_slice();
23 static void draw_xfer_func();
25 /*
26 void keyb(unsigned char key, int x, int y);
27 void keyb_up(unsigned char key, int x, int y);
28 void mouse(int bn, int state, int x, int y);
29 void motion(int x, int y);
30 int parse_args(int argc, char **argv);
31 */
33 static void create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale);
34 static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg);
35 static int round_pow2(int x);
36 static void create_transfer_map(float mean, float sdev);
38 static float cam_theta = 0, cam_phi = 0, cam_dist = 4.0;
39 static float cam_x, cam_y, cam_z;
41 static Vector2 tex_scale;
42 static unsigned int vol_sdr, slice_sdr, ray_tex;
43 static int win_xsz, win_ysz;
44 static bool raytex_needs_recalc = true;
46 static unsigned int xfer_tex;
47 static float xfer_mean = 0.7, xfer_sdev = 0.1;
48 static bool xfertex_needs_recalc = true;
50 static float cur_z = 0.0;
51 static float ray_step = 0.01;
53 static Volume *volume;
56 bool volray_init()
57 {
58 glewInit();
60 if(!(vol_sdr = create_program_load("sdr/volray.v.glsl", "sdr/volray.p.glsl"))) {
61 return false;
62 }
63 set_uniform_int(vol_sdr, "volume", 0);
64 set_uniform_int(vol_sdr, "ray_tex", 1);
65 set_uniform_int(vol_sdr, "xfer_tex", 2);
66 set_uniform_float(vol_sdr, "ray_step", ray_step);
67 set_uniform_float(vol_sdr, "zclip", cur_z);
69 if(!(slice_sdr = create_program_load(0, "sdr/slice.p.glsl"))) {
70 return false;
71 }
72 set_uniform_int(slice_sdr, "volume", 0);
73 set_uniform_int(slice_sdr, "xfer_tex", 1);
75 init_demo();
77 return true;
78 }
80 void volray_setvolume(Volume *vol)
81 {
82 volume = vol;
83 }
85 Volume *volray_getvolume()
86 {
87 return volume;
88 }
90 void volray_draw(void)
91 {
92 /* recalculate primary ray texture if needed */
93 if(raytex_needs_recalc) {
94 create_ray_texture(win_xsz, win_ysz, 50.0, &tex_scale);
95 }
96 /* recalculate transfer function texture if needed */
97 if(xfertex_needs_recalc) {
98 create_transfer_map(xfer_mean, xfer_sdev);
99 }
101 draw_demo();
103 glClear(GL_COLOR_BUFFER_BIT);
105 if(volume) {
106 render_volume();
107 draw_slice();
108 draw_xfer_func();
109 }
111 assert(glGetError() == GL_NO_ERROR);
112 }
114 static void render_volume(void)
115 {
116 /* set the camera transformation */
117 glMatrixMode(GL_MODELVIEW);
118 glPushMatrix();
119 glLoadIdentity();
120 glRotatef(-90, 1, 0, 0);
121 glTranslatef(cam_x, cam_y, -cam_z);
122 glRotatef(cam_theta, 0, 1, 0);
123 glRotatef(cam_phi, 1, 0, 0);
124 glTranslatef(0, 0, -cam_dist);
126 /* setup the texture matrix to map the useful part of the ray texture to [0,1] */
127 glMatrixMode(GL_TEXTURE);
128 glPushMatrix();
129 glLoadIdentity();
130 glScalef(tex_scale.x, tex_scale.y, 1.0);
132 /* tex unit0: volume data 3D texture */
133 glActiveTexture(GL_TEXTURE0);
134 glBindTexture(GL_TEXTURE_3D, volume->get_texture());
135 glEnable(GL_TEXTURE_3D);
137 /* tex unit1: primary rays in view space */
138 glActiveTexture(GL_TEXTURE1);
139 glBindTexture(GL_TEXTURE_2D, ray_tex);
140 glEnable(GL_TEXTURE_2D);
142 /* tex unit2: transfer function (1d) */
143 glActiveTexture(GL_TEXTURE2);
144 glBindTexture(GL_TEXTURE_1D, xfer_tex);
145 glEnable(GL_TEXTURE_1D);
147 bind_program(vol_sdr);
148 glBegin(GL_QUADS);
149 glColor3f(1, 1, 1);
150 glTexCoord2f(0, 1); glVertex2f(-1, -1);
151 glTexCoord2f(1, 1); glVertex2f(1, -1);
152 glTexCoord2f(1, 0); glVertex2f(1, 1);
153 glTexCoord2f(0, 0); glVertex2f(-1, 1);
154 glEnd();
155 bind_program(0);
157 glActiveTexture(GL_TEXTURE2);
158 glDisable(GL_TEXTURE_1D);
159 glActiveTexture(GL_TEXTURE1);
160 glDisable(GL_TEXTURE_2D);
161 glActiveTexture(GL_TEXTURE0);
162 glDisable(GL_TEXTURE_3D);
164 glMatrixMode(GL_TEXTURE);
165 glPopMatrix();
166 glMatrixMode(GL_MODELVIEW);
167 glPopMatrix();
168 }
170 static void draw_slice(void)
171 {
172 glMatrixMode(GL_MODELVIEW);
173 glPushMatrix();
174 glTranslatef(0.9, 0.9, 0);
175 glScalef(0.3, 0.3 * ((float)win_xsz / win_ysz), 1);
176 glTranslatef(-1, -1, 0);
178 glActiveTexture(GL_TEXTURE0);
179 glBindTexture(GL_TEXTURE_3D, volume->get_texture());
180 glEnable(GL_TEXTURE_3D);
182 glActiveTexture(GL_TEXTURE1);
183 glBindTexture(GL_TEXTURE_1D, xfer_tex);
184 glEnable(GL_TEXTURE_1D);
186 bind_program(slice_sdr);
188 glBegin(GL_QUADS);
189 glColor3f(1, 1, 1);
190 glTexCoord3f(0, 1, cur_z); glVertex2f(-1, -1);
191 glTexCoord3f(1, 1, cur_z); glVertex2f(1, -1);
192 glTexCoord3f(1, 0, cur_z); glVertex2f(1, 1);
193 glTexCoord3f(0, 0, cur_z); glVertex2f(-1, 1);
194 glEnd();
196 bind_program(0);
198 glActiveTexture(GL_TEXTURE1);
199 glDisable(GL_TEXTURE_1D);
200 glActiveTexture(GL_TEXTURE0);
201 glDisable(GL_TEXTURE_3D);
202 glPopMatrix();
203 }
205 static void draw_xfer_func(void)
206 {
207 glMatrixMode(GL_MODELVIEW);
208 glPushMatrix();
209 glTranslatef(-0.9, -0.9, 0);
210 glScalef(0.5, 0.1, 1);
212 glBindTexture(GL_TEXTURE_1D, xfer_tex);
213 glEnable(GL_TEXTURE_1D);
215 glBegin(GL_QUADS);
216 glColor3f(1, 1, 1);
217 glTexCoord1f(1);
218 glVertex2f(1, 0);
219 glVertex2f(1, 1);
220 glTexCoord1f(0);
221 glVertex2f(0, 1);
222 glVertex2f(0, 0);
223 glEnd();
225 glDisable(GL_TEXTURE_1D);
227 glLineWidth(2.0);
228 glBegin(GL_LINE_LOOP);
229 /*if(uimode == UIMODE_XFER) {
230 glColor3f(1, 0, 0);
231 } else {*/
232 glColor3f(0, 0, 1);
233 //}
234 glVertex2f(0, 0);
235 glVertex2f(1, 0);
236 glVertex2f(1, 1);
237 glVertex2f(0, 1);
238 glEnd();
240 glPopMatrix();
241 }
243 void volray_resize(int x, int y)
244 {
245 glViewport(0, 0, x, y);
247 if(x != win_xsz || y != win_ysz) {
248 raytex_needs_recalc = true;
249 win_xsz = x;
250 win_ysz = y;
251 }
252 }
254 #if 0
255 void keyb(unsigned char key, int x, int y)
256 {
257 switch(key) {
258 case 27:
259 exit(0);
261 case 'x':
262 uimode = UIMODE_XFER;
263 post_redisplay();
264 break;
266 case 'c':
267 uimode = UIMODE_CURSOR;
268 post_redisplay();
269 break;
271 default:
272 break;
273 }
274 }
276 void keyb_up(unsigned char key, int x, int y)
277 {
278 switch(key) {
279 case 'x':
280 if(uimode == UIMODE_XFER) {
281 uimode = UIMODE_DEFAULT;
282 post_redisplay();
283 }
284 break;
286 case 'c':
287 if(uimode == UIMODE_CURSOR) {
288 uimode = UIMODE_DEFAULT;
289 post_redisplay();
290 }
291 break;
293 default:
294 break;
295 }
296 }
297 #endif
299 static int bnstate[32];
300 static int prev_x, prev_y;
302 void volray_mouse(int bn, int state, int x, int y)
303 {
304 bnstate[bn] = state;
305 prev_x = x;
306 prev_y = y;
307 }
309 void volray_motion(int x, int y)
310 {
311 int dx = x - prev_x;
312 int dy = y - prev_y;
313 prev_x = x;
314 prev_y = y;
316 /*switch(uimode) {
317 case UIMODE_XFER:
318 if(dx || dy) {
319 xfer_mean += dx / (float)win_xsz;
320 xfer_sdev += 0.5 * dy / (float)win_ysz;
322 xfer_mean = xfer_mean < 0.0 ? 0.0 : (xfer_mean > 1.0 ? 1.0 : xfer_mean);
323 xfer_sdev = xfer_sdev < 0.0 ? 0.0 : (xfer_sdev > 1.0 ? 1.0 : xfer_sdev);
325 xfertex_needs_recalc = true;
326 post_redisplay();
327 }
328 break;
330 case UIMODE_CURSOR:
331 cur_z += 0.5 * dy / (float)win_ysz;
333 if(cur_z < 0.0)
334 cur_z = 0.0;
335 if(cur_z > 1.0)
336 cur_z = 1.0;
338 set_uniform_float(vol_sdr, "zclip", cur_z);
339 post_redisplay();
340 break;
342 default:*/
343 /* view control */
344 if(bnstate[0]) {
345 cam_theta += dx * 0.5;
346 cam_phi += dy * 0.5;
348 if(cam_phi <= -90) cam_phi = -89;
349 if(cam_phi >= 90) cam_phi = 89;
350 post_redisplay();
351 }
353 if(bnstate[1]) {
354 cam_x += dx * 0.025;
355 cam_y += dy * 0.025;
356 post_redisplay();
357 }
359 if(bnstate[2]) {
360 cam_dist += dy * 0.025;
361 if(cam_dist < 0.0) cam_dist = 0.0;
362 post_redisplay();
363 }
364 //}
365 }
367 #if 0
368 int parse_args(int argc, char **argv)
369 {
370 int i;
371 char *endp;
373 for(i=1; i<argc; i++) {
374 if(argv[i][0] == '-' && argv[i][2] == 0) {
375 switch(argv[i][1]) {
376 case 'm':
377 xfer_mean = strtod(argv[++i], &endp);
378 if(endp == argv[i]) {
379 fprintf(stderr, "-m must be followed by the transfer function mean\n");
380 return -1;
381 }
382 break;
384 case 'd':
385 xfer_sdev = strtod(argv[++i], &endp);
386 if(endp == argv[i]) {
387 fprintf(stderr, "-d must be followed by the transfer function std.deviation\n");
388 return -1;
389 }
390 break;
392 default:
393 fprintf(stderr, "unrecognized option: %s\n", argv[i]);
394 return -1;
395 }
396 } else {
397 if(fname) {
398 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
399 return -1;
400 }
401 fname = argv[i];
402 }
403 }
405 if(!fname) {
406 fprintf(stderr, "pass the volume descriptor filename\n");
407 return -1;
408 }
409 return 0;
410 }
411 #endif
414 static void create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale)
415 {
416 int cur_tex_xsz, cur_tex_ysz;
417 int tex_xsz = round_pow2(xsz);
418 int tex_ysz = round_pow2(ysz);
419 float *teximg, *dir;
421 teximg = new float[3 * xsz * ysz];
422 dir = teximg;
424 for(int i=0; i<ysz; i++) {
425 for(int j=0; j<xsz; j++) {
426 Vector3 rdir = get_primary_ray_dir(j, i, xsz, ysz, vfov);
427 *dir++ = rdir.x;
428 *dir++ = rdir.y;
429 *dir++ = rdir.z;
430 }
431 }
433 if(!ray_tex) {
434 glGenTextures(1, &ray_tex);
435 }
437 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cur_tex_xsz);
438 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cur_tex_ysz);
440 if(tex_xsz > cur_tex_xsz || tex_ysz > cur_tex_ysz) {
441 glBindTexture(GL_TEXTURE_2D, ray_tex);
442 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
443 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
444 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
445 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
446 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, 0);
447 }
449 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, teximg);
450 delete [] teximg;
452 if(tex_scale) {
453 tex_scale->x = (float)xsz / (float)tex_xsz;
454 tex_scale->y = (float)ysz / (float)tex_ysz;
455 }
456 raytex_needs_recalc = false;
457 }
459 static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg)
460 {
461 float vfov = M_PI * vfov_deg / 180.0;
462 float aspect = (float)w / (float)h;
464 float ysz = 2.0;
465 float xsz = aspect * ysz;
467 float px = ((float)x / (float)w) * xsz - xsz / 2.0;
468 float py = 1.0 - ((float)y / (float)h) * ysz;
469 float pz = 1.0 / tan(0.5 * vfov);
471 float mag = sqrt(px * px + py * py + pz * pz);
472 return Vector3(px / mag, py / mag, pz / mag);
473 }
475 static int round_pow2(int x)
476 {
477 x--;
478 x = (x >> 1) | x;
479 x = (x >> 2) | x;
480 x = (x >> 4) | x;
481 x = (x >> 8) | x;
482 x = (x >> 16) | x;
483 return x + 1;
484 }
486 static void create_transfer_map(float mean, float sdev)
487 {
488 static float map[XFER_MAP_SZ];
490 if(!xfer_tex) {
491 glGenTextures(1, &xfer_tex);
492 glBindTexture(GL_TEXTURE_1D, xfer_tex);
493 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
494 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
495 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
496 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
497 glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE32F_ARB, XFER_MAP_SZ, 0, GL_LUMINANCE, GL_FLOAT, 0);
498 }
500 for(int i=0; i<XFER_MAP_SZ; i++) {
501 float x = (float)i / (float)(XFER_MAP_SZ - 1);
502 map[i] = gaussian(x, mean, sdev) - 1.0;
503 }
505 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, XFER_MAP_SZ, GL_LUMINANCE, GL_FLOAT, map);
506 xfertex_needs_recalc = false;
507 }