Panda3D

trackball.cxx

00001 // Filename: trackball.cxx
00002 // Created by:  drose (12Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "trackball.h"
00016 #include "buttonEvent.h"
00017 #include "buttonEventList.h"
00018 #include "dataNodeTransmit.h"
00019 #include "compose_matrix.h"
00020 #include "mouseData.h"
00021 #include "modifierButtons.h"
00022 #include "linmath_events.h"
00023 #include "mouseButton.h"
00024 #include "keyboardButton.h"
00025 
00026 TypeHandle Trackball::_type_handle;
00027 
00028 // These are used internally.
00029 #define B1_MASK 0x01
00030 #define B2_MASK 0x02
00031 #define B3_MASK 0x04
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: Trackball::Constructor
00035 //       Access: Public
00036 //  Description:
00037 ////////////////////////////////////////////////////////////////////
00038 Trackball::
00039 Trackball(const string &name) :
00040   MouseInterfaceNode(name)
00041 {
00042   _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
00043 
00044   _transform_output = define_output("transform", TransformState::get_class_type());
00045 
00046   _transform = TransformState::make_identity();
00047 
00048   _rotscale = 0.3f;
00049   _fwdscale = 0.3f;
00050 
00051   _last_button = 0;
00052   _lastx = _lasty = 0.5f;
00053 
00054   _rotation = LMatrix4f::ident_mat();
00055   _translation.set(0.0f, 0.0f, 0.0f);
00056   _mat = LMatrix4f::ident_mat();
00057   _orig = LMatrix4f::ident_mat();
00058   _invert = true;
00059   _cs = get_default_coordinate_system();
00060 
00061   // We want to track the state of these buttons.
00062   watch_button(MouseButton::one());
00063   watch_button(MouseButton::two());
00064   watch_button(MouseButton::three());
00065 
00066 #ifdef IS_OSX
00067   // In OSX mode, we need to use the command and option key in
00068   // conjunction with the (one) mouse button.
00069   watch_button(KeyboardButton::meta());
00070   watch_button(KeyboardButton::alt());
00071 #endif
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: Trackball::Destructor
00076 //       Access: Published
00077 //  Description:
00078 ////////////////////////////////////////////////////////////////////
00079 Trackball::
00080 ~Trackball() {
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: Trackball::reset
00085 //       Access: Published
00086 //  Description: Reinitializes all transforms to identity.
00087 ////////////////////////////////////////////////////////////////////
00088 void Trackball::
00089 reset() {
00090   _rotation = LMatrix4f::ident_mat();
00091   _translation.set(0.0f, 0.0f, 0.0f);
00092   _orig = LMatrix4f::ident_mat();
00093   _mat = LMatrix4f::ident_mat();
00094 }
00095 
00096 ////////////////////////////////////////////////////////////////////
00097 //     Function: Trackball::get_forward_scale
00098 //       Access: Published
00099 //  Description: Returns the scale factor applied to forward and
00100 //               backward motion.  See set_forward_scale().
00101 ////////////////////////////////////////////////////////////////////
00102 float Trackball::
00103 get_forward_scale() const {
00104   return _fwdscale;
00105 }
00106 
00107 ////////////////////////////////////////////////////////////////////
00108 //     Function: Trackball::set_forward_scale
00109 //       Access: Published
00110 //  Description: Changes the scale factor applied to forward and
00111 //               backward motion.  The larger this number, the faster
00112 //               the model will move in response to dollying in and
00113 //               out.
00114 ////////////////////////////////////////////////////////////////////
00115 void Trackball::
00116 set_forward_scale(float fwdscale) {
00117   _fwdscale = fwdscale;
00118 }
00119 
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: Trackball::get_pos
00123 //       Access: Published
00124 //  Description: Return the offset from the center of rotation.
00125 ////////////////////////////////////////////////////////////////////
00126 const LPoint3f &Trackball::
00127 get_pos() const {
00128   return _translation;
00129 }
00130 
00131 float Trackball::
00132 get_x() const {
00133   return _translation[0];
00134 }
00135 
00136 float Trackball::
00137 get_y() const {
00138   return _translation[1];
00139 }
00140 
00141 float Trackball::
00142 get_z() const {
00143   return _translation[2];
00144 }
00145 
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: Trackball::set_pos
00149 //       Access: Published
00150 //  Description: Directly set the offset from the rotational origin.
00151 ////////////////////////////////////////////////////////////////////
00152 void Trackball::
00153 set_pos(const LVecBase3f &vec) {
00154   _translation = vec;
00155   recompute();
00156 }
00157 
00158 void Trackball::
00159 set_pos(float x, float y, float z) {
00160   _translation.set(x, y, z);
00161   recompute();
00162 }
00163 
00164 void Trackball::
00165 set_x(float x) {
00166   _translation[0] = x;
00167   recompute();
00168 }
00169 
00170 void Trackball::
00171 set_y(float y) {
00172   _translation[1] = y;
00173   recompute();
00174 }
00175 
00176 void Trackball::
00177 set_z(float z) {
00178   _translation[2] = z;
00179   recompute();
00180 }
00181 
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: Trackball::get_hpr
00185 //       Access: Published
00186 //  Description: Return the trackball's orientation.
00187 ////////////////////////////////////////////////////////////////////
00188 LVecBase3f Trackball::
00189 get_hpr() const {
00190   LVecBase3f scale, shear, hpr, translate;
00191   decompose_matrix(_rotation, scale, shear, hpr, translate);
00192   return hpr;
00193 }
00194 
00195 float Trackball::
00196 get_h() const {
00197   LVecBase3f scale, shear, hpr, translate;
00198   decompose_matrix(_rotation, scale, shear, hpr, translate);
00199   return hpr[0];
00200 }
00201 
00202 float Trackball::
00203 get_p() const {
00204   LVecBase3f scale, shear, hpr, translate;
00205   decompose_matrix(_rotation, scale, shear, hpr, translate);
00206   return hpr[1];
00207 }
00208 
00209 float Trackball::
00210 get_r() const {
00211   LVecBase3f scale, shear, hpr, translate;
00212   decompose_matrix(_rotation, scale, shear, hpr, translate);
00213   return hpr[2];
00214 }
00215 
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: Trackball::set_hpr
00219 //       Access: Published
00220 //  Description: Directly set the mover's orientation.
00221 ////////////////////////////////////////////////////////////////////
00222 void Trackball::
00223 set_hpr(const LVecBase3f &hpr) {
00224   LVecBase3f scale, shear, old_hpr, translate;
00225   decompose_matrix(_rotation, scale, shear, old_hpr, translate);
00226   compose_matrix(_rotation, scale, shear, hpr, translate);
00227   recompute();
00228 }
00229 
00230 void Trackball::
00231 set_hpr(float h, float p, float r) {
00232   LVecBase3f scale, shear, hpr, translate;
00233   decompose_matrix(_rotation, scale, shear, hpr, translate);
00234   hpr.set(h, p, r);
00235   compose_matrix(_rotation, scale, shear, hpr, translate);
00236   recompute();
00237 }
00238 
00239 void Trackball::
00240 set_h(float h) {
00241   LVecBase3f scale, shear, hpr, translate;
00242   decompose_matrix(_rotation, scale, shear, hpr, translate);
00243   hpr[0] = h;
00244   compose_matrix(_rotation, scale, shear, hpr, translate);
00245   recompute();
00246 }
00247 
00248 void Trackball::
00249 set_p(float p) {
00250   LVecBase3f scale, shear, hpr, translate;
00251   decompose_matrix(_rotation, scale, shear, hpr, translate);
00252   hpr[1] = p;
00253   compose_matrix(_rotation, scale, shear, hpr, translate);
00254   recompute();
00255 }
00256 
00257 void Trackball::
00258 set_r(float r) {
00259   LVecBase3f scale, shear, hpr, translate;
00260   decompose_matrix(_rotation, scale, shear, hpr, translate);
00261   hpr[2] = r;
00262   compose_matrix(_rotation, scale, shear, hpr, translate);
00263   recompute();
00264 }
00265 
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: Trackball::reset_origin_here
00269 //       Access: Published
00270 //  Description: Reposition the center of rotation to coincide with
00271 //               the current translation offset.  Future rotations
00272 //               will be about the current origin.
00273 ////////////////////////////////////////////////////////////////////
00274 void Trackball::
00275 reset_origin_here() {
00276   recompute();
00277   _rotation = _orig;
00278   _translation.set(0.0f, 0.0f, 0.0f);
00279 }
00280 
00281 
00282 ////////////////////////////////////////////////////////////////////
00283 //     Function: Trackball::move_origin
00284 //       Access: Published
00285 //  Description: Moves the center of rotation by the given amount.
00286 ////////////////////////////////////////////////////////////////////
00287 void Trackball::
00288 move_origin(float x, float y, float z) {
00289   _rotation = LMatrix4f::translate_mat(LVecBase3f(x, y, z)) *  _rotation;
00290 }
00291 
00292 ////////////////////////////////////////////////////////////////////
00293 //     Function: Trackball::get_origin
00294 //       Access: Published
00295 //  Description: Returns the current center of rotation.
00296 ////////////////////////////////////////////////////////////////////
00297 LPoint3f Trackball::
00298 get_origin() const {
00299   return _rotation.get_row3(3);
00300 }
00301 
00302 ////////////////////////////////////////////////////////////////////
00303 //     Function: Trackball::set_origin
00304 //       Access: Published
00305 //  Description: Directly sets the center of rotation.
00306 ////////////////////////////////////////////////////////////////////
00307 void Trackball::
00308 set_origin(const LVecBase3f &origin) {
00309   _rotation.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
00310   _rotation = LMatrix4f::translate_mat(-origin) *  _rotation;
00311 }
00312 
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: Trackball::set_invert
00316 //       Access: Published
00317 //  Description: Sets the invert flag.  When this is set, the inverse
00318 //               matrix is generated, suitable for joining to a
00319 //               camera, instead of parenting the scene under it.
00320 ////////////////////////////////////////////////////////////////////
00321 void Trackball::
00322 set_invert(bool flag) {
00323   _invert = flag;
00324 }
00325 
00326 ////////////////////////////////////////////////////////////////////
00327 //     Function: Trackball::get_invert
00328 //       Access: Published
00329 //  Description: Returns the invert flag.  When this is set, the
00330 //               inverse matrix is generated, suitable for joining to
00331 //               a camera, instead of parenting the scene under it.
00332 ////////////////////////////////////////////////////////////////////
00333 bool Trackball::
00334 get_invert() const {
00335   return _invert;
00336 }
00337 
00338 ////////////////////////////////////////////////////////////////////
00339 //     Function: Trackball::set_rel_to
00340 //       Access: Published
00341 //  Description: Sets the NodePath that all trackball manipulations
00342 //               are to be assumed to be relative to.  For instance,
00343 //               set your camera node here to make the trackball
00344 //               motion camera relative.  The default is the empty
00345 //               path, which means trackball motion is in global
00346 //               space.
00347 ////////////////////////////////////////////////////////////////////
00348 void Trackball::
00349 set_rel_to(const NodePath &rel_to) {
00350   _rel_to = rel_to;
00351 }
00352 
00353 ////////////////////////////////////////////////////////////////////
00354 //     Function: Trackball::get_rel_to
00355 //       Access: Published
00356 //  Description: Returns the NodePath that all trackball manipulations
00357 //               are relative to, or the empty path.
00358 ////////////////////////////////////////////////////////////////////
00359 const NodePath &Trackball::
00360 get_rel_to() const {
00361   return _rel_to;
00362 }
00363 
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: Trackball::set_coordinate_system
00367 //       Access: Published
00368 //  Description: Sets the coordinate system of the Trackball.
00369 //               Normally, this is the default coordinate system.
00370 //               This changes the axes the Trackball manipulates so
00371 //               that the user interface remains consistent across
00372 //               different coordinate systems.
00373 ////////////////////////////////////////////////////////////////////
00374 void Trackball::
00375 set_coordinate_system(CoordinateSystem cs) {
00376   _cs = cs;
00377 }
00378 
00379 ////////////////////////////////////////////////////////////////////
00380 //     Function: Trackball::get_coordinate_system
00381 //       Access: Published
00382 //  Description: Returns the coordinate system of the Trackball.
00383 //               See set_coordinate_system().
00384 ////////////////////////////////////////////////////////////////////
00385 CoordinateSystem Trackball::
00386 get_coordinate_system() const {
00387   return _cs;
00388 }
00389 
00390 ////////////////////////////////////////////////////////////////////
00391 //     Function: Trackball::set_mat
00392 //       Access: Published
00393 //  Description: Stores the indicated transform in the trackball.
00394 //               This is a transform in global space, regardless of
00395 //               the rel_to node.
00396 ////////////////////////////////////////////////////////////////////
00397 void Trackball::
00398 set_mat(const LMatrix4f &mat) {
00399   _orig = mat;
00400   if (_invert) {
00401     _mat = invert(_orig);
00402   } else {
00403     _mat = _orig;
00404   }
00405 
00406   reextract();
00407 }
00408 
00409 
00410 ////////////////////////////////////////////////////////////////////
00411 //     Function: Trackball::get_mat
00412 //       Access: Published
00413 //  Description: Returns the matrix represented by the trackball
00414 //               rotation.
00415 ////////////////////////////////////////////////////////////////////
00416 const LMatrix4f &Trackball::
00417 get_mat() const {
00418   return _orig;
00419 }
00420 
00421 ////////////////////////////////////////////////////////////////////
00422 //     Function: Trackball::get_trans_mat
00423 //       Access: Published
00424 //  Description: Returns the actual transform that will be applied to
00425 //               the scene graph.  This is the same as get_mat(),
00426 //               unless invert is in effect.
00427 ////////////////////////////////////////////////////////////////////
00428 const LMatrix4f &Trackball::
00429 get_trans_mat() const {
00430   return _mat;
00431 }
00432 
00433 
00434 ////////////////////////////////////////////////////////////////////
00435 //     Function: Trackball::apply
00436 //       Access: Private
00437 //  Description: Applies the operation indicated by the user's mouse
00438 //               motion to the current state.  Returns the matrix
00439 //               indicating the new state.
00440 ////////////////////////////////////////////////////////////////////
00441 void Trackball::
00442 apply(double x, double y, int button) {
00443   if (button && !_rel_to.is_empty()) {
00444     // If we have a rel_to node, we must first adjust our rotation and
00445     // translation to be in those local coordinates.
00446     reextract();
00447   }
00448   if (button == B1_MASK) {
00449     // Button 1: translate in plane parallel to screen.
00450 
00451     _translation +=
00452       x * _fwdscale * LVector3f::right(_cs) +
00453       y * _fwdscale * LVector3f::down(_cs);
00454 
00455   } else if (button == (B2_MASK | B3_MASK)) {
00456     // Buttons 2 + 3: rotate about the vector perpendicular to the
00457     // screen.
00458 
00459     _rotation *=
00460       LMatrix4f::rotate_mat_normaxis((x - y) * _rotscale,
00461                             LVector3f::forward(_cs), _cs);
00462 
00463   } else if ((button == B2_MASK) || (button == (B1_MASK | B3_MASK))) {
00464     // Button 2, or buttons 1 + 3: rotate about the right and up
00465     // vectors.  (We alternately define this as buttons 1 + 3, to
00466     // support two-button mice.)
00467 
00468     _rotation *=
00469       LMatrix4f::rotate_mat_normaxis(x * _rotscale, LVector3f::up(_cs), _cs) *
00470       LMatrix4f::rotate_mat_normaxis(y * _rotscale, LVector3f::right(_cs), _cs);
00471 
00472   } else if ((button == B3_MASK) || (button == (B1_MASK | B2_MASK))) {
00473     // Button 3, or buttons 1 + 2: dolly in and out along the forward
00474     // vector.  (We alternately define this as buttons 1 + 2, to
00475     // support two-button mice.)
00476     _translation -= y * _fwdscale * LVector3f::forward(_cs);
00477   }
00478 
00479   if (button) {
00480     recompute();
00481   }
00482 }
00483 
00484 
00485 ////////////////////////////////////////////////////////////////////
00486 //     Function: Trackball::reextract
00487 //       Access: Private
00488 //  Description: Given a correctly computed _orig matrix, rederive the
00489 //               translation and rotation elements.
00490 ////////////////////////////////////////////////////////////////////
00491 void Trackball::
00492 reextract() {
00493   LMatrix4f m = _orig;
00494   if (!_rel_to.is_empty()) {
00495     NodePath root;
00496     m = _orig * root.get_transform(_rel_to)->get_mat();
00497   }
00498 
00499   m.get_row3(_translation,3);
00500   _rotation = m;
00501   _rotation.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
00502 }
00503 
00504 ////////////////////////////////////////////////////////////////////
00505 //     Function: Trackball::recompute
00506 //       Access: Private
00507 //  Description: Rebuilds the matrix according to the stored rotation
00508 //               and translation components.
00509 ////////////////////////////////////////////////////////////////////
00510 void Trackball::
00511 recompute() {
00512   _orig = _rotation * LMatrix4f::translate_mat(_translation);
00513 
00514   if (!_rel_to.is_empty()) {
00515     NodePath root;
00516     _orig = _orig * _rel_to.get_transform(root)->get_mat();
00517   }
00518 
00519   if (_invert) {
00520     _mat = invert(_orig);
00521   } else {
00522     _mat = _orig;
00523   }
00524 }
00525 
00526 
00527 ////////////////////////////////////////////////////////////////////
00528 //     Function: Trackball::do_transmit_data
00529 //       Access: Protected, Virtual
00530 //  Description: The virtual implementation of transmit_data().  This
00531 //               function receives an array of input parameters and
00532 //               should generate an array of output parameters.  The
00533 //               input parameters may be accessed with the index
00534 //               numbers returned by the define_input() calls that
00535 //               were made earlier (presumably in the constructor);
00536 //               likewise, the output parameters should be set with
00537 //               the index numbers returned by the define_output()
00538 //               calls.
00539 ////////////////////////////////////////////////////////////////////
00540 void Trackball::
00541 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input,
00542                  DataNodeTransmit &output) {
00543   // First, update our modifier buttons.
00544   bool required_buttons_match;
00545   check_button_events(input, required_buttons_match);
00546 
00547   // Now, check for mouse motion.
00548   if (required_buttons_match && input.has_data(_pixel_xy_input)) {
00549     const EventStoreVec2 *pixel_xy;
00550     DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
00551     const LVecBase2f &p = pixel_xy->get_value();
00552     float this_x = p[0];
00553     float this_y = p[1];
00554     int this_button = 0;
00555     
00556     if (is_down(MouseButton::one())) {
00557 #ifdef IS_OSX
00558       if (is_down(KeyboardButton::alt())) {
00559         // B1 + alt (option) = B2.
00560         this_button |= B2_MASK;
00561         if (is_down(KeyboardButton::meta())) {
00562           this_button |= B3_MASK;
00563         }
00564 
00565       } else if (is_down(KeyboardButton::meta())) {
00566         // B1 + meta (command) = B3.
00567         this_button |= B3_MASK;
00568 
00569       } else {
00570         // Without a special key, B1 is B1.
00571         this_button |= B1_MASK;
00572       }
00573 #else   // IS_OSX
00574       this_button |= B1_MASK;
00575 #endif  // IS_OSX
00576     }
00577     if (is_down(MouseButton::two())) {
00578       this_button |= B2_MASK;
00579     }
00580     if (is_down(MouseButton::three())) {
00581       this_button |= B3_MASK;
00582     }
00583     
00584     float x = this_x - _lastx;
00585     float y = this_y - _lasty;
00586 
00587     if (this_button == _last_button) {
00588       apply(x, y, this_button);
00589     }
00590     
00591     _last_button = this_button;
00592     _lastx = this_x;
00593     _lasty = this_y;
00594   } else {
00595     _last_button = 0;
00596   }
00597 
00598   // Now send our matrix down the pipe.
00599   _transform = TransformState::make_mat(_mat);
00600   output.set_data(_transform_output, EventParameter(_transform));
00601 }
 All Classes Functions Variables Enumerations