GLTrackball.cc
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #include "GLTrackball.hh"
00055
00056
00057
00058
00059
00060 namespace ACG {
00061
00062
00063
00064
00065
00066 GLTrackball::
00067 GLTrackball(GLState& _state)
00068 : glstate_(_state),
00069 center_(0,0,0)
00070 {
00071 for (int i=0; i<10; ++i)
00072 button_down_[i] = false;
00073 }
00074
00075
00076
00077
00078
00079 void
00080 GLTrackball::mouse_press(int button, int x, int y)
00081 {
00082 last_point_2D_ = ACG::Vec2i(x, y);
00083 last_point_ok_ = map_to_sphere(last_point_2D_, last_point_3D_);
00084
00085 button_down_[button] = true;
00086 }
00087
00088
00089
00090
00091
00092 void
00093 GLTrackball::mouse_release(int button, int , int )
00094 {
00095 last_point_ok_ = false;
00096 button_down_[button] = false;
00097
00098
00099 if (button == 3)
00100 zoom(0, (int)(last_point_2D_[1] - 0.05*glstate_.viewport_width()));
00101 else if (button == 4)
00102 zoom(0, (int)(last_point_2D_[1] + 0.05*glstate_.viewport_width()));
00103 }
00104
00105
00106
00107
00108
00109 void
00110 GLTrackball::mouse_move(int x, int y)
00111 {
00112 if (button_down_[0] && button_down_[1])
00113 action_ = ZOOM;
00114 else if (button_down_[0])
00115 action_ = ROTATION;
00116 else if (button_down_[1])
00117 action_ = TRANSLATION;
00118
00119 switch (action_)
00120 {
00121 case ROTATION: rotation(x, y); break;
00122 case TRANSLATION: translation(x, y); break;
00123 case ZOOM: zoom(x, y); break;
00124 }
00125
00126 last_point_2D_ = ACG::Vec2i(x, y);
00127 last_point_ok_ = map_to_sphere(last_point_2D_, last_point_3D_);
00128 }
00129
00130
00131
00132
00133
00134 void
00135 GLTrackball::rotation(int x, int y)
00136 {
00137 if (last_point_ok_)
00138 {
00139 Vec2i new_point_2D_;
00140 Vec3f new_point_3D_;
00141 bool new_point_ok_;
00142
00143 new_point_2D_ = ACG::Vec2i(x, y);
00144 new_point_ok_ = map_to_sphere(new_point_2D_, new_point_3D_);
00145
00146 if (new_point_ok_)
00147 {
00148 Vec3f axis = (last_point_3D_ % new_point_3D_);
00149 float cos_angle = (last_point_3D_ | new_point_3D_);
00150
00151 if (fabs(cos_angle) < 1.0)
00152 {
00153 float angle = 2.0*acos(cos_angle) * 180.0 / M_PI;
00154
00155 Vec3f t = glstate_.modelview().transform_point(center_);
00156 glstate_.translate(-t[0], -t[1], -t[2], MULT_FROM_LEFT);
00157 glstate_.rotate(angle, axis[0], axis[1], axis[2], MULT_FROM_LEFT);
00158 glstate_.translate( t[0], t[1], t[2], MULT_FROM_LEFT);
00159 }
00160 }
00161 }
00162 }
00163
00164
00165
00166
00167
00168 void
00169 GLTrackball::translation(int x, int y)
00170 {
00171 float dx = x - last_point_2D_[0];
00172 float dy = y - last_point_2D_[1];
00173
00174 float z = glstate_.modelview().transform_point(center_)[2];
00175 float w = glstate_.viewport_width();
00176 float h = glstate_.viewport_height();
00177 float fovy = glstate_.fovy();
00178 float nearpl = glstate_.near_plane();
00179
00180 float aspect = w / h;
00181 float top = tan(fovy/2.0f*M_PI/180.f) * nearpl;
00182 float right = aspect*top;
00183
00184 glstate_.translate(-2.0*dx/w*right/nearpl*z,
00185 2.0*dy/h*top/nearpl*z,
00186 0.0,
00187 MULT_FROM_LEFT);
00188 }
00189
00190
00191
00192
00193
00194 void
00195 GLTrackball::zoom(int , int y)
00196 {
00197 float dy = y - last_point_2D_[1];
00198 float z = glstate_.modelview().transform_point(center_)[2];
00199 float h = glstate_.viewport_height();
00200
00201 glstate_.translate(0.0,
00202 0.0,
00203 -2.0*dy/h*z,
00204 MULT_FROM_LEFT);
00205 }
00206
00207
00208
00209
00210
00211 bool
00212 GLTrackball::map_to_sphere(const Vec2i& _point, Vec3f& _result)
00213 {
00214 float width = glstate_.viewport_width();
00215 float height = glstate_.viewport_height();
00216
00217 if ( (_point[0] >= 0) && (_point[0] <= width) &&
00218 (_point[1] >= 0) && (_point[1] <= height) )
00219 {
00220 double x = (_point[0] - 0.5*width) / width;
00221 double y = (0.5*height - _point[1]) / height;
00222 double sinx = sin(M_PI * x * 0.5);
00223 double siny = sin(M_PI * y * 0.5);
00224 double sinx2siny2 = sinx * sinx + siny * siny;
00225
00226 _result[0] = sinx;
00227 _result[1] = siny;
00228 _result[2] = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
00229
00230 return true;
00231 }
00232 else return false;
00233 }
00234
00235
00236
00237 }
00238