Subversion Repositories gelsvn

Rev

Rev 87 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 87 Rev 119
1
#include <iostream>
1
#include <iostream>
2
#include "CGLA/CGLA.h"
2
#include "CGLA/CGLA.h"
3
#include "QuatTrackBall.h"
3
#include "QuatTrackBall.h"
4
 
4
 
5
#ifdef WIN32
5
#ifdef WIN32
6
#include <windows.h>
6
#include <windows.h>
7
#endif
7
#endif
8
 
8
 
9
#include <GL/glu.h>
9
#include <GL/glu.h>
10
 
10
 
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
    QuatTrackBall::QuatTrackBall(const Vec3f& _centre, 
17
    QuatTrackBall::QuatTrackBall(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 QuatTrackBall::grab_ball(TrackBallAction act, const Vec2i& v)
35
    void QuatTrackBall::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 QuatTrackBall::roll_ball(const Vec2i& v)
41
    void QuatTrackBall::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
	}
58
	}
59
	last_pos = w;	
59
	last_pos = w;	
60
    }
60
    }
61
    
61
    
62
    // Call this when the user does a mouse down.  
62
    // Call this when the user does a mouse down.  
63
    // Stop the trackball glide, then remember the mouse
63
    // Stop the trackball glide, then remember the mouse
64
    // down point (for a future rotate, pan or zoom).
64
    // down point (for a future rotate, pan or zoom).
65
    void QuatTrackBall::set_position(const Vec2f& _last_pos) 
65
    void QuatTrackBall::set_position(const Vec2f& _last_pos) 
66
    {
66
    {
67
	stop_spin();
67
	stop_spin();
68
	last_pos = _last_pos;
68
	last_pos = _last_pos;
69
    }
69
    }
70
    
70
    
71
    // Rotationaly spin the trackball by the current increment.
71
    // Rotationaly spin the trackball by the current increment.
72
    // Use this to implement rotational glide.
72
    // Use this to implement rotational glide.
73
    void QuatTrackBall::do_spin() 
73
    void QuatTrackBall::do_spin() 
74
    {
74
    {
75
	qrot = qrot*qinc;
75
	qrot = qrot*qinc;
76
    }
76
    }
77
    
77
    
78
    // Cease any rotational glide by zeroing the increment.
78
    // Cease any rotational glide by zeroing the increment.
79
    void QuatTrackBall::stop_spin() 
79
    void QuatTrackBall::stop_spin() 
80
    {
80
    {
81
	qinc.set(0.0, 0.0, 0.0, 1.0);
81
	qinc.set(0.0, 0.0, 0.0, 1.0);
82
    }
82
    }
83
    
83
    
84
    void QuatTrackBall::rotate(const Vec2f& new_v) 
84
    void QuatTrackBall::rotate(const Vec2f& new_v) 
85
    {
85
    {
86
	calcRotation(new_v);
86
	calcRotation(new_v);
87
	do_spin();	
87
	do_spin();	
88
    }
88
    }
89
    
89
    
90
    void QuatTrackBall::pan(const Vec2f& new_v) 
90
    void QuatTrackBall::pan(const Vec2f& new_v) 
91
    {
91
    {
92
	trans += (new_v - last_pos) * Vec2f(scale[0], scale[1]);
92
	trans += (new_v - last_pos) * Vec2f(scale[0], scale[1]);
93
    }
93
    }
94
    
94
    
95
    void QuatTrackBall::zoom(const Vec2f& new_v) 
95
    void QuatTrackBall::zoom(const Vec2f& new_v) 
96
    {
96
    {
97
	eye_dist += (new_v[1] - last_pos[1]) * scale[2];
97
	eye_dist += (new_v[1] - last_pos[1]) * scale[2];
98
	eye_dist = max(eye_dist, 0.01f);
98
	eye_dist = max(eye_dist, 0.01f);
99
    }
99
    }
100
    
100
    
101
    void QuatTrackBall::calcRotation(const Vec2f& new_pos) 
101
    void QuatTrackBall::calcRotation(const Vec2f& new_pos) 
102
    {
102
    {
103
	// Check for zero rotation
103
	// Check for zero rotation
104
	if (new_pos == last_pos) 
104
	if (new_pos == last_pos) 
105
	    qinc = Quaternion();
105
	    qinc = Quaternion();
106
	else
106
	else
107
	{
107
	{
108
		// Form two vectors based on input points, find rotation axis
108
		// Form two vectors based on input points, find rotation axis
109
		Vec3f p1 = Vec3f(new_pos[0], new_pos[1], projectToSphere(new_pos));
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));
110
		Vec3f p2 = Vec3f(last_pos[0], last_pos[1], projectToSphere(last_pos));
111
		
111
		
112
		Vec3f q = cross(p1, p2);		/* axis of rotation from p1 and p2 */
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)));
113
		float L = sqrt(1.0f-dot(q,q) / (dot(p1,p1) * dot(p2,p2)));
114
		
114
		
115
		q.normalize();				/* q' = axis of rotation */
115
		q.normalize();				/* q' = axis of rotation */
116
		q *= sqrt((1 - L)/2);	/* q' = q' * sin(phi) */
116
		q *= sqrt((1 - L)/2);	/* q' = q' * sin(phi) */
117
		
117
		
118
		qinc.set(q[0],q[1],q[2],sqrt((1 + L)/2));
118
		qinc.set(q[0],q[1],q[2],sqrt((1 + L)/2));
119
	    }
119
	    }
120
    }
120
    }
121
    
121
    
122
    // Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
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.
123
    // if we are away from the center of the sphere.
124
    float QuatTrackBall::projectToSphere(const Vec2f& v) 
124
    float QuatTrackBall::projectToSphere(const Vec2f& v) 
125
    {
125
    {
126
	float d, t, z;
126
	float d, t, z;
127
	
127
	
128
	d = v.length();
128
	d = v.length();
129
	
129
	
130
	// Inside sphere 
130
	// Inside sphere 
131
	if (d < ballsize * 0.70710678118654752440) {   
131
	if (d < ballsize * 0.70710678118654752440) {   
132
	    z = sqrt(ballsize*ballsize - d*d);
132
	    z = sqrt(ballsize*ballsize - d*d);
133
	}
133
	}
134
	// On hyperbola 
134
	// On hyperbola 
135
	else {           
135
	else {           
136
	    t = ballsize / 1.41421356237309504880;
136
	    t = ballsize / 1.41421356237309504880;
137
	    z = t*t / d;
137
	    z = t*t / d;
138
	}
138
	}
139
	
139
	
140
	return z;
140
	return z;
141
    }
141
    }
142
    
142
    
143
    // Scales integer point to the range [-1, 1]
143
    // Scales integer point to the range [-1, 1]
144
    Vec2f QuatTrackBall::scalePoint(const Vec2i& v) const
144
    Vec2f QuatTrackBall::scalePoint(const Vec2i& v) const
145
    {
145
    {
146
	Vec2f w(v[0],height - v[1]);
146
	Vec2f w(v[0],height - v[1]);
147
	w -= Vec2f(screen_centre);
147
	w -= Vec2f(screen_centre);
148
	w /= Vec2f(width,height);
148
	w /= Vec2f(width,height);
149
	w = CGLA::v_min(Vec2f(1.0f), CGLA::v_max(Vec2f(-1), 2*w));
149
	w = CGLA::v_min(Vec2f(1.0f), CGLA::v_max(Vec2f(-1), 2*w));
150
	return w; 
150
	return w; 
151
    }
151
    }
152
    
152
    
153
    void QuatTrackBall::get_view_param(Vec3f& eye, Vec3f& _centre, Vec3f& up) const
153
    void QuatTrackBall::get_view_param(Vec3f& eye, Vec3f& _centre, Vec3f& up) const
154
    {
154
    {
155
	up  = qrot.apply(Vec3f(0,1,0));
155
	up  = qrot.apply(Vec3f(0,1,0));
156
	Vec3f right = qrot.apply(Vec3f(1,0,0));
156
	Vec3f right = qrot.apply(Vec3f(1,0,0));
157
	_centre = centre - up * trans[1] - right * trans[0]; 
157
	_centre = centre - up * trans[1] - right * trans[0]; 
158
	eye = qrot.apply(Vec3f(0,0,1)*eye_dist) + _centre;
158
	eye = qrot.apply(Vec3f(0,0,1)*eye_dist) + _centre;
159
    }
159
    }
160
    
160
    
161
    
161
    
162
    // Modify the current gl matrix by the trackball rotation and translation.
162
    // Modify the current gl matrix by the trackball rotation and translation.
163
    void QuatTrackBall::set_gl_modelview() const
163
    void QuatTrackBall::set_gl_modelview() const
164
    {
164
    {
165
	glMatrixMode(GL_MODELVIEW);
165
	glMatrixMode(GL_MODELVIEW);
166
	glLoadIdentity();
166
	glLoadIdentity();
167
	Vec3f eye;
167
	Vec3f eye;
168
	Vec3f _centre;
168
	Vec3f _centre;
169
	Vec3f up;
169
	Vec3f up;
170
	get_view_param(eye, _centre, up);
170
	get_view_param(eye, _centre, up);
171
	gluLookAt(eye[0], eye[1], eye[2],
171
	gluLookAt(eye[0], eye[1], eye[2],
172
		  _centre[0], _centre[1], _centre[2], 
172
		  _centre[0], _centre[1], _centre[2], 
173
		  up[0],up[1],up[2]);
173
		  up[0],up[1],up[2]);
174
    }
174
    }
175
    
175
    
176
    bool QuatTrackBall::is_spinning() const
176
    bool QuatTrackBall::is_spinning() const
177
    {
177
    {
178
	static const Quaternion null_quat(0,0,0,1);
178
	static const Quaternion null_quat(0,0,0,1);
179
	if(!(qinc == null_quat))
179
	if(!(qinc == null_quat))
180
	    return true;
180
	    return true;
181
	return false;
181
	return false;
182
    }
182
    }
183
}
183
}
184
 
184