rev |
line source |
nuclear@12
|
1 /*
|
nuclear@12
|
2 glviewvol is an OpenGL 3D volume data viewer
|
nuclear@12
|
3 Copyright (C) 2014 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@12
|
4
|
nuclear@12
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@12
|
6 it under the terms of the GNU General Public License as published by
|
nuclear@12
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@12
|
8 (at your option) any later version.
|
nuclear@12
|
9
|
nuclear@12
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@12
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@12
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@12
|
13 GNU General Public License for more details.
|
nuclear@12
|
14
|
nuclear@12
|
15 You should have received a copy of the GNU General Public License
|
nuclear@12
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@12
|
17 */
|
nuclear@3
|
18 #include <stdio.h>
|
nuclear@4
|
19 #include <stdlib.h>
|
nuclear@0
|
20 #include "opengl.h"
|
nuclear@11
|
21 #include "viewer.h"
|
nuclear@1
|
22 #include "rend_fast.h"
|
nuclear@3
|
23 #include "opt.h"
|
nuclear@3
|
24 #include "volume.h"
|
nuclear@4
|
25 #include "xfer_view.h"
|
nuclear@0
|
26
|
nuclear@1
|
27 static int win_width, win_height;
|
nuclear@8
|
28 static float cam_theta, cam_phi, cam_dist = 4;
|
nuclear@8
|
29 static float pre_rot = -90;
|
nuclear@4
|
30 static int splitter_y = -1;
|
nuclear@4
|
31
|
nuclear@4
|
32 #define SPLITTER_WIDTH 5
|
nuclear@0
|
33
|
nuclear@1
|
34 static Renderer *rend;
|
nuclear@3
|
35 static Volume *vol;
|
nuclear@6
|
36 static TransferFunc *xfer;
|
nuclear@1
|
37
|
nuclear@0
|
38 extern "C" {
|
nuclear@0
|
39
|
nuclear@0
|
40 int init()
|
nuclear@0
|
41 {
|
nuclear@3
|
42 if(!opt.fname) {
|
nuclear@3
|
43 fprintf(stderr, "you must specify the volume data filename\n");
|
nuclear@1
|
44 return -1;
|
nuclear@1
|
45 }
|
nuclear@1
|
46
|
nuclear@3
|
47 switch(opt.rend_type) {
|
nuclear@3
|
48 case REND_FAST:
|
nuclear@3
|
49 rend = new RendererFast;
|
nuclear@3
|
50 break;
|
nuclear@3
|
51 default:
|
nuclear@3
|
52 return -1;
|
nuclear@3
|
53 }
|
nuclear@3
|
54
|
nuclear@3
|
55 if(!rend->init()) {
|
nuclear@3
|
56 fprintf(stderr, "renderer initialization failed\n");
|
nuclear@3
|
57 return -1;
|
nuclear@3
|
58 }
|
nuclear@3
|
59
|
nuclear@3
|
60 VoxelVolume *voxvol = new VoxelVolume;
|
nuclear@3
|
61 if(!voxvol->load(opt.fname)) {
|
nuclear@3
|
62 fprintf(stderr, "failed to load volume data from: %s\n", opt.fname);
|
nuclear@3
|
63 return -1;
|
nuclear@3
|
64 }
|
nuclear@3
|
65 vol = voxvol;
|
nuclear@3
|
66 rend->set_volume(vol);
|
nuclear@3
|
67
|
nuclear@6
|
68 xfer = new TransferWindow;
|
nuclear@6
|
69 rend->set_transfer_function(xfer);
|
nuclear@6
|
70
|
nuclear@6
|
71 if(!xfview_init(xfer)) {
|
nuclear@4
|
72 return -1;
|
nuclear@4
|
73 }
|
nuclear@14
|
74 xfview_set_volume(vol);
|
nuclear@4
|
75
|
nuclear@1
|
76 return 0;
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 void cleanup()
|
nuclear@0
|
80 {
|
nuclear@4
|
81 xfview_destroy();
|
nuclear@4
|
82
|
nuclear@1
|
83 rend->destroy();
|
nuclear@1
|
84 delete rend;
|
nuclear@3
|
85 delete vol;
|
nuclear@6
|
86 delete xfer;
|
nuclear@0
|
87 }
|
nuclear@0
|
88
|
nuclear@0
|
89 void ev_display()
|
nuclear@0
|
90 {
|
nuclear@0
|
91 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@1
|
92
|
nuclear@4
|
93 // render the main view
|
nuclear@4
|
94 glViewport(0, win_height - splitter_y, win_width, splitter_y);
|
nuclear@4
|
95
|
nuclear@4
|
96 glMatrixMode(GL_PROJECTION);
|
nuclear@4
|
97 glLoadIdentity();
|
nuclear@4
|
98 gluPerspective(50.0, (float)win_width / (float)splitter_y, 0.1, 100.0);
|
nuclear@4
|
99
|
nuclear@4
|
100 glMatrixMode(GL_MODELVIEW);
|
nuclear@4
|
101 glLoadIdentity();
|
nuclear@4
|
102 glTranslatef(0, 0, -cam_dist);
|
nuclear@8
|
103 glRotatef(cam_phi + pre_rot, 1, 0, 0);
|
nuclear@4
|
104 glRotatef(cam_theta, 0, 1, 0);
|
nuclear@4
|
105
|
nuclear@1
|
106 rend->update(0);
|
nuclear@1
|
107 rend->render();
|
nuclear@4
|
108
|
nuclear@4
|
109 // draw the transfer function view
|
nuclear@4
|
110 glViewport(0, 0, win_width, win_height - splitter_y);
|
nuclear@4
|
111
|
nuclear@4
|
112 xfview_draw();
|
nuclear@4
|
113
|
nuclear@4
|
114 // draw the GUI
|
nuclear@4
|
115 glViewport(0, 0, win_width, win_height);
|
nuclear@4
|
116
|
nuclear@4
|
117 glMatrixMode(GL_PROJECTION);
|
nuclear@4
|
118 glLoadIdentity();
|
nuclear@4
|
119 glOrtho(0, win_width, win_height, 0, -1, 1);
|
nuclear@4
|
120
|
nuclear@4
|
121 glMatrixMode(GL_MODELVIEW);
|
nuclear@4
|
122 glLoadIdentity();
|
nuclear@4
|
123
|
nuclear@4
|
124 glBegin(GL_QUADS);
|
nuclear@4
|
125 glColor3f(1, 1, 1);
|
nuclear@4
|
126 glVertex2f(0, splitter_y + SPLITTER_WIDTH / 2);
|
nuclear@4
|
127 glVertex2f(win_width, splitter_y + SPLITTER_WIDTH / 2);
|
nuclear@4
|
128 glVertex2f(win_width, splitter_y - SPLITTER_WIDTH / 2);
|
nuclear@4
|
129 glVertex2f(0, splitter_y - SPLITTER_WIDTH / 2);
|
nuclear@4
|
130 glEnd();
|
nuclear@4
|
131
|
nuclear@4
|
132 swap_buffers();
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 void ev_reshape(int x, int y)
|
nuclear@0
|
136 {
|
nuclear@4
|
137 if(splitter_y < 0) { // not initialized yet
|
nuclear@4
|
138 splitter_y = (int)(y * 0.85);
|
nuclear@4
|
139 } else {
|
nuclear@4
|
140 // calculate where the splitter was relative to the window height
|
nuclear@4
|
141 // and based on that, it's new position
|
nuclear@4
|
142 float split = (float)splitter_y / (float)win_height;
|
nuclear@4
|
143 splitter_y = (int)(y * split);
|
nuclear@4
|
144 }
|
nuclear@4
|
145
|
nuclear@0
|
146 win_width = x;
|
nuclear@0
|
147 win_height = y;
|
nuclear@0
|
148
|
nuclear@1
|
149 glViewport(0, 0, x, y);
|
nuclear@4
|
150 if(rend) {
|
nuclear@4
|
151 rend->reshape(x, y);
|
nuclear@4
|
152 }
|
nuclear@0
|
153 }
|
nuclear@0
|
154
|
nuclear@10
|
155 static bool zscaling;
|
nuclear@10
|
156
|
nuclear@1
|
157 void ev_keyboard(int key, int press, int x, int y)
|
nuclear@1
|
158 {
|
nuclear@8
|
159 RendererFast *fr;
|
nuclear@8
|
160
|
nuclear@10
|
161 switch(key) {
|
nuclear@10
|
162 case 27:
|
nuclear@10
|
163 if(press) {
|
nuclear@1
|
164 quit();
|
nuclear@10
|
165 }
|
nuclear@10
|
166 break;
|
nuclear@8
|
167
|
nuclear@10
|
168 case 'z':
|
nuclear@10
|
169 case 'Z':
|
nuclear@10
|
170 zscaling = press;
|
nuclear@10
|
171 break;
|
nuclear@10
|
172
|
nuclear@10
|
173 case '=':
|
nuclear@10
|
174 if(press && (fr = dynamic_cast<RendererFast*>(rend))) {
|
nuclear@10
|
175 int n = fr->get_proxy_count();
|
nuclear@10
|
176 int add = n / 4;
|
nuclear@10
|
177 n += add < 1 ? 1 : add;
|
nuclear@10
|
178 printf("proxy count: %d\n", n);
|
nuclear@10
|
179 fr->set_proxy_count(n);
|
nuclear@8
|
180 redisplay();
|
nuclear@10
|
181 }
|
nuclear@10
|
182 break;
|
nuclear@8
|
183
|
nuclear@10
|
184 case '-':
|
nuclear@10
|
185 if(press && (fr = dynamic_cast<RendererFast*>(rend))) {
|
nuclear@10
|
186 int n = fr->get_proxy_count();
|
nuclear@10
|
187 int sub = n / 4;
|
nuclear@10
|
188 n -= sub < 1 ? 1 : sub;
|
nuclear@8
|
189
|
nuclear@10
|
190 if(n < 1) n = 1;
|
nuclear@8
|
191
|
nuclear@10
|
192 printf("proxy count: %d\n", n);
|
nuclear@10
|
193 fr->set_proxy_count(n);
|
nuclear@8
|
194 redisplay();
|
nuclear@10
|
195 }
|
nuclear@10
|
196 break;
|
nuclear@8
|
197
|
nuclear@10
|
198 default:
|
nuclear@10
|
199 break;
|
nuclear@1
|
200 }
|
nuclear@1
|
201 }
|
nuclear@1
|
202
|
nuclear@4
|
203 static bool bnstate[8];
|
nuclear@4
|
204 static int prev_x, prev_y;
|
nuclear@4
|
205
|
nuclear@4
|
206 #define ON_SPLITTER(y) (abs(y - splitter_y) <= SPLITTER_WIDTH / 2)
|
nuclear@4
|
207 static bool splitter_dragging;
|
nuclear@4
|
208
|
nuclear@1
|
209 void ev_mouse_button(int bn, int press, int x, int y)
|
nuclear@1
|
210 {
|
nuclear@4
|
211 bnstate[bn] = press != 0;
|
nuclear@4
|
212 prev_x = x;
|
nuclear@4
|
213 prev_y = y;
|
nuclear@4
|
214
|
nuclear@4
|
215 splitter_dragging = bn == 0 && press && ON_SPLITTER(y);
|
nuclear@4
|
216
|
nuclear@4
|
217 if(!splitter_dragging && y > splitter_y) {
|
nuclear@4
|
218 xfview_button(bn, press, x, y);
|
nuclear@4
|
219 }
|
nuclear@1
|
220 }
|
nuclear@1
|
221
|
nuclear@1
|
222 void ev_mouse_motion(int x, int y)
|
nuclear@1
|
223 {
|
nuclear@4
|
224 int dx = x - prev_x;
|
nuclear@4
|
225 int dy = y - prev_y;
|
nuclear@4
|
226 prev_x = x;
|
nuclear@4
|
227 prev_y = y;
|
nuclear@4
|
228
|
nuclear@4
|
229 if((dx | dy) == 0) return;
|
nuclear@4
|
230
|
nuclear@10
|
231 if(bnstate[0] && zscaling) {
|
nuclear@10
|
232 float s = rend->get_zscale() + (float)dy / (float)win_height;
|
nuclear@10
|
233 rend->set_zscale(s < 0.0 ? 0.0 : s);
|
nuclear@10
|
234 redisplay();
|
nuclear@10
|
235 return;
|
nuclear@10
|
236 }
|
nuclear@10
|
237
|
nuclear@4
|
238 if(splitter_dragging) {
|
nuclear@4
|
239 splitter_y += dy;
|
nuclear@4
|
240 redisplay();
|
nuclear@4
|
241 return;
|
nuclear@4
|
242 }
|
nuclear@4
|
243
|
nuclear@4
|
244 if(y > splitter_y) {
|
nuclear@4
|
245 xfview_motion(x, y);
|
nuclear@4
|
246 return;
|
nuclear@4
|
247 }
|
nuclear@4
|
248
|
nuclear@4
|
249 // main view motion handling
|
nuclear@4
|
250 if(bnstate[0]) {
|
nuclear@4
|
251 cam_theta += dx * 0.5;
|
nuclear@4
|
252 cam_phi += dy * 0.5;
|
nuclear@4
|
253
|
nuclear@4
|
254 if(cam_phi < -90) cam_phi = -90;
|
nuclear@4
|
255 if(cam_phi > 90) cam_phi = 90;
|
nuclear@4
|
256 redisplay();
|
nuclear@4
|
257 }
|
nuclear@4
|
258 if(bnstate[2]) {
|
nuclear@4
|
259 cam_dist += dy * 0.1;
|
nuclear@4
|
260
|
nuclear@4
|
261 if(cam_dist < 0.0) cam_dist = 0.0;
|
nuclear@4
|
262 redisplay();
|
nuclear@4
|
263 }
|
nuclear@1
|
264 }
|
nuclear@0
|
265
|
nuclear@0
|
266 } // extern "C"
|