Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Extras / glui / arcball.cpp
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
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
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
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
68 void Arcball::set_params(const vec2 &_center, float _radius)
69 {
70     center      = _center;
71     radius      = _radius;
72 }
73
74 /*************************************** Arcball::init() **********/
75
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
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
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
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
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
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
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
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
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
229 void Arcball::set_damping(float d)
230 {
231     damp_factor = d;
232 }
233
234
235
236
237