1 /**********************************************************************
2 
3   arcball.cpp
4 
5 
6           --------------------------------------------------
7 
8   GLUI User Interface Toolkit (LGPL)
9   Copyright (c) 1998 Paul Rademacher
10      Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
11      Oct 2003, Nigel Stewart - GLUI Code Cleaning
12 
13   WWW:    http://sourceforge.net/projects/glui/
14   Forums: http://sourceforge.net/forum/?group_id=92496
15 
16   This library is free software; you can redistribute it and/or
17   modify it under the terms of the GNU Lesser General Public
18   License as published by the Free Software Foundation; either
19   version 2.1 of the License, or (at your option) any later version.
20 
21   This library is distributed in the hope that it will be useful,
22   but WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   Lesser General Public License for more details.
25 
26   You should have received a copy of the GNU Lesser General Public
27   License along with this library; if not, write to the Free Software
28   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 
30 **********************************************************************/
31 
32 #include "arcball.h"
33 
34 #include <cstdio>
35 
36 
37 /**************************************** Arcball::Arcball() ****/
38 /* Default (void) constructor for Arcball                         */
39 
Arcball()40 Arcball::Arcball()
41 {
42     rot_ptr = &rot;
43     init();
44 }
45 
46 /**************************************** Arcball::Arcball() ****/
47 /* Takes as argument a mat4 to use instead of the internal rot  */
48 
Arcball(mat4 * mtx)49 Arcball::Arcball(mat4 *mtx)
50 {
51     rot_ptr = mtx;
52 }
53 
54 
55 /**************************************** Arcball::Arcball() ****/
56 /* A constructor that accepts the screen center and arcball radius*/
57 
Arcball(const vec2 & _center,float _radius)58 Arcball::Arcball(const vec2 &_center, float _radius)
59 {
60     rot_ptr = &rot;
61     init();
62     set_params(_center, _radius);
63 }
64 
65 
66 /************************************** Arcball::set_params() ****/
67 
set_params(const vec2 & _center,float _radius)68 void Arcball::set_params(const vec2 &_center, float _radius)
69 {
70     center      = _center;
71     radius      = _radius;
72 }
73 
74 /*************************************** Arcball::init() **********/
75 
init()76 void Arcball::init()
77 {
78     center.set( 0.0, 0.0 );
79     radius         = 1.0;
80     q_now          = quat_identity();
81     *rot_ptr       = identity3D();
82     q_increment    = quat_identity();
83     rot_increment  = identity3D();
84     is_mouse_down  = false;
85     is_spinning    = false;
86     damp_factor    = 0.0;
87     zero_increment = true;
88 }
89 
90 /*********************************** Arcball::mouse_to_sphere() ****/
91 
mouse_to_sphere(const vec2 & p)92 vec3 Arcball::mouse_to_sphere(const vec2 &p)
93 {
94     float mag;
95     vec2  v2 = (p - center) / radius;
96     vec3  v3( v2[0], v2[1], 0.0 );
97 
98     mag = v2*v2;
99 
100     if ( mag > 1.0 )
101         v3.normalize();
102     else
103         v3[VZ] = (float) sqrt( 1.0 - mag );
104 
105     /* Now we add constraints - X takes precedence over Y */
106     if ( constraint_x )
107     {
108         v3 = constrain_vector( v3, vec3( 1.0, 0.0, 0.0 ));
109     }
110     else if ( constraint_y )
111         {
112             v3 = constrain_vector( v3, vec3( 0.0, 1.0, 0.0 ));
113         }
114 
115     return v3;
116 }
117 
118 
119 /************************************ Arcball::constrain_vector() ****/
120 
constrain_vector(const vec3 & vector,const vec3 & axis)121 vec3 Arcball::constrain_vector(const vec3 &vector, const vec3 &axis)
122 {
123     return (vector-(vector*axis)*axis).normalize();
124 }
125 
126 /************************************ Arcball::mouse_down() **********/
127 
mouse_down(int x,int y)128 void Arcball::mouse_down(int x, int y)
129 {
130     down_pt.set( (float)x, (float) y );
131     is_mouse_down = true;
132 
133     q_increment   = quat_identity();
134     rot_increment = identity3D();
135     zero_increment = true;
136 }
137 
138 
139 /************************************ Arcball::mouse_up() **********/
140 
mouse_up()141 void Arcball::mouse_up()
142 {
143     q_now = q_drag * q_now;
144     is_mouse_down = false;
145 }
146 
147 
148 /********************************** Arcball::mouse_motion() **********/
149 
mouse_motion(int x,int y,int shift,int ctrl,int alt)150 void Arcball::mouse_motion(int x, int y, int shift, int ctrl, int alt)
151 {
152     /* Set the X constraint if CONTROL key is pressed, Y if ALT key */
153     set_constraints( ctrl != 0, alt != 0 );
154 
155     vec2 new_pt( (float)x, (float) y );
156     vec3 v0 = mouse_to_sphere( down_pt );
157     vec3 v1 = mouse_to_sphere( new_pt );
158 
159     vec3 cross = v0^v1;
160 
161     q_drag.set( cross, v0 * v1 );
162 
163     //    *rot_ptr = (q_drag * q_now).to_mat4();
164     mat4 temp = q_drag.to_mat4();
165     *rot_ptr = *rot_ptr * temp;
166 
167     down_pt = new_pt;
168 
169     /* We keep a copy of the current incremental rotation (= q_drag) */
170     q_increment   = q_drag;
171     rot_increment = q_increment.to_mat4();
172 
173     set_constraints(false, false);
174 
175     if ( q_increment.s < .999999 )
176     {
177         is_spinning = true;
178         zero_increment = false;
179     }
180     else
181     {
182         is_spinning = false;
183         zero_increment = true;
184     }
185 }
186 
187 
188 /********************************** Arcball::mouse_motion() **********/
189 
mouse_motion(int x,int y)190 void Arcball::mouse_motion(int x, int y)
191 {
192     mouse_motion(x, y, 0, 0, 0);
193 }
194 
195 
196 /***************************** Arcball::set_constraints() **********/
197 
set_constraints(bool _constraint_x,bool _constraint_y)198 void Arcball::set_constraints(bool _constraint_x, bool _constraint_y)
199 {
200     constraint_x = _constraint_x;
201     constraint_y = _constraint_y;
202 }
203 
204 /***************************** Arcball::idle() *********************/
205 
idle()206 void Arcball::idle()
207 {
208     if (is_mouse_down)
209     {
210         is_spinning = false;
211         zero_increment = true;
212     }
213 
214     if (damp_factor < 1.0f)
215         q_increment.scale_angle(1.0f - damp_factor);
216 
217     rot_increment = q_increment.to_mat4();
218 
219     if (q_increment.s >= .999999f)
220     {
221         is_spinning = false;
222         zero_increment = true;
223     }
224 }
225 
226 
227 /************************ Arcball::set_damping() *********************/
228 
set_damping(float d)229 void Arcball::set_damping(float d)
230 {
231     damp_factor = d;
232 }
233 
234 
235 
236 
237 
238