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