Panda3D
|
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 }