glviewvol
changeset 7:71b479ffb9f7
curve manipulation works
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 30 Dec 2014 17:28:38 +0200 |
parents | f22be47a3572 |
children | fb6d93471352 |
files | Makefile src/curve.cc src/dicomview.h src/main.cc src/rend_fast.cc src/xfer_view.cc src/xfermap.cc src/xfermap.h |
diffstat | 8 files changed, 252 insertions(+), 38 deletions(-) [+] |
line diff
1.1 --- a/Makefile Tue Dec 30 06:22:54 2014 +0200 1.2 +++ b/Makefile Tue Dec 30 17:28:38 2014 +0200 1.3 @@ -5,7 +5,7 @@ 1.4 1.5 bin = dicomview 1.6 1.7 -opt = -O3 -ffast-math 1.8 +#opt = -O3 -ffast-math 1.9 dbg = -g 1.10 def = -DUSE_GLUT 1.11 #inc =
2.1 --- a/src/curve.cc Tue Dec 30 06:22:54 2014 +0200 2.2 +++ b/src/curve.cc Tue Dec 30 17:28:38 2014 +0200 2.3 @@ -43,7 +43,7 @@ 2.4 2.5 CurvePoint *Curve::get_point(int idx) 2.6 { 2.7 - if(idx < 0 || idx >= cp.size()) { 2.8 + if(idx < 0 || idx >= (int)cp.size()) { 2.9 return 0; 2.10 } 2.11 return &cp[idx]; 2.12 @@ -51,7 +51,7 @@ 2.13 2.14 const CurvePoint *Curve::get_point(int idx) const 2.15 { 2.16 - if(idx < 0 || idx >= cp.size()) { 2.17 + if(idx < 0 || idx >= (int)cp.size()) { 2.18 return 0; 2.19 } 2.20 return &cp[idx];
3.1 --- a/src/dicomview.h Tue Dec 30 06:22:54 2014 +0200 3.2 +++ b/src/dicomview.h Tue Dec 30 17:28:38 2014 +0200 3.3 @@ -19,6 +19,7 @@ 3.4 void redisplay(); 3.5 void quit(); 3.6 void get_window_size(int *xsz, int *ysz); 3.7 +unsigned int get_modifiers(); 3.8 3.9 #ifdef __cplusplus 3.10 }
4.1 --- a/src/main.cc Tue Dec 30 06:22:54 2014 +0200 4.2 +++ b/src/main.cc Tue Dec 30 17:28:38 2014 +0200 4.3 @@ -21,6 +21,7 @@ 4.4 static void motion(int x, int y); 4.5 4.6 static int win_width, win_height; 4.7 +static unsigned int mod; 4.8 4.9 int main(int argc, char **argv) 4.10 { 4.11 @@ -40,6 +41,7 @@ 4.12 glutKeyboardUpFunc(key_up); 4.13 glutMouseFunc(mouse); 4.14 glutMotionFunc(motion); 4.15 + glutPassiveMotionFunc(motion); 4.16 4.17 glewInit(); 4.18 4.19 @@ -73,6 +75,11 @@ 4.20 *ysz = win_height; 4.21 } 4.22 4.23 +unsigned int get_modifiers() 4.24 +{ 4.25 + return mod; 4.26 +} 4.27 + 4.28 static void display() 4.29 { 4.30 ev_display(); 4.31 @@ -87,16 +94,19 @@ 4.32 4.33 static void key_down(unsigned char key, int x, int y) 4.34 { 4.35 + mod = glutGetModifiers(); 4.36 ev_keyboard(key, 1, x, y); 4.37 } 4.38 4.39 static void key_up(unsigned char key, int x, int y) 4.40 { 4.41 + mod = glutGetModifiers(); 4.42 ev_keyboard(key, 0, x, y); 4.43 } 4.44 4.45 static void mouse(int bn, int state, int x, int y) 4.46 { 4.47 + mod = glutGetModifiers(); 4.48 ev_mouse_button(bn - GLUT_LEFT_BUTTON, state == GLUT_DOWN ? 1 : 0, x, y); 4.49 } 4.50
5.1 --- a/src/rend_fast.cc Tue Dec 30 06:22:54 2014 +0200 5.2 +++ b/src/rend_fast.cc Tue Dec 30 17:28:38 2014 +0200 5.3 @@ -3,8 +3,6 @@ 5.4 #include "rend_fast.h" 5.5 #include "sdr.h" 5.6 5.7 -static inline float smoothstep(float a, float b, float x); 5.8 - 5.9 #define XFER_MAP_SZ 1024 5.10 5.11 static unsigned int sdr; 5.12 @@ -117,6 +115,7 @@ 5.13 5.14 if(xfer) { 5.15 xfer->map(x, pptr); 5.16 + pptr[3] = std::max(pptr[0], std::max(pptr[1], pptr[2])); 5.17 } else { 5.18 pptr[0] = pptr[1] = pptr[2] = pptr[3] = x; 5.19 } 5.20 @@ -168,12 +167,3 @@ 5.21 glMatrixMode(GL_MODELVIEW); 5.22 glPopMatrix(); 5.23 } 5.24 - 5.25 -static inline float smoothstep(float a, float b, float x) 5.26 -{ 5.27 - if(x < a) return 0.0; 5.28 - if(x >= b) return 1.0; 5.29 - 5.30 - x = (x - a) / (b - a); 5.31 - return x * x * (3.0 - 2.0 * x); 5.32 -}
6.1 --- a/src/xfer_view.cc Tue Dec 30 06:22:54 2014 +0200 6.2 +++ b/src/xfer_view.cc Tue Dec 30 17:28:38 2014 +0200 6.3 @@ -1,11 +1,14 @@ 6.4 #include <stdio.h> 6.5 +#include <math.h> 6.6 #include "opengl.h" 6.7 #include "xfer_view.h" 6.8 #include "dicomview.h" 6.9 6.10 static TransferFunc *xfer; 6.11 6.12 -static int act_color = 3; 6.13 +static int act_color = -1; 6.14 +static int grabbed_handle = -1; 6.15 +static int mousex, mousey; 6.16 6.17 bool xfview_init(TransferFunc *xferarg) 6.18 { 6.19 @@ -25,6 +28,8 @@ 6.20 6.21 glMatrixMode(GL_PROJECTION); 6.22 glLoadIdentity(); 6.23 + glOrtho(0, 1, 0, 1, -1, 1); 6.24 + 6.25 glMatrixMode(GL_MODELVIEW); 6.26 glLoadIdentity(); 6.27 6.28 @@ -34,7 +39,8 @@ 6.29 6.30 // paint the background a faint version of the selected color 6.31 glBegin(GL_QUADS); 6.32 - glColor3f(line_color[act_color][0] * 0.1, line_color[act_color][1] * 0.1, line_color[act_color][2] * 0.1); 6.33 + int cidx = act_color == -1 ? 3 : act_color; 6.34 + glColor3f(line_color[cidx][0] * 0.1, line_color[cidx][1] * 0.1, line_color[cidx][2] * 0.1); 6.35 glVertex2f(-1, -1); 6.36 glVertex2f(1, -1); 6.37 glVertex2f(1, 1); 6.38 @@ -46,15 +52,105 @@ 6.39 glEnable(GL_BLEND); 6.40 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 6.41 6.42 + // draw handles on the selected curve 6.43 + TransferWindow *xfwin = dynamic_cast<TransferWindow*>(xfer); 6.44 + if(xfwin) { 6.45 + float dx = 1.0 / (float)xsz; 6.46 + float cursor = (float)mousex / (float)xsz; 6.47 + float low[3], high[3]; 6.48 + xfwin->get_interval_rgba(low, high); 6.49 + 6.50 + if(act_color == -1) { // all curves 6.51 + int nearest = xfwin->nearest_handle(-1, cursor); 6.52 + 6.53 + if(grabbed_handle != -1) { 6.54 + glBegin(GL_LINES); 6.55 + glColor3f(0.8, 0.8, 0.8); 6.56 + for(int i=0; i<3; i++) { 6.57 + float x = xfwin->get_handle(i, nearest); 6.58 + float rad = xfwin->get_soft_radius(); 6.59 + glVertex2f(x - rad, 0.5); 6.60 + glVertex2f(x + rad, 0.5); 6.61 + glVertex2f(x - rad, 0.4); 6.62 + glVertex2f(x - rad, 0.6); 6.63 + glVertex2f(x + rad, 0.4); 6.64 + glVertex2f(x + rad, 0.6); 6.65 + } 6.66 + glEnd(); 6.67 + } 6.68 + 6.69 + // draw handles on all lines, highlighting the nearest side of all of them 6.70 + glBegin(GL_QUADS); 6.71 + glColor3f(1, 1, 1); 6.72 + 6.73 + for(int i=0; i<3; i++) { 6.74 + float x = nearest == TransferWindow::HANDLE_LOW ? low[i] : high[i]; 6.75 + glVertex2f(x - 2.0 * dx, -1); 6.76 + glVertex2f(x + 2.0 * dx, -1); 6.77 + glVertex2f(x + 2.0 * dx, 1); 6.78 + glVertex2f(x - 2.0 * dx, 1); 6.79 + } 6.80 + for(int i=0; i<3; i++) { 6.81 + glColor3fv(line_color[i]); 6.82 + glVertex2f(low[i] - dx, -1); 6.83 + glVertex2f(low[i] + dx, -1); 6.84 + glVertex2f(low[i] + dx, 1); 6.85 + glVertex2f(low[i] - dx, 1); 6.86 + glVertex2f(high[i] - dx, -1); 6.87 + glVertex2f(high[i] + dx, -1); 6.88 + glVertex2f(high[i] + dx, 1); 6.89 + glVertex2f(high[i] - dx, 1); 6.90 + } 6.91 + glEnd(); 6.92 + 6.93 + } else { 6.94 + int nearest = xfwin->nearest_handle(act_color, cursor); 6.95 + float x = nearest == TransferWindow::HANDLE_LOW ? low[act_color] : high[act_color]; 6.96 + 6.97 + if(grabbed_handle != -1) { 6.98 + float x = xfwin->get_handle(act_color, nearest); 6.99 + float rad = xfwin->get_soft_radius(); 6.100 + 6.101 + glBegin(GL_LINES); 6.102 + glColor3f(0.8, 0.8, 0.8); 6.103 + glVertex2f(x - rad, 0.5); 6.104 + glVertex2f(x + rad, 0.5); 6.105 + glVertex2f(x - rad, 0.4); 6.106 + glVertex2f(x - rad, 0.6); 6.107 + glVertex2f(x + rad, 0.4); 6.108 + glVertex2f(x + rad, 0.6); 6.109 + glEnd(); 6.110 + } 6.111 + 6.112 + 6.113 + glBegin(GL_QUADS); 6.114 + glColor3f(1, 1, 1); 6.115 + glVertex2f(x - 2.0 * dx, -1); 6.116 + glVertex2f(x + 2.0 * dx, -1); 6.117 + glVertex2f(x + 2.0 * dx, 1); 6.118 + glVertex2f(x - 2.0 * dx, 1); 6.119 + 6.120 + glColor3fv(line_color[act_color]); 6.121 + for(int i=0; i<2; i++) { 6.122 + glVertex2f(x - dx, -1); 6.123 + glVertex2f(x + dx, -1); 6.124 + glVertex2f(x + dx, 1); 6.125 + glVertex2f(x - dx, 1); 6.126 + x = nearest == TransferWindow::HANDLE_LOW ? high[act_color] : low[act_color]; 6.127 + } 6.128 + glEnd(); 6.129 + } 6.130 + } 6.131 + 6.132 // draw curve 6.133 glLineWidth(2.0); 6.134 6.135 - for(int i=0; i<3; i++) { 6.136 + for(int i=0; i<4; i++) { 6.137 int idx; 6.138 - if(act_color < 3) { 6.139 - idx = (i + act_color + 1) % 3; 6.140 + if(act_color == -1) { 6.141 + idx = i; 6.142 } else { 6.143 - idx = i; 6.144 + idx = (i + act_color + 1) % 4; 6.145 } 6.146 6.147 glColor3fv(line_color[idx]); 6.148 @@ -63,9 +159,14 @@ 6.149 for(int j=0; j<nsamples; j++) { 6.150 float t = (float)j / (float)(nsamples - 1); 6.151 float vval[4]; 6.152 - xfer->map(t, vval); 6.153 6.154 - glVertex2f(t * 2.0 - 1.0, vval[i] * 2.0 - 1.0); 6.155 + if(idx < 3) { 6.156 + xfer->map(t, vval); 6.157 + } else { 6.158 + vval[3] = xfer->map(t); 6.159 + } 6.160 + 6.161 + glVertex2f(t, vval[idx]); 6.162 } 6.163 glEnd(); 6.164 } 6.165 @@ -73,21 +174,64 @@ 6.166 glDisable(GL_BLEND); 6.167 } 6.168 6.169 +static int prev_x, prev_y; 6.170 + 6.171 void xfview_button(int bn, int press, int x, int y) 6.172 { 6.173 - if(bn == 2 && press) { 6.174 - act_color = (act_color + 1) % 4; 6.175 + prev_x = x; 6.176 + prev_y = y; 6.177 + 6.178 + if(bn == 2 && press && grabbed_handle == -1) { 6.179 + act_color = (act_color + 2) % 4 - 1; 6.180 redisplay(); 6.181 return; 6.182 } 6.183 6.184 - if(bn == 1) { 6.185 - if(press) { 6.186 + if(bn == 0) { 6.187 + int xsz, ysz; 6.188 + get_window_size(&xsz, &ysz); 6.189 + 6.190 + TransferWindow *xfwin = dynamic_cast<TransferWindow*>(xfer); 6.191 + if(xfwin && press) { 6.192 + float cursor = (float)x / (float)xsz; 6.193 + float low[3], high[3]; 6.194 + xfwin->get_interval_rgba(low, high); 6.195 + 6.196 + // grab the nearest handle 6.197 + grabbed_handle = xfwin->nearest_handle(act_color, cursor); 6.198 } else { 6.199 + grabbed_handle = -1; 6.200 } 6.201 + redisplay(); 6.202 } 6.203 } 6.204 6.205 void xfview_motion(int x, int y) 6.206 { 6.207 + mousex = x; 6.208 + mousey = y; 6.209 + 6.210 + int dx = x - prev_x; 6.211 + int dy = y - prev_y; 6.212 + prev_x = x; 6.213 + prev_y = y; 6.214 + 6.215 + if(grabbed_handle != -1) { 6.216 + TransferWindow *xfwin = dynamic_cast<TransferWindow*>(xfer); 6.217 + if(!xfwin) return; 6.218 + 6.219 + int xsz, ysz; 6.220 + get_window_size(&xsz, &ysz); 6.221 + 6.222 + if(get_modifiers()) { 6.223 + float soft = xfwin->get_soft_radius() + dy * 0.01; 6.224 + if(soft < 0.0) soft = 0.0; 6.225 + xfwin->set_soft_radius(soft); 6.226 + } else { 6.227 + float pos = (float)x / (float)xsz; 6.228 + xfwin->set_handle(act_color, grabbed_handle, pos); 6.229 + } 6.230 + } 6.231 + 6.232 + redisplay(); 6.233 }
7.1 --- a/src/xfermap.cc Tue Dec 30 06:22:54 2014 +0200 7.2 +++ b/src/xfermap.cc Tue Dec 30 17:28:38 2014 +0200 7.3 @@ -1,3 +1,4 @@ 7.4 +#include <math.h> 7.5 #include <algorithm> 7.6 #include "xfermap.h" 7.7 7.8 @@ -11,18 +12,55 @@ 7.9 TransferWindow::TransferWindow() 7.10 { 7.11 soft_rad = 0.5; 7.12 - for(int i=0; i<4; i++) { 7.13 + for(int i=0; i<3; i++) { 7.14 low[i] = 0.5; 7.15 - high[i] = 2.0; 7.16 + high[i] = 1.5; 7.17 } 7.18 } 7.19 7.20 +void TransferWindow::set_handle(int channel, int handle, float val) 7.21 +{ 7.22 + float *dest = handle == HANDLE_LOW ? low : high; 7.23 + 7.24 + if(channel == -1) { 7.25 + dest[0] = dest[1] = dest[2] = val; 7.26 + } else { 7.27 + dest[channel] = val; 7.28 + } 7.29 +} 7.30 + 7.31 +float TransferWindow::get_handle(int channel, int handle) const 7.32 +{ 7.33 + const float *src = handle == HANDLE_LOW ? low : high; 7.34 + 7.35 + if(channel == -1) { 7.36 + return src[0]; // XXX this doens't make much sense 7.37 + } 7.38 + return src[channel]; 7.39 +} 7.40 + 7.41 +int TransferWindow::nearest_handle(int channel, float pos) const 7.42 +{ 7.43 + float ldist = 0, hdist = 0; 7.44 + 7.45 + if(channel == -1) { 7.46 + for(int i=0; i<3; i++) { 7.47 + ldist += fabs(low[i] - pos); 7.48 + hdist += fabs(high[i] - pos); 7.49 + } 7.50 + } else { 7.51 + ldist = fabs(low[channel] - pos); 7.52 + hdist = fabs(high[channel] - pos); 7.53 + } 7.54 + return ldist <= hdist ? HANDLE_LOW : HANDLE_HIGH; 7.55 +} 7.56 + 7.57 void TransferWindow::set_interval(float a, float b) 7.58 { 7.59 float v0 = std::min(a, b); 7.60 float v1 = std::max(a, b); 7.61 7.62 - for(int i=0; i<4; i++) { 7.63 + for(int i=0; i<3; i++) { 7.64 low[i] = v0; 7.65 high[i] = v1; 7.66 } 7.67 @@ -30,7 +68,7 @@ 7.68 7.69 void TransferWindow::set_interval(float *rgba_low, float *rgba_high) 7.70 { 7.71 - for(int i=0; i<4; i++) { 7.72 + for(int i=0; i<3; i++) { 7.73 low[i] = std::min(rgba_low[i], rgba_high[i]); 7.74 high[i] = std::max(rgba_low[i], rgba_high[i]); 7.75 } 7.76 @@ -42,6 +80,26 @@ 7.77 high[channel] = std::max(a, b); 7.78 } 7.79 7.80 +void TransferWindow::get_interval(float *aptr, float *bptr) const 7.81 +{ 7.82 + *aptr = low[0]; 7.83 + *bptr = high[0]; 7.84 +} 7.85 + 7.86 +void TransferWindow::get_interval_rgba(float *rgba_low, float *rgba_high) const 7.87 +{ 7.88 + for(int i=0; i<3; i++) { 7.89 + rgba_low[i] = low[i]; 7.90 + rgba_high[i] = high[i]; 7.91 + } 7.92 +} 7.93 + 7.94 +void TransferWindow::get_interval_rgba(int channel, float *aptr, float *bptr) const 7.95 +{ 7.96 + *aptr = low[channel]; 7.97 + *bptr = high[channel]; 7.98 +} 7.99 + 7.100 void TransferWindow::set_soft_radius(float s) 7.101 { 7.102 soft_rad = s; 7.103 @@ -63,15 +121,17 @@ 7.104 7.105 float TransferWindow::map(float x) const 7.106 { 7.107 - return smoothstep(low[3] - soft_rad, high[3] - soft_rad, x) * 7.108 - (1.0 - smoothstep(low[3] + soft_rad, high[3] + soft_rad, x)); 7.109 + float rgb[3]; 7.110 + map(x, rgb); 7.111 + 7.112 + return std::max(rgb[0], std::max(rgb[1], rgb[2])); 7.113 } 7.114 7.115 -void TransferWindow::map(float x, float *rgba_value) const 7.116 +void TransferWindow::map(float x, float *rgb_value) const 7.117 { 7.118 - for(int i=0; i<4; i++) { 7.119 - float val = smoothstep(low[i] - soft_rad, high[i] - soft_rad, x); 7.120 - val *= 1.0 - smoothstep(low[i] + soft_rad, high[i] + soft_rad, x); 7.121 - rgba_value[i] = val; 7.122 + for(int i=0; i<3; i++) { 7.123 + float val = smoothstep(low[i] - soft_rad, low[i] + soft_rad, x); 7.124 + val *= 1.0 - smoothstep(high[i] - soft_rad, high[i] + soft_rad, x); 7.125 + rgb_value[i] = val; 7.126 } 7.127 }
8.1 --- a/src/xfermap.h Tue Dec 30 06:22:54 2014 +0200 8.2 +++ b/src/xfermap.h Tue Dec 30 17:28:38 2014 +0200 8.3 @@ -12,11 +12,20 @@ 8.4 class TransferWindow : public TransferFunc { 8.5 private: 8.6 float soft_rad; 8.7 - float low[4], high[4]; // rgb 8.8 + float low[3], high[3]; // rgb 8.9 8.10 public: 8.11 + enum { HANDLE_LOW = 0, HANDLE_HIGH = 1}; 8.12 + 8.13 TransferWindow(); 8.14 8.15 + // handle: 0 or HANDLE_LOW is low, 1 or HANDLE_HIGH is high 8.16 + // if channel == -1, change all channels simultaneously 8.17 + void set_handle(int channel, int handle, float val); 8.18 + float get_handle(int channel, int handle) const; 8.19 + 8.20 + int nearest_handle(int channel, float pos) const; 8.21 + 8.22 void set_interval(float a, float b); 8.23 void set_interval(float *rgba_low, float *rgba_high); 8.24 void set_interval_rgba(int channel, float a, float b);