# HG changeset patch # User Eleni Maria Stea # Date 1390770817 -7200 # Node ID 40febfed6cff77a88da9eac454f394640a446b92 # Parent 928954bfefd7092d2722051d14eba076b555cb95 rendering isosurfaces / added simple gui diff -r 928954bfefd7 -r 40febfed6cff Makefile --- a/Makefile Sat Jan 25 19:25:32 2014 +0200 +++ b/Makefile Sun Jan 26 23:13:37 2014 +0200 @@ -9,7 +9,7 @@ CXX = g++ CXXFLAGS = -std=c++11 -pedantic -Wall $(dbg) $(opt) $(inc) -LDFLAGS = -lGL -lGLU -lGLEW -lglut -limago -lm +LDFLAGS = -lGL -lGLU -lGLEW -lglut -limago -lm -lmetasurf -lglui $(bin): $(obj) $(CXX) -o $@ $(obj) $(LDFLAGS) diff -r 928954bfefd7 -r 40febfed6cff src/main.cc --- a/src/main.cc Sat Jan 25 19:25:32 2014 +0200 +++ b/src/main.cc Sun Jan 26 23:13:37 2014 +0200 @@ -1,27 +1,40 @@ #include #include +#include #include #include +#include + +#include "mesh.h" #include "volume.h" -//static void init(void); -static void display(void); -static void reshape(int x, int y); -static void keyboard(unsigned char key, int x, int y); -static void mouse(int button, int state, int x, int y); -static void motion(int x, int y); +bool init(void); +GLUI *create_ui(void); +void display(void); +void reshape(int x, int y); +void keyboard(unsigned char key, int x, int y); +void keyboard_up(unsigned char key, int x, int y); +void mouse(int button, int state, int x, int y); +void motion(int x, int y); static int win_xsz, win_ysz; +static float cam_phi, cam_theta, cam_dist = 6; +static std::vector key_state(256); ///////////////////////////// // debug TODO remove //////////////////////////// -static bool init(); static Volume *vol; -static float cur_z; +static Mesh *mesh; +static float cur_z, thres = 0.5; + +static int use_orig_vol_res = 1; +static int vol_res[3]; // volume sampling resolution x/y/z + +static GLUI *ui; int main(int argc, char **argv) { @@ -36,6 +49,7 @@ glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); + glutKeyboardUpFunc(keyboard_up); glutMouseFunc(mouse); glutMotionFunc(motion); @@ -51,9 +65,85 @@ return 0; } +bool init() +{ + vol = new Volume; + if(!vol->load("data/test1.vol")) { + fprintf(stderr, "Failed to load test1.vol"); + return false; + } + mesh = new Mesh; + cur_z = 0.5; + + vol_res[0] = vol->get_slice(0)->get_width(); + vol_res[1] = vol->get_slice(0)->get_height(); + vol_res[2] = vol->get_slice_count(); + + if(!(ui = create_ui())) { + return false; + } + + return true; +} + +static GLUI_Spinner *res_spin[3]; + +static void toggle_use_orig(int id) +{ + for(int i=0; i<3; i++) { + if(use_orig_vol_res) { + res_spin[i]->disable(); + } else { + res_spin[i]->enable(); + } + } +} + +static void thres_change(int id) +{ + static float prev_thres = thres; + + if(prev_thres != thres) { + prev_thres = thres; + mesh->clear(); + } +} + +GLUI *create_ui() +{ + GLUI *ui = GLUI_Master.create_glui("ui"); + assert(ui); + + ui->set_main_gfx_window(glutGetWindow()); + + GLUI_Spinner *thres_spin = ui->add_spinner("iso threshold", GLUI_SPINNER_FLOAT, &thres, 0, thres_change); + thres_spin->set_float_limits(0, 1); + + GLUI_Panel *res_panel = ui->add_panel("volume resolution"); + + ui->add_checkbox_to_panel(res_panel, "original resolution", &use_orig_vol_res, 0, toggle_use_orig); + + static const char *res_spin_name[] = {"x", "y", "z"}; + for(int i=0; i<3; i++) { + res_spin[i] = ui->add_spinner_to_panel(res_panel, res_spin_name[i], GLUI_SPINNER_INT, vol_res + i); + res_spin[i]->set_int_limits(8, 256); // TODO limits as arguments or config + res_spin[i]->disable(); + } + + return ui; +} + void display(void) { - //render + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -cam_dist); + glRotatef(cam_phi, 1, 0, 0); + glRotatef(cam_theta, 0, 1, 0); + +/* glBindTexture(GL_TEXTURE_3D, vol->get_texture()); glEnable(GL_TEXTURE_3D); glBegin(GL_QUADS); @@ -63,7 +153,17 @@ glTexCoord3f(1, 0, cur_z); glVertex3f(1, -1, 0); glEnd(); glDisable(GL_TEXTURE_3D); +*/ + if(mesh->is_empty()) { + printf("recalculating isosurface ... "); + fflush(stdout); + vol->create_mesh(mesh, thres); + printf("done.\n"); + } + mesh->draw(); + + //TODO: draw threshold glutSwapBuffers(); assert(glGetError() == GL_NO_ERROR); } @@ -71,8 +171,11 @@ void reshape(int x, int y) { glViewport(0, 0, x, y); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45, (float)x / (float)y, 0.5, 500); + if(x != win_xsz || y != win_ysz) { - //TODO raytex_needs_recalc = 1; win_xsz = x; win_ysz = y; } @@ -80,42 +183,91 @@ void keyboard(unsigned char key, int x, int y) { + key_state[(int)key] = true; + switch(key) { case 27: exit(0); + case 'w': + { + static bool wire; + + wire = !wire; + glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL); + } + break; default: break; } } +void keyboard_up(unsigned char key, int x, int y) +{ + key_state[(int) key] = false; +} + static int prev_x, prev_y; +static bool bn_state[32]; +static float prev_thres; + void mouse(int bn, int state, int x, int y) { prev_x = x; prev_y = y; + + bn_state[bn - GLUT_LEFT_BUTTON] = (state == GLUT_DOWN); + + if(state == GLUT_DOWN) { + prev_thres = thres; + } + else { + if(thres != prev_thres) { + mesh->clear(); + } + } } void motion(int x, int y) { int dx = x - prev_x; int dy = y - prev_y; + + if(!dx && !dy) + return; + prev_x = x; prev_y = y; - if(dx != 0) { - cur_z = (float)x / (float)win_xsz; + if(key_state[(int)'t']) { + thres = (float)x / (float)win_xsz; + printf("threshold: %f\n", thres); + + glutPostRedisplay(); + return; + } + + // camera + if(bn_state[0]) { + if(key_state[(int)'z']) { + //zoom the camera + + cam_dist += dy * 0.1; + + if(cam_dist < 0) + cam_dist = 0; + } + else { + //rotate the camera + + cam_phi += dy * 0.5; + cam_theta += dx * 0.5; + + if(cam_phi > 90) + cam_phi = 90; + if(cam_phi < -90) + cam_phi = -90; + } + glutPostRedisplay(); } } - -bool init() -{ - vol = new Volume; - if(!vol->load("data/test1.vol")) { - fprintf(stderr, "Failed to load test1.vol"); - return false; - } - cur_z = 0.5; - - return true; -} diff -r 928954bfefd7 -r 40febfed6cff src/mesh.cc --- a/src/mesh.cc Sat Jan 25 19:25:32 2014 +0200 +++ b/src/mesh.cc Sun Jan 26 23:13:37 2014 +0200 @@ -21,6 +21,11 @@ normals.clear(); } +bool Mesh::is_empty() const +{ + return vertices.empty(); +} + void Mesh::draw() const { size_t sz = vertices.size(); diff -r 928954bfefd7 -r 40febfed6cff src/mesh.h --- a/src/mesh.h Sat Jan 25 19:25:32 2014 +0200 +++ b/src/mesh.h Sun Jan 26 23:13:37 2014 +0200 @@ -16,6 +16,7 @@ void add_normal(const Vector3 &normal); void clear(); + bool is_empty() const; void draw() const; }; diff -r 928954bfefd7 -r 40febfed6cff src/volume.cc --- a/src/volume.cc Sat Jan 25 19:25:32 2014 +0200 +++ b/src/volume.cc Sun Jan 26 23:13:37 2014 +0200 @@ -10,6 +10,9 @@ #include #include +#include + +#include "mesh.h" #include "volume.h" static char *strip_whitespaces(char *buf); @@ -163,6 +166,38 @@ return vol_tex; } +static Mesh *cur_mesh; +static Volume *cur_vol; + +static float cb_eval(float x, float y, float z) +{ + const Image *img = cur_vol->get_slice_by_z((z + 1) / 2.0); + const float *pixels = img->get_pixels(); + + int px = (x + 1) / 2.0 * img->get_width(); + int py = (y + 1) / 2.0 * img->get_height(); + + return pixels[px + img->get_width() * py]; +} + +void Volume::create_mesh(Mesh *mesh, float threshold) +{ + cur_mesh = mesh; + cur_vol = this; + + metasurface *ms = msurf_create(); + msurf_threshold(ms, threshold); + msurf_resolution(ms, width, height, slices.size()); + msurf_vertex_func(ms, + [](float x, float y, float z){cur_mesh->add_vertex(Vector3(x, y, z));}); + msurf_normal_func(ms, + [](float x, float y, float z){cur_mesh->add_normal(Vector3(x, y, z));}); + + msurf_eval_func(ms, cb_eval); + msurf_polygonize(ms); + msurf_free(ms); +} + void Volume::draw() const { } diff -r 928954bfefd7 -r 40febfed6cff src/volume.h --- a/src/volume.h Sat Jan 25 19:25:32 2014 +0200 +++ b/src/volume.h Sun Jan 26 23:13:37 2014 +0200 @@ -4,6 +4,8 @@ #include #include "image.h" +class Mesh; + class Volume { private: std::vector slices; @@ -25,13 +27,19 @@ bool push_slice(Image &&slice); const Image *get_slice(int num_slice) const; + + // z must be in [0, 1] const Image *get_slice_by_z(float z) const; + int get_slice_count() const; + // z must be in [0, 1] int get_slice_idx_by_z(float z) const; unsigned int get_texture() const; + void create_mesh(Mesh *mesh, float threshold); + void draw() const; };