rev |
line source |
nuclear@8
|
1 #include <stdio.h>
|
nuclear@8
|
2 #include <stdlib.h>
|
nuclear@8
|
3 #include <string.h>
|
nuclear@8
|
4 #include <ctype.h>
|
nuclear@11
|
5 #include <list>
|
nuclear@11
|
6 #include <string>
|
nuclear@8
|
7
|
nuclear@8
|
8 #ifndef __APPLE__
|
nuclear@8
|
9 #include <GL/gl.h>
|
nuclear@8
|
10 #else
|
nuclear@8
|
11 #include <OpenGL/gl.h>
|
nuclear@8
|
12 #endif
|
nuclear@8
|
13
|
nuclear@8
|
14 #include <imago2.h>
|
nuclear@9
|
15 #include "volume.h"
|
nuclear@8
|
16
|
nuclear@9
|
17 static void calc_gradients(float *voxels, int xsz, int ysz, int zsz);
|
nuclear@8
|
18 static struct slice *read_voldesc(const char *fname, struct volume *vol);
|
nuclear@8
|
19 static char *trim(char *str);
|
nuclear@8
|
20
|
nuclear@11
|
21 Volume::Volume()
|
nuclear@8
|
22 {
|
nuclear@11
|
23 sz[0] = sz[1] = sz[2] = 0;
|
nuclear@11
|
24 zaspect = 1.0;
|
nuclear@11
|
25 tex = 0;
|
nuclear@11
|
26 }
|
nuclear@11
|
27
|
nuclear@11
|
28 Volume::~Volume()
|
nuclear@11
|
29 {
|
nuclear@11
|
30 if(tex) {
|
nuclear@11
|
31 glDeleteTextures(1, &tex);
|
nuclear@11
|
32 }
|
nuclear@11
|
33 }
|
nuclear@11
|
34
|
nuclear@11
|
35 bool Volume::load(const char *fname)
|
nuclear@11
|
36 {
|
nuclear@11
|
37 std::list<std::string> slist;
|
nuclear@9
|
38 float *voxels = 0, *vptr;
|
nuclear@9
|
39 struct img_pixmap img;
|
nuclear@8
|
40
|
nuclear@11
|
41 if(!(read_voldesc(fname, &slist))) {
|
nuclear@11
|
42 return false;
|
nuclear@8
|
43 }
|
nuclear@8
|
44
|
nuclear@9
|
45 /* load the first image to determine slice dimensions */
|
nuclear@9
|
46 img_init(&img);
|
nuclear@13
|
47 if(img_load(&img, slist.begin()->c_str()) == -1) {
|
nuclear@13
|
48 fprintf(stderr, "failed to load volume slice: %s\n", slist.begin()->c_str());
|
nuclear@11
|
49 return false;
|
nuclear@9
|
50 }
|
nuclear@9
|
51
|
nuclear@11
|
52 sz[0] = img.width;
|
nuclear@11
|
53 sz[1] = img.height;
|
nuclear@13
|
54 printf("volume dimensions: %dx%dx%d\n", img.width, img.height, sz[2]);
|
nuclear@9
|
55
|
nuclear@9
|
56 /* allocate the whole volume at once */
|
nuclear@11
|
57 voxels = new float[sz[0] * sz[1] * sz[2] * 4];
|
nuclear@9
|
58 vptr = voxels;
|
nuclear@9
|
59 img_destroy(&img);
|
nuclear@9
|
60
|
nuclear@9
|
61 /* put the volume data into the alpha component */
|
nuclear@11
|
62 for(auto slice : slist) {
|
nuclear@9
|
63 int x, y, xsz, ysz;
|
nuclear@9
|
64 float *pixels, *src;
|
nuclear@9
|
65
|
nuclear@13
|
66 if(!(pixels = (float*)img_load_pixels(slice.c_str(), &xsz, &ysz, IMG_FMT_GREYF))) {
|
nuclear@13
|
67 fprintf(stderr, "failed to load volume slice: %s\n", slice.c_str());
|
nuclear@11
|
68 delete [] voxels;
|
nuclear@11
|
69 return false;
|
nuclear@9
|
70 }
|
nuclear@9
|
71
|
nuclear@11
|
72 if(xsz != sz[0] || ysz != sz[1]) {
|
nuclear@9
|
73 fprintf(stderr, "inconsistent dimensions for slice %s: %dx%d (%dx%d expected)\n",
|
nuclear@13
|
74 slice.c_str(), xsz, ysz, sz[0], sz[1]);
|
nuclear@11
|
75 delete [] voxels;
|
nuclear@11
|
76 return false;
|
nuclear@9
|
77 }
|
nuclear@9
|
78
|
nuclear@9
|
79 src = pixels;
|
nuclear@9
|
80 for(y=0; y<ysz; y++) {
|
nuclear@9
|
81 for(x=0; x<xsz; x++) {
|
nuclear@9
|
82 vptr[0] = vptr[1] = vptr[2] = 0.0f;
|
nuclear@9
|
83 vptr[3] = *src++;
|
nuclear@9
|
84 vptr += 4;
|
nuclear@9
|
85 }
|
nuclear@9
|
86 }
|
nuclear@9
|
87 img_free_pixels(pixels);
|
nuclear@9
|
88 }
|
nuclear@9
|
89
|
nuclear@9
|
90 /* calculate gradients */
|
nuclear@11
|
91 calc_gradients(voxels, sz[0], sz[1], sz[2]);
|
nuclear@9
|
92
|
nuclear@9
|
93 /* create the volume texture */
|
nuclear@11
|
94 glGenTextures(1, &tex);
|
nuclear@11
|
95 glBindTexture(GL_TEXTURE_3D, tex);
|
nuclear@8
|
96 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@8
|
97 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@8
|
98 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
nuclear@8
|
99 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
nuclear@8
|
100 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
nuclear@11
|
101 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F_ARB, sz[0], sz[1], sz[2], 0, GL_RGBA, GL_FLOAT, voxels);
|
nuclear@8
|
102
|
nuclear@9
|
103 /* ... and destroy our copy */
|
nuclear@11
|
104 delete [] voxels;
|
nuclear@11
|
105 return true;
|
nuclear@9
|
106 }
|
nuclear@9
|
107
|
nuclear@11
|
108 unsigned int Volume::get_texture() const
|
nuclear@9
|
109 {
|
nuclear@11
|
110 return tex;
|
nuclear@11
|
111 }
|
nuclear@11
|
112
|
nuclear@11
|
113 void Volume::bind(int tex_unit) const
|
nuclear@11
|
114 {
|
nuclear@11
|
115 glActiveTexture(GL_TEXTURE0 + tex_unit);
|
nuclear@11
|
116 glBindTexture(GL_TEXTURE_3D, tex);
|
nuclear@9
|
117 }
|
nuclear@9
|
118
|
nuclear@9
|
119 struct vec4 { float x, y, z, w; };
|
nuclear@9
|
120
|
nuclear@9
|
121 static void calc_gradients(float *voxels, int xsz, int ysz, int zsz)
|
nuclear@9
|
122 {
|
nuclear@9
|
123 int x, y, z, slice_pixels = xsz * ysz;
|
nuclear@11
|
124 vec4 *vptr = (vec4*)voxels;
|
nuclear@9
|
125
|
nuclear@9
|
126 for(z=0; z<zsz; z++) {
|
nuclear@9
|
127 for(y=0; y<ysz; y++) {
|
nuclear@9
|
128 for(x=0; x<xsz; x++) {
|
nuclear@9
|
129 float x0, x1, y0, y1, z0, z1;
|
nuclear@9
|
130
|
nuclear@9
|
131 x0 = x > 0 ? (vptr - 1)->w : vptr->w;
|
nuclear@9
|
132 y0 = y > 0 ? (vptr - xsz)->w : vptr->w;
|
nuclear@9
|
133 z0 = z > 0 ? (vptr - slice_pixels)->w : vptr->w;
|
nuclear@9
|
134 x1 = x < xsz - 1 ? (vptr + 1)->w : vptr->w;
|
nuclear@9
|
135 y1 = y < ysz - 1 ? (vptr + xsz)->w : vptr->w;
|
nuclear@9
|
136 z1 = z < zsz - 1 ? (vptr + slice_pixels)->w : vptr->w;
|
nuclear@9
|
137
|
nuclear@9
|
138 vptr->x = x1 - x0;
|
nuclear@9
|
139 vptr->y = y1 - y0;
|
nuclear@9
|
140 vptr->z = z1 - z0;
|
nuclear@9
|
141
|
nuclear@9
|
142 vptr++;
|
nuclear@9
|
143 }
|
nuclear@9
|
144 }
|
nuclear@9
|
145 }
|
nuclear@8
|
146 }
|
nuclear@8
|
147
|
nuclear@13
|
148 bool Volume::read_voldesc(const char *fname, std::list<std::string> *slist)
|
nuclear@8
|
149 {
|
nuclear@8
|
150 FILE *fp = 0;
|
nuclear@9
|
151 char buf[512], *slash, *prefix = "";
|
nuclear@8
|
152 int mode_slices = 0;
|
nuclear@11
|
153
|
nuclear@11
|
154 slist->clear();
|
nuclear@8
|
155
|
nuclear@8
|
156 if(!(fp = fopen(fname, "r"))) {
|
nuclear@8
|
157 fprintf(stderr, "failed to open volume descriptor: %s\n", fname);
|
nuclear@11
|
158 return false;
|
nuclear@8
|
159 }
|
nuclear@8
|
160 fgets(buf, sizeof buf, fp);
|
nuclear@8
|
161 if(strstr(buf, "VOLDESC") != buf) {
|
nuclear@8
|
162 fprintf(stderr, "invalid file format while trying to read volume descriptor: %s\n", fname);
|
nuclear@11
|
163 fclose(fp);
|
nuclear@11
|
164 return false;
|
nuclear@8
|
165 }
|
nuclear@8
|
166
|
nuclear@13
|
167 if((slash = strrchr((char*)fname, '/'))) {
|
nuclear@9
|
168 int len = slash - fname + 1;
|
nuclear@13
|
169 prefix = (char*)alloca(len + 1);
|
nuclear@9
|
170 memcpy(prefix, fname, len);
|
nuclear@9
|
171 prefix[len] = 0;
|
nuclear@9
|
172 }
|
nuclear@9
|
173
|
nuclear@8
|
174 while(fgets(buf, sizeof buf, fp)) {
|
nuclear@8
|
175 char *line = trim(buf);
|
nuclear@8
|
176
|
nuclear@8
|
177 if(!*line || *line == '#')
|
nuclear@8
|
178 continue;
|
nuclear@8
|
179
|
nuclear@8
|
180 if(mode_slices) {
|
nuclear@8
|
181 /* we're in the part that contains filenames... append to the list */
|
nuclear@11
|
182 slist->push_back(std::string(prefix) + std::string(line));
|
nuclear@11
|
183 sz[2]++;
|
nuclear@8
|
184 } else {
|
nuclear@8
|
185 /* TODO we're in the options part... parse */
|
nuclear@9
|
186 if(strcmp(line, "SLICES") == 0) {
|
nuclear@9
|
187 mode_slices = 1;
|
nuclear@9
|
188 }
|
nuclear@8
|
189 }
|
nuclear@8
|
190 }
|
nuclear@8
|
191 fclose(fp);
|
nuclear@8
|
192
|
nuclear@11
|
193 if(slist->empty()) {
|
nuclear@8
|
194 fprintf(stderr, "file: %s contains no slices\n", fname);
|
nuclear@11
|
195 return false;
|
nuclear@8
|
196 }
|
nuclear@11
|
197 return true;
|
nuclear@8
|
198 }
|
nuclear@8
|
199
|
nuclear@8
|
200 static char *trim(char *str)
|
nuclear@8
|
201 {
|
nuclear@8
|
202 char *tmp = str + strlen(str) - 1;
|
nuclear@8
|
203
|
nuclear@8
|
204 while(isspace(*tmp))
|
nuclear@8
|
205 tmp--;
|
nuclear@8
|
206 tmp[1] = 0;
|
nuclear@8
|
207
|
nuclear@8
|
208 tmp = str;
|
nuclear@8
|
209 while(isspace(*tmp))
|
nuclear@8
|
210 tmp++;
|
nuclear@8
|
211 return tmp;
|
nuclear@8
|
212 }
|