Subversion Repositories gelsvn

Rev

Rev 23 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 23 Rev 38
Line 11... Line 11...
11
using namespace std;
11
using namespace std;
12
using namespace CGLA;
12
using namespace CGLA;
13
 
13
 
14
namespace Graphics
14
namespace Graphics
15
{
15
{
16
 
16
    
17
	TrackBall::TrackBall(const Vec3f& _centre, 
17
    TrackBall::TrackBall(const Vec3f& _centre, 
18
											 float _eye_dist,
18
			 float _eye_dist,
19
											 unsigned _width, 
19
			 unsigned _width, 
20
											 unsigned _height):
20
			 unsigned _height):
21
		centre(_centre), eye_dist(_eye_dist), scale(0.5*_eye_dist), 
21
	centre(_centre), eye_dist(_eye_dist), scale(0.5*_eye_dist), 
22
		width(_width), height(_height)
22
	width(_width), height(_height)
23
	{
23
	{
24
		// This size should really be based on the distance from the center of
24
	// This size should really be based on the distance from the center of
25
		// rotation to the point on the object underneath the mouse.  That
25
	// rotation to the point on the object underneath the mouse.  That
26
		// point would then track the mouse as closely as possible.  This is a
26
	// point would then track the mouse as closely as possible.  This is a
27
		// simple example, though, so that is left as an exercise.
27
	// simple example, though, so that is left as an exercise.
28
		ballsize = 2.0f;
28
	ballsize = 2.0f;
29
		screen_centre = Vec2i(width/2, height/2);
29
	screen_centre = Vec2i(width/2, height/2);
30
		qrot = Quaternion(0.0, 0.0, 0.0, 1.0);
30
	qrot = Quaternion(0.0, 0.0, 0.0, 1.0);
31
		qinc = Quaternion(0.0, 0.0, 0.0, 1.0);
31
	qinc = Quaternion(0.0, 0.0, 0.0, 1.0);
32
		trans = Vec2f(0.0, 0.0);
32
	trans = Vec2f(0.0, 0.0);
33
	}
33
    }
34
 
34
    
35
	void TrackBall::grab_ball(TrackBallAction act, const Vec2i& v)
35
    void TrackBall::grab_ball(TrackBallAction act, const Vec2i& v)
36
	{
36
    {
37
		set_position(scalePoint(v));
37
	set_position(scalePoint(v));
38
		current_action = act;
38
	current_action = act;
39
	}
39
    }
40
 
40
    
41
	void TrackBall::roll_ball(const Vec2i& v)
41
    void TrackBall::roll_ball(const Vec2i& v)
42
	{
42
    {
43
		Vec2f w = scalePoint(v); 
43
	Vec2f w = scalePoint(v); 
44
	
44
	
45
		switch (current_action) 
45
	switch (current_action) 
46
			{
46
	{
47
			case ROTATE_ACTION:
47
			case ROTATE_ACTION:
48
				rotate(w);
48
	    rotate(w);
49
				break;
49
	    break;
50
			
50
	    
51
			case PAN_ACTION:
51
			case PAN_ACTION:
52
				pan(w);
52
	    pan(w);
53
				break;
53
	    break;
54
			
54
	    
55
			case ZOOM_ACTION:
55
			case ZOOM_ACTION:
56
				zoom(w);
56
	    zoom(w);
57
				break;
57
	    break;
58
			}
-
 
59
		last_pos = w;	
-
 
60
	}
-
 
61
 
-
 
62
	// Call this when the user does a mouse down.  
-
 
63
	// Stop the trackball glide, then remember the mouse
-
 
64
	// down point (for a future rotate, pan or zoom).
-
 
65
	void TrackBall::set_position(const Vec2f& _last_pos) 
-
 
66
	{
-
 
67
		stop_spin();
-
 
68
		last_pos = _last_pos;
-
 
69
	}
-
 
70
 
-
 
71
	// Rotationaly spin the trackball by the current increment.
-
 
72
	// Use this to implement rotational glide.
-
 
73
	void TrackBall::do_spin() 
-
 
74
	{
-
 
75
		qrot = qrot*qinc;
-
 
76
	}
-
 
77
 
-
 
78
	// Cease any rotational glide by zeroing the increment.
-
 
79
	void TrackBall::stop_spin() 
-
 
80
	{
-
 
81
		qinc.set(0.0, 0.0, 0.0, 1.0);
-
 
82
	}
-
 
83
 
-
 
84
	void TrackBall::rotate(const Vec2f& new_v) 
-
 
85
	{
-
 
86
		calcRotation(new_v);
-
 
87
		do_spin();	
-
 
88
	}
-
 
89
 
-
 
90
	void TrackBall::pan(const Vec2f& new_v) 
-
 
91
	{
-
 
92
		trans += (new_v - last_pos) * Vec2f(scale[0], scale[1]);
-
 
93
	}
-
 
94
 
-
 
95
	void TrackBall::zoom(const Vec2f& new_v) 
-
 
96
	{
-
 
97
		eye_dist += (new_v[1] - last_pos[1]) * scale[2];
-
 
98
		eye_dist = max(eye_dist, 0.01f);
-
 
99
	}
-
 
100
 
-
 
101
	void TrackBall::calcRotation(const Vec2f& new_pos) 
-
 
102
	{
-
 
103
		// Check for zero rotation
-
 
104
		if (new_pos == last_pos) 
-
 
105
			qinc = Quaternion();
-
 
106
		else
-
 
107
			{
-
 
108
				// Form two vectors based on input points, find rotation axis
-
 
109
				Vec3f p1 = Vec3f(new_pos[0], new_pos[1], projectToSphere(new_pos));
-
 
110
				Vec3f p2 = Vec3f(last_pos[0], last_pos[1], projectToSphere(last_pos));
-
 
111
			
-
 
112
				Vec3f q = cross(p1, p2);		/* axis of rotation from p1 and p2 */
-
 
113
				float L = sqrt(1.0f-dot(q,q) / (dot(p1,p1) * dot(p2,p2)));
-
 
114
			
-
 
115
				q.normalize();				/* q' = axis of rotation */
-
 
116
				q *= sqrt((1 - L)/2);	/* q' = q' * sin(phi) */
-
 
117
			
-
 
118
				qinc.set(q[0],q[1],q[2],sqrt((1 + L)/2));
-
 
119
			}
-
 
120
	}
-
 
121
 
-
 
122
	// Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
-
 
123
	// if we are away from the center of the sphere.
-
 
124
	float TrackBall::projectToSphere(const Vec2f& v) 
-
 
125
	{
-
 
126
		float d, t, z;
-
 
127
 
-
 
128
		d = v.length();
-
 
129
  
-
 
130
		// Inside sphere 
-
 
131
		if (d < ballsize * 0.70710678118654752440) {   
-
 
132
			z = sqrt(ballsize*ballsize - d*d);
-
 
133
		}
-
 
134
		// On hyperbola 
-
 
135
		else {           
-
 
136
			t = ballsize / 1.41421356237309504880;
-
 
137
			z = t*t / d;
-
 
138
		}
-
 
139
 
-
 
140
		return z;
-
 
141
	}
-
 
142
 
-
 
143
	// Scales integer point to the range [-1, 1]
-
 
144
	Vec2f TrackBall::scalePoint(const Vec2i& v) const
-
 
145
	{
-
 
146
		Vec2f w(v[0],height - v[1]);
-
 
147
		w -= Vec2f(screen_centre);
-
 
148
		w /= Vec2f(width,height);
-
 
149
		w = CGLA::v_min(Vec2f(1.0f), CGLA::v_max(Vec2f(-1), 2*w));
-
 
150
		return w; 
-
 
151
	}
58
	}
-
 
59
	last_pos = w;	
-
 
60
    }
152
 
61
    
-
 
62
    // Call this when the user does a mouse down.  
-
 
63
    // Stop the trackball glide, then remember the mouse
-
 
64
    // down point (for a future rotate, pan or zoom).
153
	void TrackBall::get_view_param(Vec3f& eye, Vec3f& _centre, Vec3f& up) const
65
    void TrackBall::set_position(const Vec2f& _last_pos) 
154
	{
66
    {
155
		up  = qrot.apply(Vec3f(0,1,0));
67
	stop_spin();
156
		Vec3f right = qrot.apply(Vec3f(1,0,0));
68
	last_pos = _last_pos;
-
 
69
    }
-
 
70
    
157
		_centre = centre - up * trans[1] - right * trans[0]; 
71
    // Rotationaly spin the trackball by the current increment.
158
		eye = qrot.apply(Vec3f(0,0,1)*eye_dist) + _centre;
72
    // Use this to implement rotational glide.
-
 
73
    void TrackBall::do_spin() 
159
	}
74
    {
-
 
75
	qrot = qrot*qinc;
160
 
76
    }
161
 
77
    
162
	// Modify the current gl matrix by the trackball rotation and translation.
78
    // Cease any rotational glide by zeroing the increment.
163
	void TrackBall::set_gl_modelview() const
79
    void TrackBall::stop_spin() 
164
	{
80
    {
165
		glMatrixMode(GL_MODELVIEW);
81
	qinc.set(0.0, 0.0, 0.0, 1.0);
-
 
82
    }
-
 
83
    
-
 
84
    void TrackBall::rotate(const Vec2f& new_v) 
-
 
85
    {
166
		glLoadIdentity();
86
	calcRotation(new_v);
167
		Vec3f eye;
87
	do_spin();	
-
 
88
    }
-
 
89
    
-
 
90
    void TrackBall::pan(const Vec2f& new_v) 
-
 
91
    {
-
 
92
	trans += (new_v - last_pos) * Vec2f(scale[0], scale[1]);
168
		Vec3f _centre;
93
    }
-
 
94
    
-
 
95
    void TrackBall::zoom(const Vec2f& new_v) 
169
		Vec3f up;
96
    {
-
 
97
	eye_dist += (new_v[1] - last_pos[1]) * scale[2];
170
		get_view_param(eye, _centre, up);
98
	eye_dist = max(eye_dist, 0.01f);
-
 
99
    }
-
 
100
    
-
 
101
    void TrackBall::calcRotation(const Vec2f& new_pos) 
-
 
102
    {
171
		gluLookAt(eye[0], eye[1], eye[2],
103
	// Check for zero rotation
172
							_centre[0], _centre[1], _centre[2], 
104
	if (new_pos == last_pos) 
173
							up[0],up[1],up[2]);
105
	    qinc = Quaternion();
-
 
106
	else
174
	}
107
	{
-
 
108
		// Form two vectors based on input points, find rotation axis
-
 
109
		Vec3f p1 = Vec3f(new_pos[0], new_pos[1], projectToSphere(new_pos));
-
 
110
		Vec3f p2 = Vec3f(last_pos[0], last_pos[1], projectToSphere(last_pos));
-
 
111
		
-
 
112
		Vec3f q = cross(p1, p2);		/* axis of rotation from p1 and p2 */
-
 
113
		float L = sqrt(1.0f-dot(q,q) / (dot(p1,p1) * dot(p2,p2)));
-
 
114
		
-
 
115
		q.normalize();				/* q' = axis of rotation */
-
 
116
		q *= sqrt((1 - L)/2);	/* q' = q' * sin(phi) */
175
 
117
		
-
 
118
		qinc.set(q[0],q[1],q[2],sqrt((1 + L)/2));
-
 
119
	    }
-
 
120
    }
-
 
121
    
-
 
122
    // Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
-
 
123
    // if we are away from the center of the sphere.
176
	bool TrackBall::is_spinning() const
124
    float TrackBall::projectToSphere(const Vec2f& v) 
-
 
125
    {
-
 
126
	float d, t, z;
-
 
127
	
-
 
128
	d = v.length();
177
	{
129
	
-
 
130
	// Inside sphere 
-
 
131
	if (d < ballsize * 0.70710678118654752440) {   
178
		static const Quaternion null_quat(0,0,0,1);
132
	    z = sqrt(ballsize*ballsize - d*d);
-
 
133
	}
179
		if(!(qinc == null_quat))
134
	// On hyperbola 
180
			return true;
135
	else {           
-
 
136
	    t = ballsize / 1.41421356237309504880;
181
		return false;
137
	    z = t*t / d;
182
	}
138
	}
-
 
139
	
-
 
140
	return z;
-
 
141
    }
-
 
142
    
-
 
143
    // Scales integer point to the range [-1, 1]
-
 
144
    Vec2f TrackBall::scalePoint(const Vec2i& v) const
-
 
145
    {
-
 
146
	Vec2f w(v[0],height - v[1]);
-
 
147
	w -= Vec2f(screen_centre);
-
 
148
	w /= Vec2f(width,height);
-
 
149
	w = CGLA::v_min(Vec2f(1.0f), CGLA::v_max(Vec2f(-1), 2*w));
-
 
150
	return w; 
-
 
151
    }
-
 
152
    
-
 
153
    void TrackBall::get_view_param(Vec3f& eye, Vec3f& _centre, Vec3f& up) const
-
 
154
    {
-
 
155
	up  = qrot.apply(Vec3f(0,1,0));
-
 
156
	Vec3f right = qrot.apply(Vec3f(1,0,0));
-
 
157
	_centre = centre - up * trans[1] - right * trans[0]; 
-
 
158
	eye = qrot.apply(Vec3f(0,0,1)*eye_dist) + _centre;
-
 
159
    }
-
 
160
    
-
 
161
    
-
 
162
    // Modify the current gl matrix by the trackball rotation and translation.
-
 
163
    void TrackBall::set_gl_modelview() const
-
 
164
    {
-
 
165
	glMatrixMode(GL_MODELVIEW);
-
 
166
	glLoadIdentity();
-
 
167
	Vec3f eye;
-
 
168
	Vec3f _centre;
-
 
169
	Vec3f up;
-
 
170
	get_view_param(eye, _centre, up);
-
 
171
	gluLookAt(eye[0], eye[1], eye[2],
-
 
172
		  _centre[0], _centre[1], _centre[2], 
-
 
173
		  up[0],up[1],up[2]);
-
 
174
    }
-
 
175
    
-
 
176
    bool TrackBall::is_spinning() const
-
 
177
    {
-
 
178
	static const Quaternion null_quat(0,0,0,1);
-
 
179
	if(!(qinc == null_quat))
-
 
180
	    return true;
-
 
181
	return false;
-
 
182
    }
183
}
183
}