nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #include nuclear@0: #ifndef __APPLE__ nuclear@0: #include nuclear@0: #else nuclear@0: #include nuclear@0: #endif nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@0: #include "sdr.h" nuclear@9: #include "volume.h" nuclear@13: #include "ui.h" nuclear@18: #include "demo.h" nuclear@0: nuclear@3: #define XFER_MAP_SZ 512 nuclear@3: nuclear@11: static void render_volume(); nuclear@11: static void draw_slice(); nuclear@11: static void draw_xfer_func(); nuclear@5: nuclear@11: /* nuclear@0: void keyb(unsigned char key, int x, int y); nuclear@4: void keyb_up(unsigned char key, int x, int y); nuclear@0: void mouse(int bn, int state, int x, int y); nuclear@0: void motion(int x, int y); nuclear@0: int parse_args(int argc, char **argv); nuclear@11: */ nuclear@0: nuclear@11: static void create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale); nuclear@11: static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg); nuclear@0: static int round_pow2(int x); nuclear@3: static void create_transfer_map(float mean, float sdev); nuclear@0: nuclear@9: static float cam_theta = 0, cam_phi = 0, cam_dist = 4.0; nuclear@9: static float cam_x, cam_y, cam_z; nuclear@0: nuclear@13: static Vector2 tex_scale; nuclear@9: static unsigned int vol_sdr, slice_sdr, ray_tex; nuclear@9: static int win_xsz, win_ysz; nuclear@11: static bool raytex_needs_recalc = true; nuclear@0: nuclear@9: static unsigned int xfer_tex; nuclear@9: static float xfer_mean = 0.7, xfer_sdev = 0.1; nuclear@11: static bool xfertex_needs_recalc = true; nuclear@3: nuclear@19: static float cur_z = 0.5; nuclear@23: static bool clip_z; nuclear@7: static float ray_step = 0.01; nuclear@4: nuclear@18: static Volume *volume; nuclear@9: nuclear@9: nuclear@11: bool volray_init() nuclear@0: { nuclear@0: glewInit(); nuclear@0: nuclear@9: if(!(vol_sdr = create_program_load("sdr/volray.v.glsl", "sdr/volray.p.glsl"))) { nuclear@11: return false; nuclear@0: } nuclear@5: set_uniform_int(vol_sdr, "volume", 0); nuclear@5: set_uniform_int(vol_sdr, "ray_tex", 1); nuclear@5: set_uniform_int(vol_sdr, "xfer_tex", 2); nuclear@7: set_uniform_float(vol_sdr, "ray_step", ray_step); nuclear@23: set_uniform_float(vol_sdr, "zclip", 0.0); nuclear@5: nuclear@9: if(!(slice_sdr = create_program_load(0, "sdr/slice.p.glsl"))) { nuclear@11: return false; nuclear@5: } nuclear@5: set_uniform_int(slice_sdr, "volume", 0); nuclear@5: set_uniform_int(slice_sdr, "xfer_tex", 1); nuclear@0: nuclear@18: init_demo(); nuclear@18: nuclear@11: return true; nuclear@0: } nuclear@0: nuclear@18: void volray_setvolume(Volume *vol) nuclear@13: { nuclear@13: volume = vol; nuclear@13: } nuclear@13: nuclear@18: Volume *volray_getvolume() nuclear@18: { nuclear@18: return volume; nuclear@18: } nuclear@18: nuclear@21: void volray_setvalue(int which, float val) nuclear@21: { nuclear@21: switch(which) { nuclear@21: case VOLRAY_ZCURSOR: nuclear@21: cur_z = val; nuclear@23: if(clip_z) { nuclear@23: set_uniform_float(vol_sdr, "zclip", cur_z); nuclear@23: } nuclear@21: post_redisplay(); nuclear@21: break; nuclear@21: nuclear@22: case VOLRAY_ZCLIP: nuclear@23: clip_z = val > 0.5; nuclear@23: set_uniform_float(vol_sdr, "zclip", clip_z ? cur_z : 0.0); nuclear@23: post_redisplay(); nuclear@23: break; nuclear@22: nuclear@21: default: nuclear@21: break; nuclear@21: } nuclear@21: } nuclear@21: nuclear@21: float volray_getvalue(int which) nuclear@21: { nuclear@21: switch(which) { nuclear@21: case VOLRAY_ZCURSOR: nuclear@21: return cur_z; nuclear@21: nuclear@23: case VOLRAY_ZCLIP: nuclear@23: return clip_z > 0.5 ? 1.0 : 0.0; nuclear@23: break; nuclear@23: nuclear@21: default: nuclear@21: break; nuclear@21: } nuclear@21: return 0.0; nuclear@21: } nuclear@21: nuclear@11: void volray_draw(void) nuclear@0: { nuclear@4: /* recalculate primary ray texture if needed */ nuclear@1: if(raytex_needs_recalc) { nuclear@1: create_ray_texture(win_xsz, win_ysz, 50.0, &tex_scale); nuclear@1: } nuclear@4: /* recalculate transfer function texture if needed */ nuclear@3: if(xfertex_needs_recalc) { nuclear@3: create_transfer_map(xfer_mean, xfer_sdev); nuclear@3: } nuclear@1: nuclear@18: draw_demo(); nuclear@18: nuclear@13: glClear(GL_COLOR_BUFFER_BIT); nuclear@13: nuclear@13: if(volume) { nuclear@13: render_volume(); nuclear@28: //draw_slice(); nuclear@13: draw_xfer_func(); nuclear@13: } nuclear@4: nuclear@4: assert(glGetError() == GL_NO_ERROR); nuclear@4: } nuclear@4: nuclear@11: static void render_volume(void) nuclear@4: { nuclear@4: /* set the camera transformation */ nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@4: glPushMatrix(); nuclear@0: glLoadIdentity(); nuclear@1: glRotatef(-90, 1, 0, 0); nuclear@0: glTranslatef(cam_x, cam_y, -cam_z); nuclear@0: glRotatef(cam_theta, 0, 1, 0); nuclear@0: glRotatef(cam_phi, 1, 0, 0); nuclear@0: glTranslatef(0, 0, -cam_dist); nuclear@0: nuclear@4: /* setup the texture matrix to map the useful part of the ray texture to [0,1] */ nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@4: glPushMatrix(); nuclear@1: glLoadIdentity(); nuclear@0: glScalef(tex_scale.x, tex_scale.y, 1.0); nuclear@0: nuclear@4: /* tex unit0: volume data 3D texture */ nuclear@0: glActiveTexture(GL_TEXTURE0); nuclear@13: glBindTexture(GL_TEXTURE_3D, volume->get_texture()); nuclear@0: glEnable(GL_TEXTURE_3D); nuclear@0: nuclear@4: /* tex unit1: primary rays in view space */ nuclear@0: glActiveTexture(GL_TEXTURE1); nuclear@1: glBindTexture(GL_TEXTURE_2D, ray_tex); nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: nuclear@4: /* tex unit2: transfer function (1d) */ nuclear@3: glActiveTexture(GL_TEXTURE2); nuclear@3: glBindTexture(GL_TEXTURE_1D, xfer_tex); nuclear@3: glEnable(GL_TEXTURE_1D); nuclear@3: nuclear@5: bind_program(vol_sdr); nuclear@0: glBegin(GL_QUADS); nuclear@0: glColor3f(1, 1, 1); nuclear@1: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@1: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@1: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@1: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@0: glEnd(); nuclear@0: bind_program(0); nuclear@0: nuclear@3: glActiveTexture(GL_TEXTURE2); nuclear@3: glDisable(GL_TEXTURE_1D); nuclear@1: glActiveTexture(GL_TEXTURE1); nuclear@0: glDisable(GL_TEXTURE_2D); nuclear@0: glActiveTexture(GL_TEXTURE0); nuclear@0: glDisable(GL_TEXTURE_3D); nuclear@0: nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@4: glPopMatrix(); nuclear@4: glMatrixMode(GL_MODELVIEW); nuclear@4: glPopMatrix(); nuclear@4: } nuclear@0: nuclear@28: void volray_draw_slice(void) nuclear@5: { nuclear@5: glActiveTexture(GL_TEXTURE0); nuclear@13: glBindTexture(GL_TEXTURE_3D, volume->get_texture()); nuclear@5: glEnable(GL_TEXTURE_3D); nuclear@5: nuclear@5: glActiveTexture(GL_TEXTURE1); nuclear@5: glBindTexture(GL_TEXTURE_1D, xfer_tex); nuclear@5: glEnable(GL_TEXTURE_1D); nuclear@5: nuclear@5: bind_program(slice_sdr); nuclear@5: nuclear@5: glBegin(GL_QUADS); nuclear@5: glColor3f(1, 1, 1); nuclear@5: glTexCoord3f(0, 1, cur_z); glVertex2f(-1, -1); nuclear@5: glTexCoord3f(1, 1, cur_z); glVertex2f(1, -1); nuclear@5: glTexCoord3f(1, 0, cur_z); glVertex2f(1, 1); nuclear@5: glTexCoord3f(0, 0, cur_z); glVertex2f(-1, 1); nuclear@5: glEnd(); nuclear@5: nuclear@5: bind_program(0); nuclear@5: nuclear@5: glActiveTexture(GL_TEXTURE1); nuclear@5: glDisable(GL_TEXTURE_1D); nuclear@5: glActiveTexture(GL_TEXTURE0); nuclear@5: glDisable(GL_TEXTURE_3D); nuclear@5: } nuclear@5: nuclear@11: static void draw_xfer_func(void) nuclear@4: { nuclear@4: glMatrixMode(GL_MODELVIEW); nuclear@4: glPushMatrix(); nuclear@4: glTranslatef(-0.9, -0.9, 0); nuclear@4: glScalef(0.5, 0.1, 1); nuclear@4: nuclear@4: glBindTexture(GL_TEXTURE_1D, xfer_tex); nuclear@4: glEnable(GL_TEXTURE_1D); nuclear@4: nuclear@4: glBegin(GL_QUADS); nuclear@4: glColor3f(1, 1, 1); nuclear@4: glTexCoord1f(1); nuclear@4: glVertex2f(1, 0); nuclear@4: glVertex2f(1, 1); nuclear@4: glTexCoord1f(0); nuclear@4: glVertex2f(0, 1); nuclear@4: glVertex2f(0, 0); nuclear@4: glEnd(); nuclear@4: nuclear@4: glDisable(GL_TEXTURE_1D); nuclear@4: nuclear@4: glLineWidth(2.0); nuclear@4: glBegin(GL_LINE_LOOP); nuclear@13: /*if(uimode == UIMODE_XFER) { nuclear@5: glColor3f(1, 0, 0); nuclear@13: } else {*/ nuclear@5: glColor3f(0, 0, 1); nuclear@13: //} nuclear@4: glVertex2f(0, 0); nuclear@4: glVertex2f(1, 0); nuclear@4: glVertex2f(1, 1); nuclear@4: glVertex2f(0, 1); nuclear@4: glEnd(); nuclear@4: nuclear@4: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@11: void volray_resize(int x, int y) nuclear@0: { nuclear@0: glViewport(0, 0, x, y); nuclear@0: nuclear@0: if(x != win_xsz || y != win_ysz) { nuclear@11: raytex_needs_recalc = true; nuclear@0: win_xsz = x; nuclear@0: win_ysz = y; nuclear@0: } nuclear@0: } nuclear@0: nuclear@11: #if 0 nuclear@0: void keyb(unsigned char key, int x, int y) nuclear@0: { nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@4: nuclear@4: case 'x': nuclear@5: uimode = UIMODE_XFER; nuclear@13: post_redisplay(); nuclear@4: break; nuclear@5: nuclear@5: case 'c': nuclear@5: uimode = UIMODE_CURSOR; nuclear@13: post_redisplay(); nuclear@5: break; nuclear@5: nuclear@5: default: nuclear@5: break; nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: void keyb_up(unsigned char key, int x, int y) nuclear@4: { nuclear@4: switch(key) { nuclear@4: case 'x': nuclear@5: if(uimode == UIMODE_XFER) { nuclear@5: uimode = UIMODE_DEFAULT; nuclear@13: post_redisplay(); nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: case 'c': nuclear@5: if(uimode == UIMODE_CURSOR) { nuclear@5: uimode = UIMODE_DEFAULT; nuclear@13: post_redisplay(); nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: default: nuclear@4: break; nuclear@0: } nuclear@0: } nuclear@13: #endif nuclear@0: nuclear@0: static int bnstate[32]; nuclear@0: static int prev_x, prev_y; nuclear@0: nuclear@13: void volray_mouse(int bn, int state, int x, int y) nuclear@0: { nuclear@13: bnstate[bn] = state; nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: } nuclear@0: nuclear@13: void volray_motion(int x, int y) nuclear@0: { nuclear@0: int dx = x - prev_x; nuclear@0: int dy = y - prev_y; nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: nuclear@13: /*switch(uimode) { nuclear@5: case UIMODE_XFER: nuclear@4: if(dx || dy) { nuclear@4: xfer_mean += dx / (float)win_xsz; nuclear@4: xfer_sdev += 0.5 * dy / (float)win_ysz; nuclear@0: nuclear@4: xfer_mean = xfer_mean < 0.0 ? 0.0 : (xfer_mean > 1.0 ? 1.0 : xfer_mean); nuclear@4: xfer_sdev = xfer_sdev < 0.0 ? 0.0 : (xfer_sdev > 1.0 ? 1.0 : xfer_sdev); nuclear@0: nuclear@11: xfertex_needs_recalc = true; nuclear@13: post_redisplay(); nuclear@4: } nuclear@5: break; nuclear@0: nuclear@5: case UIMODE_CURSOR: nuclear@5: cur_z += 0.5 * dy / (float)win_ysz; nuclear@5: nuclear@5: if(cur_z < 0.0) nuclear@5: cur_z = 0.0; nuclear@5: if(cur_z > 1.0) nuclear@5: cur_z = 1.0; nuclear@7: nuclear@7: set_uniform_float(vol_sdr, "zclip", cur_z); nuclear@13: post_redisplay(); nuclear@5: break; nuclear@5: nuclear@13: default:*/ nuclear@5: /* view control */ nuclear@4: if(bnstate[0]) { nuclear@4: cam_theta += dx * 0.5; nuclear@4: cam_phi += dy * 0.5; nuclear@0: nuclear@4: if(cam_phi <= -90) cam_phi = -89; nuclear@4: if(cam_phi >= 90) cam_phi = 89; nuclear@13: post_redisplay(); nuclear@4: } nuclear@4: nuclear@4: if(bnstate[1]) { nuclear@4: cam_x += dx * 0.025; nuclear@4: cam_y += dy * 0.025; nuclear@13: post_redisplay(); nuclear@4: } nuclear@4: nuclear@4: if(bnstate[2]) { nuclear@4: cam_dist += dy * 0.025; nuclear@4: if(cam_dist < 0.0) cam_dist = 0.0; nuclear@13: post_redisplay(); nuclear@4: } nuclear@13: //} nuclear@0: } nuclear@0: nuclear@13: #if 0 nuclear@0: int parse_args(int argc, char **argv) nuclear@0: { nuclear@0: int i; nuclear@3: char *endp; nuclear@0: nuclear@0: for(i=1; i cur_tex_xsz || tex_ysz > cur_tex_ysz) { nuclear@1: glBindTexture(GL_TEXTURE_2D, ray_tex); nuclear@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); nuclear@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nuclear@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); nuclear@1: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); nuclear@1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, 0); nuclear@1: } nuclear@1: nuclear@1: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, teximg); nuclear@11: delete [] teximg; nuclear@0: nuclear@0: if(tex_scale) { nuclear@0: tex_scale->x = (float)xsz / (float)tex_xsz; nuclear@0: tex_scale->y = (float)ysz / (float)tex_ysz; nuclear@0: } nuclear@11: raytex_needs_recalc = false; nuclear@0: } nuclear@0: nuclear@11: static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg) nuclear@0: { nuclear@0: float vfov = M_PI * vfov_deg / 180.0; nuclear@0: float aspect = (float)w / (float)h; nuclear@0: nuclear@0: float ysz = 2.0; nuclear@0: float xsz = aspect * ysz; nuclear@0: nuclear@0: float px = ((float)x / (float)w) * xsz - xsz / 2.0; nuclear@0: float py = 1.0 - ((float)y / (float)h) * ysz; nuclear@0: float pz = 1.0 / tan(0.5 * vfov); nuclear@0: nuclear@0: float mag = sqrt(px * px + py * py + pz * pz); nuclear@11: return Vector3(px / mag, py / mag, pz / mag); nuclear@0: } nuclear@0: nuclear@0: static int round_pow2(int x) nuclear@0: { nuclear@0: x--; nuclear@0: x = (x >> 1) | x; nuclear@0: x = (x >> 2) | x; nuclear@0: x = (x >> 4) | x; nuclear@0: x = (x >> 8) | x; nuclear@0: x = (x >> 16) | x; nuclear@0: return x + 1; nuclear@0: } nuclear@0: nuclear@3: static void create_transfer_map(float mean, float sdev) nuclear@3: { nuclear@3: static float map[XFER_MAP_SZ]; nuclear@3: nuclear@3: if(!xfer_tex) { nuclear@3: glGenTextures(1, &xfer_tex); nuclear@3: glBindTexture(GL_TEXTURE_1D, xfer_tex); nuclear@3: glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@3: glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@3: glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); nuclear@3: glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); nuclear@3: glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE32F_ARB, XFER_MAP_SZ, 0, GL_LUMINANCE, GL_FLOAT, 0); nuclear@3: } nuclear@3: nuclear@11: for(int i=0; i