rev |
line source |
elene@6
|
1 #include <GL/glew.h>
|
elene@6
|
2
|
elene@6
|
3 #include <assert.h>
|
elene@6
|
4
|
elene@5
|
5 #include <ctype.h>
|
elene@5
|
6 #include <errno.h>
|
elene@4
|
7 #include <stdio.h>
|
elene@5
|
8 #include <string.h>
|
elene@5
|
9
|
elene@5
|
10 #include <string>
|
elene@5
|
11 #include <vector>
|
elene@4
|
12
|
elene@3
|
13 #include "volume.h"
|
elene@4
|
14
|
elene@5
|
15 static char *strip_whitespaces(char *buf);
|
elene@5
|
16
|
elene@4
|
17 Volume::Volume()
|
elene@4
|
18 {
|
elene@4
|
19 width = height = 0;
|
elene@5
|
20 zaspect = 1;
|
elene@6
|
21 vol_tex_valid = false;
|
elene@6
|
22
|
elene@6
|
23 glGenTextures(1, &vol_tex);
|
elene@4
|
24 }
|
elene@4
|
25
|
elene@6
|
26 Volume::~Volume()
|
elene@6
|
27 {
|
elene@6
|
28 glDeleteTextures(1, &vol_tex);
|
elene@6
|
29 }
|
elene@6
|
30
|
elene@6
|
31 void Volume::create_vol_tex() const
|
elene@6
|
32 {
|
elene@6
|
33 if(slices.empty())
|
elene@6
|
34 return;
|
elene@6
|
35
|
elene@6
|
36 glBindTexture(GL_TEXTURE_3D, vol_tex);
|
elene@6
|
37 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
elene@6
|
38 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
elene@6
|
39 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
elene@6
|
40 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
elene@6
|
41 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
elene@6
|
42
|
elene@6
|
43 assert(glGetError() == GL_NO_ERROR);
|
elene@6
|
44 glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, width, height,
|
elene@6
|
45 slices.size(), 0, GL_LUMINANCE, GL_FLOAT, 0);
|
elene@6
|
46 assert(glGetError() == GL_NO_ERROR);
|
elene@6
|
47
|
elene@6
|
48 for(size_t i=0; i<slices.size(); i++) {
|
elene@6
|
49 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, width, height,
|
elene@6
|
50 1, GL_LUMINANCE, GL_FLOAT, slices[i].get_pixels());
|
elene@6
|
51 }
|
elene@6
|
52 }
|
elene@6
|
53
|
elene@6
|
54 bool Volume::load(const char *fname)
|
elene@4
|
55 {
|
elene@5
|
56 FILE *fp = fopen(fname, "r");
|
elene@5
|
57 if(!fp) {
|
elene@5
|
58 fprintf(stderr, "Failed to open file: %s: %s\n", fname, strerror(errno));
|
elene@5
|
59 return false;
|
elene@5
|
60 }
|
elene@5
|
61
|
elene@5
|
62 char buf[512];
|
elene@5
|
63 if(!fgets(buf, sizeof buf, fp)) {
|
elene@5
|
64 fprintf(stderr, "Empty file: %s.\n", fname);
|
elene@5
|
65 return false;
|
elene@5
|
66 }
|
elene@5
|
67 if(strstr(buf, "VOLUME") != buf) {
|
elene@5
|
68 fprintf(stderr, "Invalid volume file format: %s\n", fname);
|
elene@5
|
69 return false;
|
elene@5
|
70 }
|
elene@5
|
71
|
elene@5
|
72 bool reading_slices = false;
|
elene@5
|
73 std::vector<std::string> img_fnames;
|
elene@5
|
74
|
elene@5
|
75 while(fgets(buf, sizeof buf, fp)) {
|
elene@5
|
76 char *line = strip_whitespaces(buf);
|
elene@5
|
77 if(!line || *line == 0 || *line == '#')
|
elene@5
|
78 continue;
|
elene@5
|
79
|
elene@5
|
80 if(reading_slices == false) {
|
elene@5
|
81 if(strcmp(line, "SLICES") == 0)
|
elene@5
|
82 reading_slices = true;
|
elene@5
|
83
|
elene@5
|
84 sscanf(line, "zaspect = %f", &zaspect);
|
elene@5
|
85 }
|
elene@5
|
86 else {
|
elene@5
|
87 img_fnames.push_back(line);
|
elene@5
|
88 }
|
elene@5
|
89 }
|
elene@5
|
90
|
elene@5
|
91 fclose(fp);
|
elene@5
|
92
|
elene@5
|
93 for(size_t i=0; i<img_fnames.size(); i++) {
|
elene@5
|
94 Image img;
|
elene@5
|
95 if(img.load(img_fnames[i].c_str())) {
|
elene@5
|
96 push_slice(std::move(img));
|
elene@5
|
97 }
|
elene@5
|
98 else {
|
elene@5
|
99 fprintf(stderr, "Failed to load slice: %s\n", img_fnames[i].c_str());
|
elene@5
|
100 }
|
elene@5
|
101 }
|
elene@5
|
102
|
elene@4
|
103 return true;
|
elene@4
|
104 }
|
elene@4
|
105
|
elene@4
|
106 bool Volume::push_slice(Image &&slice)
|
elene@4
|
107 {
|
elene@4
|
108 if(slices.empty()) {
|
elene@4
|
109 width = slice.get_width();
|
elene@4
|
110 height = slice.get_height();
|
elene@4
|
111 }
|
elene@4
|
112 else {
|
elene@4
|
113 if(width != slice.get_width() || height != slice.get_height()) {
|
elene@4
|
114 fprintf(stderr, "failed to load slice no: %d\n", (int)slices.size() + 1);
|
elene@4
|
115 return false;
|
elene@4
|
116 }
|
elene@4
|
117 }
|
elene@4
|
118
|
elene@4
|
119 slices.push_back(slice);
|
elene@4
|
120 return true;
|
elene@4
|
121 }
|
elene@5
|
122
|
elene@6
|
123 const Image *Volume::get_slice(int num_slice) const
|
elene@6
|
124 {
|
elene@6
|
125 if(num_slice >= (int)slices.size() || num_slice < 0)
|
elene@6
|
126 return 0;
|
elene@6
|
127
|
elene@6
|
128 return &slices[num_slice];
|
elene@6
|
129 }
|
elene@6
|
130
|
elene@6
|
131 const Image *Volume::get_slice_by_z(float z) const
|
elene@6
|
132 {
|
elene@6
|
133 int idx = get_slice_idx_by_z(z);
|
elene@6
|
134 return get_slice(idx);
|
elene@6
|
135 }
|
elene@6
|
136
|
elene@6
|
137 int Volume::get_slice_count() const
|
elene@6
|
138 {
|
elene@6
|
139 return (int)slices.size();
|
elene@6
|
140 }
|
elene@6
|
141
|
elene@6
|
142 int Volume::get_slice_idx_by_z(float z) const
|
elene@6
|
143 {
|
elene@6
|
144 int last_slice_idx = (int)slices.size() - 1;
|
elene@6
|
145 int idx = z * last_slice_idx;
|
elene@6
|
146 if(idx < 0) {
|
elene@6
|
147 idx = 0;
|
elene@6
|
148 }
|
elene@6
|
149 else if(idx > last_slice_idx) {
|
elene@6
|
150 idx = last_slice_idx;
|
elene@6
|
151 }
|
elene@6
|
152
|
elene@6
|
153 return idx;
|
elene@6
|
154 }
|
elene@6
|
155
|
elene@6
|
156 unsigned int Volume::get_texture() const
|
elene@6
|
157 {
|
elene@6
|
158 if(!vol_tex_valid) {
|
elene@6
|
159 create_vol_tex();
|
elene@6
|
160 vol_tex_valid = true;
|
elene@6
|
161 }
|
elene@6
|
162
|
elene@6
|
163 return vol_tex;
|
elene@6
|
164 }
|
elene@6
|
165
|
elene@5
|
166 void Volume::draw()
|
elene@5
|
167 {
|
elene@5
|
168 }
|
elene@5
|
169
|
elene@5
|
170 static char *strip_whitespaces(char *buf)
|
elene@5
|
171 {
|
elene@5
|
172 while(*buf && isspace(*buf))
|
elene@5
|
173 buf++;
|
elene@5
|
174
|
elene@5
|
175 if(!*buf)
|
elene@5
|
176 return 0;
|
elene@5
|
177
|
elene@5
|
178 char *end = buf + strlen(buf) - 1;
|
elene@5
|
179 while(end > buf && isspace(*end))
|
elene@5
|
180 end--;
|
elene@5
|
181 end[1] = 0;
|
elene@5
|
182 return buf;
|
elene@5
|
183 }
|