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);