Panda3D
trackball.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file trackball.cxx
10  * @author drose
11  * @date 2002-03-12
12  */
13 
14 #include "trackball.h"
15 #include "buttonEvent.h"
16 #include "buttonEventList.h"
17 #include "dataNodeTransmit.h"
18 #include "compose_matrix.h"
19 #include "mouseData.h"
20 #include "modifierButtons.h"
21 #include "linmath_events.h"
22 #include "mouseButton.h"
23 #include "keyboardButton.h"
24 #include "config_tform.h"
25 
26 TypeHandle Trackball::_type_handle;
27 
28 // These are used internally.
29 #define B1_MASK 0x01
30 #define B2_MASK 0x02
31 #define B3_MASK 0x04
32 
33 /**
34  *
35  */
36 Trackball::
37 Trackball(const std::string &name) :
38  MouseInterfaceNode(name)
39 {
40  _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
41 
42  _transform_output = define_output("transform", TransformState::get_class_type());
43 
44  _transform = TransformState::make_identity();
45 
46  _rotscale = 0.3;
47  _fwdscale = 0.3;
48 
49  _last_button = 0;
50  _lastx = _lasty = 0.5f;
51 
52  _rotation = LMatrix4::ident_mat();
53  _translation.set(0.0f, 0.0f, 0.0f);
54  _mat = LMatrix4::ident_mat();
55  _orig = LMatrix4::ident_mat();
56  _invert = true;
57  _cs = get_default_coordinate_system();
58  _control_mode = CM_default;
59 
60  // We want to track the state of these buttons.
61  watch_button(MouseButton::one());
62  watch_button(MouseButton::two());
63  watch_button(MouseButton::three());
64 
65  if (trackball_use_alt_keys) {
66  // In OSX mode, we need to use the command and option key in conjunction
67  // with the (one) mouse button.
68  watch_button(KeyboardButton::control());
69  watch_button(KeyboardButton::meta());
70  watch_button(KeyboardButton::alt());
71  }
72 }
73 
74 /**
75  *
76  */
77 Trackball::
78 ~Trackball() {
79 }
80 
81 /**
82  * Reinitializes all transforms to identity.
83  */
85 reset() {
86  _rotation = LMatrix4::ident_mat();
87  _translation.set(0.0f, 0.0f, 0.0f);
88  _orig = LMatrix4::ident_mat();
89  _mat = LMatrix4::ident_mat();
90 }
91 
92 /**
93  * Returns the scale factor applied to forward and backward motion. See
94  * set_forward_scale().
95  */
96 PN_stdfloat Trackball::
97 get_forward_scale() const {
98  return _fwdscale;
99 }
100 
101 /**
102  * Changes the scale factor applied to forward and backward motion. The
103  * larger this number, the faster the model will move in response to dollying
104  * in and out.
105  */
107 set_forward_scale(PN_stdfloat fwdscale) {
108  _fwdscale = fwdscale;
109 }
110 
111 
112 /**
113  * Return the offset from the center of rotation.
114  */
115 const LPoint3 &Trackball::
116 get_pos() const {
117  return _translation;
118 }
119 
120 PN_stdfloat Trackball::
121 get_x() const {
122  return _translation[0];
123 }
124 
125 PN_stdfloat Trackball::
126 get_y() const {
127  return _translation[1];
128 }
129 
130 PN_stdfloat Trackball::
131 get_z() const {
132  return _translation[2];
133 }
134 
135 
136 /**
137  * Directly set the offset from the rotational origin.
138  */
140 set_pos(const LVecBase3 &vec) {
141  _translation = vec;
142  recompute();
143 }
144 
145 void Trackball::
146 set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) {
147  _translation.set(x, y, z);
148  recompute();
149 }
150 
151 void Trackball::
152 set_x(PN_stdfloat x) {
153  _translation[0] = x;
154  recompute();
155 }
156 
157 void Trackball::
158 set_y(PN_stdfloat y) {
159  _translation[1] = y;
160  recompute();
161 }
162 
163 void Trackball::
164 set_z(PN_stdfloat z) {
165  _translation[2] = z;
166  recompute();
167 }
168 
169 
170 /**
171  * Return the trackball's orientation.
172  */
173 LVecBase3 Trackball::
174 get_hpr() const {
175  LVecBase3 scale, shear, hpr, translate;
176  decompose_matrix(_rotation, scale, shear, hpr, translate);
177  return hpr;
178 }
179 
180 PN_stdfloat Trackball::
181 get_h() const {
182  LVecBase3 scale, shear, hpr, translate;
183  decompose_matrix(_rotation, scale, shear, hpr, translate);
184  return hpr[0];
185 }
186 
187 PN_stdfloat Trackball::
188 get_p() const {
189  LVecBase3 scale, shear, hpr, translate;
190  decompose_matrix(_rotation, scale, shear, hpr, translate);
191  return hpr[1];
192 }
193 
194 PN_stdfloat Trackball::
195 get_r() const {
196  LVecBase3 scale, shear, hpr, translate;
197  decompose_matrix(_rotation, scale, shear, hpr, translate);
198  return hpr[2];
199 }
200 
201 
202 /**
203  * Directly set the mover's orientation.
204  */
206 set_hpr(const LVecBase3 &hpr) {
207  LVecBase3 scale, shear, old_hpr, translate;
208  decompose_matrix(_rotation, scale, shear, old_hpr, translate);
209  compose_matrix(_rotation, scale, shear, hpr, translate);
210  recompute();
211 }
212 
213 void Trackball::
214 set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) {
215  LVecBase3 scale, shear, hpr, translate;
216  decompose_matrix(_rotation, scale, shear, hpr, translate);
217  hpr.set(h, p, r);
218  compose_matrix(_rotation, scale, shear, hpr, translate);
219  recompute();
220 }
221 
222 void Trackball::
223 set_h(PN_stdfloat h) {
224  LVecBase3 scale, shear, hpr, translate;
225  decompose_matrix(_rotation, scale, shear, hpr, translate);
226  hpr[0] = h;
227  compose_matrix(_rotation, scale, shear, hpr, translate);
228  recompute();
229 }
230 
231 void Trackball::
232 set_p(PN_stdfloat p) {
233  LVecBase3 scale, shear, hpr, translate;
234  decompose_matrix(_rotation, scale, shear, hpr, translate);
235  hpr[1] = p;
236  compose_matrix(_rotation, scale, shear, hpr, translate);
237  recompute();
238 }
239 
240 void Trackball::
241 set_r(PN_stdfloat r) {
242  LVecBase3 scale, shear, hpr, translate;
243  decompose_matrix(_rotation, scale, shear, hpr, translate);
244  hpr[2] = r;
245  compose_matrix(_rotation, scale, shear, hpr, translate);
246  recompute();
247 }
248 
249 
250 /**
251  * Reposition the center of rotation to coincide with the current translation
252  * offset. Future rotations will be about the current origin.
253  */
256  recompute();
257  _rotation = _orig;
258  _translation.set(0.0f, 0.0f, 0.0f);
259 }
260 
261 
262 /**
263  * Moves the center of rotation by the given amount.
264  */
266 move_origin(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) {
267  _rotation = LMatrix4::translate_mat(LVecBase3(x, y, z)) * _rotation;
268 }
269 
270 /**
271  * Returns the current center of rotation.
272  */
273 LPoint3 Trackball::
274 get_origin() const {
275  return _rotation.get_row3(3);
276 }
277 
278 /**
279  * Directly sets the center of rotation.
280  */
282 set_origin(const LVecBase3 &origin) {
283  _rotation.set_row(3, LVecBase3(0.0f, 0.0f, 0.0f));
284  _rotation = LMatrix4::translate_mat(-origin) * _rotation;
285 }
286 
287 
288 /**
289  * Sets the invert flag. When this is set, the inverse matrix is generated,
290  * suitable for joining to a camera, instead of parenting the scene under it.
291  */
293 set_invert(bool flag) {
294  _invert = flag;
295 }
296 
297 /**
298  * Returns the invert flag. When this is set, the inverse matrix is
299  * generated, suitable for joining to a camera, instead of parenting the scene
300  * under it.
301  */
303 get_invert() const {
304  return _invert;
305 }
306 
307 /**
308  * Sets the control mode. Normally this is CM_default, which means each mouse
309  * button serves its normal function. When it is CM_truck, CM_pan, CM_dolly,
310  * or CM_roll, all of the mouse buttons serve the indicated function instead
311  * of their normal function. This can be used in conjunction with some
312  * external way of changing modes.
313  */
315 set_control_mode(ControlMode control_mode) {
316  _control_mode = control_mode;
317 }
318 
319 /**
320  * Returns the control mode. See set_control_mode().
321  */
322 Trackball::ControlMode Trackball::
323 get_control_mode() const {
324  return _control_mode;
325 }
326 
327 /**
328  * Sets the NodePath that all trackball manipulations are to be assumed to be
329  * relative to. For instance, set your camera node here to make the trackball
330  * motion camera relative. The default is the empty path, which means
331  * trackball motion is in global space.
332  */
334 set_rel_to(const NodePath &rel_to) {
335  _rel_to = rel_to;
336 }
337 
338 /**
339  * Returns the NodePath that all trackball manipulations are relative to, or
340  * the empty path.
341  */
343 get_rel_to() const {
344  return _rel_to;
345 }
346 
347 
348 /**
349  * Sets the coordinate system of the Trackball. Normally, this is the default
350  * coordinate system. This changes the axes the Trackball manipulates so that
351  * the user interface remains consistent across different coordinate systems.
352  */
354 set_coordinate_system(CoordinateSystem cs) {
355  _cs = cs;
356 }
357 
358 /**
359  * Returns the coordinate system of the Trackball. See
360  * set_coordinate_system().
361  */
362 CoordinateSystem Trackball::
363 get_coordinate_system() const {
364  return _cs;
365 }
366 
367 /**
368  * Stores the indicated transform in the trackball. This is a transform in
369  * global space, regardless of the rel_to node.
370  */
372 set_mat(const LMatrix4 &mat) {
373  _orig = mat;
374  if (_invert) {
375  _mat = invert(_orig);
376  } else {
377  _mat = _orig;
378  }
379 
380  reextract();
381 }
382 
383 
384 /**
385  * Returns the matrix represented by the trackball rotation.
386  */
387 const LMatrix4 &Trackball::
388 get_mat() const {
389  return _orig;
390 }
391 
392 /**
393  * Returns the actual transform that will be applied to the scene graph. This
394  * is the same as get_mat(), unless invert is in effect.
395  */
396 const LMatrix4 &Trackball::
397 get_trans_mat() const {
398  return _mat;
399 }
400 
401 
402 /**
403  * Applies the operation indicated by the user's mouse motion to the current
404  * state. Returns the matrix indicating the new state.
405  */
406 void Trackball::
407 apply(double x, double y, int button) {
408  if (button && !_rel_to.is_empty()) {
409  // If we have a rel_to node, we must first adjust our rotation and
410  // translation to be in those local coordinates.
411  reextract();
412  }
413 
414  if (button == B1_MASK && _control_mode != CM_default) {
415  // We have a control mode set; this may change the meaning of button 1.
416  // Remap button to match the current control mode setting.
417  switch (_control_mode) {
418  case CM_truck:
419  button = B1_MASK;
420  break;
421 
422  case CM_pan:
423  button = B2_MASK;
424  break;
425 
426  case CM_dolly:
427  button = B3_MASK;
428  break;
429 
430  case CM_roll:
431  button = B2_MASK | B3_MASK;
432  break;
433 
434  case CM_default:
435  // Not possible due to above logic.
436  nassertv(false);
437  }
438  }
439 
440  if (button == B1_MASK) {
441  // Button 1: translate in plane parallel to screen.
442 
443  _translation +=
444  x * _fwdscale * LVector3::right(_cs) +
445  y * _fwdscale * LVector3::down(_cs);
446 
447  } else if (button == (B2_MASK | B3_MASK)) {
448  // Buttons 2 + 3: rotate about the vector perpendicular to the screen.
449 
450  _rotation *=
451  LMatrix4::rotate_mat_normaxis((x - y) * _rotscale,
452  LVector3::forward(_cs), _cs);
453 
454  } else if ((button == B2_MASK) || (button == (B1_MASK | B3_MASK))) {
455  // Button 2, or buttons 1 + 3: rotate about the right and up vectors. (We
456  // alternately define this as buttons 1 + 3, to support two-button mice.)
457 
458  _rotation *=
459  LMatrix4::rotate_mat_normaxis(x * _rotscale, LVector3::up(_cs), _cs) *
460  LMatrix4::rotate_mat_normaxis(y * _rotscale, LVector3::right(_cs), _cs);
461 
462  } else if ((button == B3_MASK) || (button == (B1_MASK | B2_MASK))) {
463  // Button 3, or buttons 1 + 2: dolly in and out along the forward vector.
464  // (We alternately define this as buttons 1 + 2, to support two-button
465  // mice.)
466  _translation -= y * _fwdscale * LVector3::forward(_cs);
467  }
468 
469  if (button) {
470  recompute();
471  }
472 }
473 
474 
475 /**
476  * Given a correctly computed _orig matrix, rederive the translation and
477  * rotation elements.
478  */
479 void Trackball::
480 reextract() {
481  LMatrix4 m = _orig;
482  if (!_rel_to.is_empty()) {
483  NodePath root;
484  m = _orig * root.get_transform(_rel_to)->get_mat();
485  }
486 
487  m.get_row3(_translation,3);
488  _rotation = m;
489  _rotation.set_row(3, LVecBase3(0.0f, 0.0f, 0.0f));
490 }
491 
492 /**
493  * Rebuilds the matrix according to the stored rotation and translation
494  * components.
495  */
496 void Trackball::
497 recompute() {
498  _orig = _rotation * LMatrix4::translate_mat(_translation);
499 
500  if (!_rel_to.is_empty()) {
501  NodePath root;
502  _orig = _orig * _rel_to.get_transform(root)->get_mat();
503  }
504 
505  if (_invert) {
506  _mat = invert(_orig);
507  } else {
508  _mat = _orig;
509  }
510 }
511 
512 
513 /**
514  * The virtual implementation of transmit_data(). This function receives an
515  * array of input parameters and should generate an array of output
516  * parameters. The input parameters may be accessed with the index numbers
517  * returned by the define_input() calls that were made earlier (presumably in
518  * the constructor); likewise, the output parameters should be set with the
519  * index numbers returned by the define_output() calls.
520  */
521 void Trackball::
522 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input,
523  DataNodeTransmit &output) {
524  // First, update our modifier buttons.
525  bool required_buttons_match;
526  check_button_events(input, required_buttons_match);
527 
528  // Now, check for mouse motion.
529  if (required_buttons_match && input.has_data(_pixel_xy_input)) {
530  const EventStoreVec2 *pixel_xy;
531  DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
532  const LVecBase2 &p = pixel_xy->get_value();
533  PN_stdfloat this_x = p[0];
534  PN_stdfloat this_y = p[1];
535  int this_button = 0;
536 
537  if (is_down(MouseButton::one())) {
538  if (is_down(KeyboardButton::alt())) {
539  // B1 + alt (option) = B2.
540  this_button |= B2_MASK;
541  if (is_down(KeyboardButton::meta()) || is_down(KeyboardButton::control())) {
542  this_button |= B3_MASK;
543  }
544 
545  } else if (is_down(KeyboardButton::meta()) || is_down(KeyboardButton::control())) {
546  // B1 + meta (command) = B3.
547  this_button |= B3_MASK;
548 
549  } else {
550  // Without a special key, B1 is B1.
551  this_button |= B1_MASK;
552  }
553  }
554  if (is_down(MouseButton::two())) {
555  this_button |= B2_MASK;
556  }
557  if (is_down(MouseButton::three())) {
558  this_button |= B3_MASK;
559  }
560 
561  PN_stdfloat x = this_x - _lastx;
562  PN_stdfloat y = this_y - _lasty;
563 
564  if (this_button == _last_button) {
565  apply(x, y, this_button);
566  }
567 
568  _last_button = this_button;
569  _lastx = this_x;
570  _lasty = this_y;
571  } else {
572  _last_button = 0;
573  }
574 
575  // Now send our matrix down the pipe.
576  _transform = TransformState::make_mat(_mat);
577  output.set_data(_transform_output, EventParameter(_transform));
578 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object supervises the traversal of the data graph and the moving of data from one DataNode to it...
Encapsulates the data generated from (or sent into) any particular DataNode.
const EventParameter & get_data(int index) const
Extracts the data for the indicated index, if it has been stored, or the empty parameter if it has no...
void set_data(int index, const EventParameter &data)
Sets the data for the indicated parameter.
bool has_data(int index) const
Returns true if the indicated parameter has been stored, false otherwise.
An optional parameter associated with an event.
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:43
static ButtonHandle two()
Returns the ButtonHandle associated with the second mouse button.
Definition: mouseButton.cxx:51
static ButtonHandle three()
Returns the ButtonHandle associated with the third mouse button.
Definition: mouseButton.cxx:59
This is the base class for some classes that monitor the mouse and keyboard input and perform some ac...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:795
A handy class object for storing simple values (like integers or strings) passed along with an Event ...
Definition: paramValue.h:103
get_value
Retrieves the value stored in the parameter.
Definition: paramValue.h:115
void reset()
Reinitializes all transforms to identity.
Definition: trackball.cxx:85
const LMatrix4 & get_mat() const
Returns the matrix represented by the trackball rotation.
Definition: trackball.cxx:388
const LMatrix4 & get_trans_mat() const
Returns the actual transform that will be applied to the scene graph.
Definition: trackball.cxx:397
void set_control_mode(ControlMode control_mode)
Sets the control mode.
Definition: trackball.cxx:315
void set_hpr(const LVecBase3 &hpr)
Directly set the mover's orientation.
Definition: trackball.cxx:206
LVecBase3 get_hpr() const
Return the trackball's orientation.
Definition: trackball.cxx:174
const LPoint3 & get_pos() const
Return the offset from the center of rotation.
Definition: trackball.cxx:116
bool get_invert() const
Returns the invert flag.
Definition: trackball.cxx:303
void set_origin(const LVecBase3 &origin)
Directly sets the center of rotation.
Definition: trackball.cxx:282
PN_stdfloat get_forward_scale() const
Returns the scale factor applied to forward and backward motion.
Definition: trackball.cxx:97
CoordinateSystem get_coordinate_system() const
Returns the coordinate system of the Trackball.
Definition: trackball.cxx:363
void move_origin(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Moves the center of rotation by the given amount.
Definition: trackball.cxx:266
void reset_origin_here()
Reposition the center of rotation to coincide with the current translation offset.
Definition: trackball.cxx:255
void set_coordinate_system(CoordinateSystem cs)
Sets the coordinate system of the Trackball.
Definition: trackball.cxx:354
void set_invert(bool flag)
Sets the invert flag.
Definition: trackball.cxx:293
LPoint3 get_origin() const
Returns the current center of rotation.
Definition: trackball.cxx:274
void set_rel_to(const NodePath &rel_to)
Sets the NodePath that all trackball manipulations are to be assumed to be relative to.
Definition: trackball.cxx:334
void set_mat(const LMatrix4 &mat)
Stores the indicated transform in the trackball.
Definition: trackball.cxx:372
void set_pos(const LVecBase3 &vec)
Directly set the offset from the rotational origin.
Definition: trackball.cxx:140
const NodePath & get_rel_to() const
Returns the NodePath that all trackball manipulations are relative to, or the empty path.
Definition: trackball.cxx:343
ControlMode get_control_mode() const
Returns the control mode.
Definition: trackball.cxx:323
void set_forward_scale(PN_stdfloat fwdscale)
Changes the scale factor applied to forward and backward motion.
Definition: trackball.cxx:107
get_mat
Returns the matrix that describes the transform.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.