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