Panda3D
Loading...
Searching...
No Matches
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
26TypeHandle 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 */
36Trackball::
37Trackball(const std::string &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 */
77Trackball::
78~Trackball() {
79}
80
81/**
82 * Reinitializes all transforms to identity.
83 */
85reset() {
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 */
96PN_stdfloat Trackball::
97get_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 */
107set_forward_scale(PN_stdfloat fwdscale) {
108 _fwdscale = fwdscale;
109}
110
111
112/**
113 * Return the offset from the center of rotation.
114 */
115const LPoint3 &Trackball::
116get_pos() const {
117 return _translation;
118}
119
120PN_stdfloat Trackball::
121get_x() const {
122 return _translation[0];
123}
124
125PN_stdfloat Trackball::
126get_y() const {
127 return _translation[1];
128}
129
130PN_stdfloat Trackball::
131get_z() const {
132 return _translation[2];
133}
134
135
136/**
137 * Directly set the offset from the rotational origin.
138 */
140set_pos(const LVecBase3 &vec) {
141 _translation = vec;
142 recompute();
143}
144
145void Trackball::
146set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) {
147 _translation.set(x, y, z);
148 recompute();
149}
150
151void Trackball::
152set_x(PN_stdfloat x) {
153 _translation[0] = x;
154 recompute();
155}
156
157void Trackball::
158set_y(PN_stdfloat y) {
159 _translation[1] = y;
160 recompute();
161}
162
163void Trackball::
164set_z(PN_stdfloat z) {
165 _translation[2] = z;
166 recompute();
167}
168
169
170/**
171 * Return the trackball's orientation.
172 */
173LVecBase3 Trackball::
174get_hpr() const {
175 LVecBase3 scale, shear, hpr, translate;
176 decompose_matrix(_rotation, scale, shear, hpr, translate);
177 return hpr;
178}
179
180PN_stdfloat Trackball::
181get_h() const {
182 LVecBase3 scale, shear, hpr, translate;
183 decompose_matrix(_rotation, scale, shear, hpr, translate);
184 return hpr[0];
185}
186
187PN_stdfloat Trackball::
188get_p() const {
189 LVecBase3 scale, shear, hpr, translate;
190 decompose_matrix(_rotation, scale, shear, hpr, translate);
191 return hpr[1];
192}
193
194PN_stdfloat Trackball::
195get_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 */
206set_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
213void Trackball::
214set_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
222void Trackball::
223set_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
231void Trackball::
232set_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
240void Trackball::
241set_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 */
266move_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 */
274get_origin() const {
275 return _rotation.get_row3(3);
276}
277
278/**
279 * Directly sets the center of rotation.
280 */
282set_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 */
293set_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 */
303get_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 */
315set_control_mode(ControlMode control_mode) {
316 _control_mode = control_mode;
317}
318
319/**
320 * Returns the control mode. See set_control_mode().
321 */
322Trackball::ControlMode Trackball::
323get_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 */
334set_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 */
343get_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 */
354set_coordinate_system(CoordinateSystem cs) {
355 _cs = cs;
356}
357
358/**
359 * Returns the coordinate system of the Trackball. See
360 * set_coordinate_system().
361 */
362CoordinateSystem Trackball::
363get_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 */
372set_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 */
387const LMatrix4 &Trackball::
388get_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 */
396const LMatrix4 &Trackball::
397get_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 */
406void Trackball::
407apply(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 */
479void Trackball::
480reextract() {
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 */
496void Trackball::
497recompute() {
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 */
521void Trackball::
522do_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.
static ButtonHandle two()
Returns the ButtonHandle associated with the second mouse button.
static ButtonHandle three()
Returns the ButtonHandle associated with the third mouse button.
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:794
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.
const LMatrix4 & get_trans_mat() const
Returns the actual transform that will be applied to the scene graph.
void set_control_mode(ControlMode control_mode)
Sets the control mode.
void set_hpr(const LVecBase3 &hpr)
Directly set the mover's orientation.
LVecBase3 get_hpr() const
Return the trackball's orientation.
const LPoint3 & get_pos() const
Return the offset from the center of rotation.
bool get_invert() const
Returns the invert flag.
void set_origin(const LVecBase3 &origin)
Directly sets the center of rotation.
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.
void move_origin(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Moves the center of rotation by the given amount.
void reset_origin_here()
Reposition the center of rotation to coincide with the current translation offset.
void set_coordinate_system(CoordinateSystem cs)
Sets the coordinate system of the Trackball.
void set_invert(bool flag)
Sets the invert flag.
LPoint3 get_origin() const
Returns the current center of rotation.
void set_rel_to(const NodePath &rel_to)
Sets the NodePath that all trackball manipulations are to be assumed to be relative to.
void set_mat(const LMatrix4 &mat)
Stores the indicated transform in the trackball.
void set_pos(const LVecBase3 &vec)
Directly set the offset from the rotational origin.
const NodePath & get_rel_to() const
Returns the NodePath that all trackball manipulations are relative to, or the empty path.
ControlMode get_control_mode() const
Returns the control mode.
void set_forward_scale(PN_stdfloat fwdscale)
Changes the scale factor applied to forward and backward motion.
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.