volmetrics

view src/volume.cc @ 11:c5af275b6a60

fixed normals
author Eleni Maria Stea <elene.mst@gmail.com>
date Mon, 27 Jan 2014 01:22:02 +0200
parents 40febfed6cff
children 1272e3335608
line source
1 #include <GL/glew.h>
3 #include <assert.h>
5 #include <ctype.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <string.h>
10 #include <string>
11 #include <vector>
13 #include <metasurf.h>
15 #include "mesh.h"
16 #include "volume.h"
18 static char *strip_whitespaces(char *buf);
20 Volume::Volume()
21 {
22 width = height = 0;
23 zaspect = 1;
24 vol_tex_valid = false;
26 glGenTextures(1, &vol_tex);
27 }
29 Volume::~Volume()
30 {
31 glDeleteTextures(1, &vol_tex);
32 }
34 void Volume::create_vol_tex() const
35 {
36 if(slices.empty())
37 return;
39 glBindTexture(GL_TEXTURE_3D, vol_tex);
40 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
41 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
42 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
43 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
44 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
46 assert(glGetError() == GL_NO_ERROR);
47 glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, width, height,
48 slices.size(), 0, GL_LUMINANCE, GL_FLOAT, 0);
49 assert(glGetError() == GL_NO_ERROR);
51 for(size_t i=0; i<slices.size(); i++) {
52 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, width, height,
53 1, GL_LUMINANCE, GL_FLOAT, slices[i].get_pixels());
54 }
55 }
57 bool Volume::load(const char *fname)
58 {
59 FILE *fp = fopen(fname, "r");
60 if(!fp) {
61 fprintf(stderr, "Failed to open file: %s: %s\n", fname, strerror(errno));
62 return false;
63 }
65 char buf[512];
66 if(!fgets(buf, sizeof buf, fp)) {
67 fprintf(stderr, "Empty file: %s.\n", fname);
68 return false;
69 }
70 if(strstr(buf, "VOLUME") != buf) {
71 fprintf(stderr, "Invalid volume file format: %s\n", fname);
72 return false;
73 }
75 bool reading_slices = false;
76 std::vector<std::string> img_fnames;
78 while(fgets(buf, sizeof buf, fp)) {
79 char *line = strip_whitespaces(buf);
80 if(!line || *line == 0 || *line == '#')
81 continue;
83 if(reading_slices == false) {
84 if(strcmp(line, "SLICES") == 0)
85 reading_slices = true;
87 sscanf(line, "zaspect = %f", &zaspect);
88 }
89 else {
90 img_fnames.push_back(line);
91 }
92 }
94 fclose(fp);
96 for(size_t i=0; i<img_fnames.size(); i++) {
97 Image img;
98 if(img.load(img_fnames[i].c_str())) {
99 push_slice(std::move(img));
100 }
101 else {
102 fprintf(stderr, "Failed to load slice: %s\n", img_fnames[i].c_str());
103 }
104 }
106 return true;
107 }
109 bool Volume::push_slice(Image &&slice)
110 {
111 if(slices.empty()) {
112 width = slice.get_width();
113 height = slice.get_height();
114 }
115 else {
116 if(width != slice.get_width() || height != slice.get_height()) {
117 fprintf(stderr, "failed to load slice no: %d\n", (int)slices.size() + 1);
118 return false;
119 }
120 }
122 slices.push_back(slice);
123 return true;
124 }
126 const Image *Volume::get_slice(int num_slice) const
127 {
128 if(num_slice >= (int)slices.size() || num_slice < 0)
129 return 0;
131 return &slices[num_slice];
132 }
134 const Image *Volume::get_slice_by_z(float z) const
135 {
136 int idx = get_slice_idx_by_z(z);
137 return get_slice(idx);
138 }
140 int Volume::get_slice_count() const
141 {
142 return (int)slices.size();
143 }
145 int Volume::get_slice_idx_by_z(float z) const
146 {
147 int last_slice_idx = (int)slices.size() - 1;
148 int idx = z * last_slice_idx;
149 if(idx < 0) {
150 idx = 0;
151 }
152 else if(idx > last_slice_idx) {
153 idx = last_slice_idx;
154 }
156 return idx;
157 }
159 unsigned int Volume::get_texture() const
160 {
161 if(!vol_tex_valid) {
162 create_vol_tex();
163 vol_tex_valid = true;
164 }
166 return vol_tex;
167 }
169 static Mesh *cur_mesh;
170 static Volume *cur_vol;
172 static float cb_eval(float x, float y, float z)
173 {
174 const Image *img = cur_vol->get_slice_by_z((z + 1) / 2.0);
175 const float *pixels = img->get_pixels();
177 int px = (x + 1) / 2.0 * img->get_width();
178 int py = (y + 1) / 2.0 * img->get_height();
180 return pixels[px + img->get_width() * py];
181 }
183 static void cb_vertex(float x, float y, float z)
184 {
185 float dx = 1.0 / cur_vol->get_slice(0)->get_width();
186 float dy = 1.0 / cur_vol->get_slice(0)->get_height();
187 float dz = 1.0 / cur_vol->get_slice_count();
188 float dfdx = cb_eval(x - dx, y, z) - cb_eval(x + dx, y, z);
189 float dfdy = cb_eval(x, y - dy, z) - cb_eval(x, y + dy, z);
190 float dfdz = cb_eval(x, y, z - dz) - cb_eval(x, y, z + dz);
192 cur_mesh->add_normal(Vector3(dfdx, dfdy, dfdz));
193 cur_mesh->add_vertex(Vector3(x, y, z));
194 }
196 void Volume::create_mesh(Mesh *mesh, float threshold)
197 {
198 cur_mesh = mesh;
199 cur_vol = this;
201 metasurface *ms = msurf_create();
202 msurf_threshold(ms, threshold);
203 msurf_resolution(ms, width, height, slices.size());
204 msurf_vertex_func(ms, cb_vertex);
205 msurf_eval_func(ms, cb_eval);
206 msurf_polygonize(ms);
207 msurf_free(ms);
208 }
210 void Volume::draw() const
211 {
212 }
214 static char *strip_whitespaces(char *buf)
215 {
216 while(*buf && isspace(*buf))
217 buf++;
219 if(!*buf)
220 return 0;
222 char *end = buf + strlen(buf) - 1;
223 while(end > buf && isspace(*end))
224 end--;
225 end[1] = 0;
226 return buf;
227 }