diff --git a/panda/src/device/clientButtonDevice.h b/panda/src/device/clientButtonDevice.h index da8e576483..07c603e7b4 100644 --- a/panda/src/device/clientButtonDevice.h +++ b/panda/src/device/clientButtonDevice.h @@ -13,6 +13,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////// // Class : ClientButtonDevice diff --git a/panda/src/device/mouse.cxx b/panda/src/device/mouse.cxx index 6e4a6f6aa1..e18bd72eb9 100644 --- a/panda/src/device/mouse.cxx +++ b/panda/src/device/mouse.cxx @@ -18,7 +18,6 @@ //////////////////////////////////////////////////////////////////// TypeHandle MouseAndKeyboard::_type_handle; -TypeHandle MouseAndKeyboard::_mods_type; TypeHandle MouseAndKeyboard::_pixel_xyz_type; TypeHandle MouseAndKeyboard::_xyz_type; TypeHandle MouseAndKeyboard::_button_events_type; @@ -35,17 +34,14 @@ MouseAndKeyboard(GraphicsWindow *window, int device, const string& name) : _window(window), _device(device) { - _mods = new ModifierButtonDataAttribute(); _pixel_xyz = new Vec3DataAttribute(LPoint3f(0, 0, 0)); _xyz = new Vec3DataAttribute(LPoint3f(0, 0, 0)); _button_events = new ButtonEventDataAttribute(); - _got_mouse_attrib.set_attribute(_mods_type, _mods); _got_mouse_attrib.set_attribute(_pixel_xyz_type, _pixel_xyz); _got_mouse_attrib.set_attribute(_xyz_type, _xyz); _got_mouse_attrib.set_attribute(_button_events_type, _button_events); - _no_mouse_attrib.set_attribute(_mods_type, _mods); _no_mouse_attrib.set_attribute(_button_events_type, _button_events); } @@ -63,9 +59,6 @@ transmit_data(NodeAttributes &data) { _button_events->push_back(be); } - // Get modifier buttons - _mods->set_mods(_window->get_modifier_buttons(_device)); - if (_window->has_pointer(_device)) { const MouseData &mdata = _window->get_mouse_data(_device); @@ -105,9 +98,6 @@ init_type() { register_type(_type_handle, "MouseAndKeyboard", DataNode::get_class_type()); - ModifierButtonDataTransition::init_type(); - register_data_transition(_mods_type, "ModifierButtons", - ModifierButtonDataTransition::get_class_type()); Vec3DataTransition::init_type(); register_data_transition(_pixel_xyz_type, "PixelXYZ", Vec3DataTransition::get_class_type()); diff --git a/panda/src/device/mouse.h b/panda/src/device/mouse.h index b19e5d0aba..d36928e680 100644 --- a/panda/src/device/mouse.h +++ b/panda/src/device/mouse.h @@ -12,8 +12,6 @@ #include #include -#include -#include #include #include #include @@ -57,7 +55,6 @@ public: public: NodeAttributes _got_mouse_attrib; NodeAttributes _no_mouse_attrib; - PT(ModifierButtonDataAttribute) _mods; PT(Vec3DataAttribute) _pixel_xyz; PT(Vec3DataAttribute) _xyz; PT(ButtonEventDataAttribute) _button_events; diff --git a/panda/src/dgraph/Sources.pp b/panda/src/dgraph/Sources.pp index 110d8c0629..5b6a7e70cc 100644 --- a/panda/src/dgraph/Sources.pp +++ b/panda/src/dgraph/Sources.pp @@ -11,7 +11,9 @@ buttonEventDataAttribute.h buttonEventDataTransition.I \ buttonEventDataTransition.cxx buttonEventDataTransition.h \ config_dgraph.cxx config_dgraph.h dataGraphTraversal.cxx \ - dataGraphTraversal.h dataNode.cxx dataNode.h dataRelation.I \ + dataGraphTraversal.h \ + dataGraphTraverser.I dataGraphTraverser.cxx dataGraphTraverser.h \ + dataNode.cxx dataNode.h dataRelation.I \ dataRelation.N dataRelation.cxx dataRelation.h \ describe_data_verbose.cxx describe_data_verbose.h \ doubleDataAttribute.I doubleDataAttribute.cxx doubleDataAttribute.h \ @@ -24,9 +26,6 @@ intDataTransition.h matrixDataAttribute.I matrixDataAttribute.cxx \ matrixDataAttribute.h matrixDataTransition.I \ matrixDataTransition.cxx matrixDataTransition.h \ - modifierButtonDataAttribute.I modifierButtonDataAttribute.cxx \ - modifierButtonDataAttribute.h modifierButtonDataTransition.I \ - modifierButtonDataTransition.cxx modifierButtonDataTransition.h \ vec3DataAttribute.I vec3DataAttribute.cxx vec3DataAttribute.h \ vec3DataTransition.I vec3DataTransition.cxx vec3DataTransition.h \ vec4DataAttribute.I vec4DataAttribute.cxx vec4DataAttribute.h \ @@ -35,7 +34,8 @@ #define INSTALL_HEADERS \ buttonEventDataAttribute.I buttonEventDataAttribute.h \ buttonEventDataTransition.I buttonEventDataTransition.h \ - dataGraphTraversal.h dataNode.h dataRelation.I dataRelation.h \ + dataGraphTraversal.h \ + dataNode.h dataRelation.I dataRelation.h \ describe_data_verbose.h doubleDataAttribute.I doubleDataAttribute.h \ doubleDataTransition.I doubleDataTransition.h \ doublePtrDataAttribute.I doublePtrDataAttribute.h \ @@ -43,8 +43,6 @@ intDataAttribute.I intDataAttribute.h intDataTransition.I \ intDataTransition.h matrixDataAttribute.I matrixDataAttribute.h \ matrixDataTransition.I matrixDataTransition.h \ - modifierButtonDataAttribute.I modifierButtonDataAttribute.h \ - modifierButtonDataTransition.I modifierButtonDataTransition.h \ numericDataAttribute.I numericDataAttribute.h \ numericDataTransition.I numericDataTransition.h \ pointerDataAttribute.I pointerDataAttribute.h \ diff --git a/panda/src/dgraph/buttonEventDataAttribute.cxx b/panda/src/dgraph/buttonEventDataAttribute.cxx index e6a54da0a6..b09ae7bb9c 100644 --- a/panda/src/dgraph/buttonEventDataAttribute.cxx +++ b/panda/src/dgraph/buttonEventDataAttribute.cxx @@ -7,12 +7,27 @@ #include "buttonEventDataTransition.h" #include - +#include #include TypeHandle ButtonEventDataAttribute::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: ButtonEventDataAttribute::update_mods +// Access: Public +// Description: Updates the indicated ModifierButtons object with all +// of the button up/down transitions indicated in the +// queue. +//////////////////////////////////////////////////////////////////// +void ButtonEventDataAttribute:: +update_mods(ModifierButtons &mods) const { + Buttons::const_iterator bi; + for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) { + mods.add_event(*bi); + } +} + //////////////////////////////////////////////////////////////////// // Function: ButtonEventDataAttribute::make_copy // Access: Public, Virtual @@ -43,6 +58,38 @@ get_handle() const { return ButtonEventDataTransition::get_class_type(); } +//////////////////////////////////////////////////////////////////// +// Function: ButtonEventDataAttribute::merge +// Access: Public, Virtual +// Description: Attempts to merge this attribute with the other one, +// if that makes sense to do. Returns a new +// NodeAttribute pointer that represents the merge, or +// if the merge is not possible, returns the "other" +// pointer unchanged (which is the result of the merge). +//////////////////////////////////////////////////////////////////// +NodeAttribute *ButtonEventDataAttribute:: +merge(const NodeAttribute *other) const { + const ButtonEventDataAttribute *oa; + DCAST_INTO_R(oa, other, NULL); + + if (_buttons.empty()) { + return (ButtonEventDataAttribute *)oa; + + } else if (oa->_buttons.empty()) { + return (ButtonEventDataAttribute *)this; + + } else { + // We have to create a new data attribute that includes both sets + // of buttons. + ButtonEventDataAttribute *new_attrib = + new ButtonEventDataAttribute(*this); + + new_attrib->_buttons.insert(new_attrib->_buttons.end(), + oa->_buttons.begin(), oa->_buttons.end()); + return new_attrib; + } +} + //////////////////////////////////////////////////////////////////// // Function: ButtonEventDataAttribute::output // Access: Public, Virtual diff --git a/panda/src/dgraph/buttonEventDataAttribute.h b/panda/src/dgraph/buttonEventDataAttribute.h index 9b5435bd88..dd6703627d 100644 --- a/panda/src/dgraph/buttonEventDataAttribute.h +++ b/panda/src/dgraph/buttonEventDataAttribute.h @@ -14,6 +14,7 @@ #include class ButtonEventDataTransition; +class ModifierButtons; //////////////////////////////////////////////////////////////////// // Class : ButtonEventDataAttribute @@ -42,12 +43,16 @@ public: INLINE void clear(); INLINE void push_back(const ButtonEvent &event); + void update_mods(ModifierButtons &mods) const; + public: virtual NodeAttribute *make_copy() const; virtual NodeAttribute *make_initial() const; virtual TypeHandle get_handle() const; + virtual NodeAttribute *merge(const NodeAttribute *other) const; + virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; diff --git a/panda/src/dgraph/config_dgraph.cxx b/panda/src/dgraph/config_dgraph.cxx index ffb2c99a1a..b5017dd84b 100644 --- a/panda/src/dgraph/config_dgraph.cxx +++ b/panda/src/dgraph/config_dgraph.cxx @@ -16,9 +16,6 @@ #include "matrixDataAttribute.h" #include "buttonEventDataTransition.h" #include "buttonEventDataAttribute.h" -#include "modifierButtonDataTransition.h" -#include "modifierButtonDataAttribute.h" -#include "dataGraphTraversal.h" #include @@ -38,9 +35,6 @@ ConfigureFn(config_dgraph) { MatrixDataAttribute::init_type(); ButtonEventDataTransition::init_type(); ButtonEventDataAttribute::init_type(); - ModifierButtonDataTransition::init_type(); - ModifierButtonDataAttribute::init_type(); - DataGraphTraversal::init_spam_flag(); DataRelation::register_with_factory(); } diff --git a/panda/src/dgraph/dataGraphTraversal.cxx b/panda/src/dgraph/dataGraphTraversal.cxx index 78b9ae22b5..849529a4f6 100644 --- a/panda/src/dgraph/dataGraphTraversal.cxx +++ b/panda/src/dgraph/dataGraphTraversal.cxx @@ -4,82 +4,7 @@ //////////////////////////////////////////////////////////////////// #include "dataGraphTraversal.h" -#include "dataNode.h" -#include "dataRelation.h" -#include "intDataTransition.h" -#include "intDataAttribute.h" -#include "config_dgraph.h" -#include "describe_data_verbose.h" - -#include -#include -#include -#include - - -// Here's the static member of DataGraphTraversal. -TypeHandle DataGraphTraversal::_spam_flag_type; - - - -//////////////////////////////////////////////////////////////////// -// Function: DataGraphTraversal::init_spam_flag -// Access: Public, Static -// Description: This function is called during static -// initialization and registers a convenient type handle -// for the spam flag. -//////////////////////////////////////////////////////////////////// -void DataGraphTraversal:: -init_spam_flag() { - // We shouldn't try to call this function more than once. This - // function is only to be called during static initialization. - nassertv(_spam_flag_type == TypeHandle::none()); - IntDataTransition::init_type(); - register_type(_spam_flag_type, "SpamFlagTransition", - IntDataTransition::get_class_type()); -} - -//////////////////////////////////////////////////////////////////// -// Function: DataGraphVisitor::reached_node -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -bool DataGraphVisitor:: -reached_node(Node *node, AllAttributesWrapper &state, NullLevelState &) { - // Is the spam flag set? - bool has_spam_flag = - state.has_attribute(DataGraphTraversal::_spam_flag_type); - - if (has_spam_flag && dgraph_cat.is_info()) { - dgraph_cat.info() << "Sending into " << *node << " {\n"; - describe_data_verbose(dgraph_cat.info(false), state.get_attributes(), 2); - dgraph_cat.info(false) << "}\n"; - } - - if (node->is_of_type(DataNode::get_class_type())) { - DataNode *dnode = DCAST(DataNode, node); - - // Now let the data node process the data itself. - dnode->transmit_data(state.get_attributes()); - - if (dnode->get_spam_mode() && !has_spam_flag) { - // If the node we pass through has the spam flag set, then we'll - // set it on our current state, and insist that it gets through - // to all our children. - state.set_attribute(DataGraphTraversal::_spam_flag_type, - new IntDataAttribute); - has_spam_flag = true; - } - } - - if (has_spam_flag && !node->_children.empty() && - dgraph_cat.is_info()) { - dgraph_cat.info() << "Receiving from " << *node << " {\n"; - describe_data_verbose(dgraph_cat.info(false), state.get_attributes(), 2); - dgraph_cat.info(false) << "}\n"; - } - return true; -} +#include "dataGraphTraverser.h" //////////////////////////////////////////////////////////////////// @@ -90,7 +15,6 @@ reached_node(Node *node, AllAttributesWrapper &state, NullLevelState &) { // downwards. //////////////////////////////////////////////////////////////////// void traverse_data_graph(Node *root) { - DataGraphVisitor dgv; - df_traverse(root, dgv, AllAttributesWrapper(), - NullLevelState(), DataRelation::get_class_type()); + DataGraphTraverser dgt; + dgt.traverse(root); } diff --git a/panda/src/dgraph/dataGraphTraversal.h b/panda/src/dgraph/dataGraphTraversal.h index 15615c8cb7..21a6e966ee 100644 --- a/panda/src/dgraph/dataGraphTraversal.h +++ b/panda/src/dgraph/dataGraphTraversal.h @@ -17,46 +17,12 @@ // This is the main interface to the data graph. Traversing the data // graph transmits data down the graph--reading data from devices and // sending it to the DataNodes that want it. +// //////////////////////////////////////////////////////////////////// #include -#include -#include -#include -#include - - -//////////////////////////////////////////////////////////////////// -// Class : DataGraphTraversal -// Description : This is mainly a holder for the static -// _spam_flag_type TypeHandle, which is a registered -// NumericDataAttribute that keeps track of the state of -// the spam flag during data graph traversal. The class -// otherwise doesn't do anything useful, but see the -// traverse_data_graph() function, below. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA DataGraphTraversal { -public: - static void init_spam_flag(); - - static TypeHandle _spam_flag_type; -}; - - -//////////////////////////////////////////////////////////////////// -// Class : DataGraphVisitor -// Description : The TraverserVisitor to handle data graph traversals. -// This manages the spam flag, and may eventually handle -// merging of data from different parents into a single -// node. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA DataGraphVisitor : - public TraverserVisitor { -public: - bool reached_node(Node *node, AllAttributesWrapper &state, NullLevelState &); -}; - +class Node; //////////////////////////////////////////////////////////////////// // Function: traverse_data_graph diff --git a/panda/src/dgraph/dataGraphTraverser.I b/panda/src/dgraph/dataGraphTraverser.I new file mode 100644 index 0000000000..7442331398 --- /dev/null +++ b/panda/src/dgraph/dataGraphTraverser.I @@ -0,0 +1,46 @@ +// Filename: dataGraphTraverser.I +// Created by: drose (05Feb01) +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE DataGraphTraverser:: +DataGraphTraverser() { +} + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::traverse +// Access: Public +// Description: Fires off the traversal, beginning at the indicated +// node. +//////////////////////////////////////////////////////////////////// +INLINE void DataGraphTraverser:: +traverse(Node *node) { + NodeAttributes empty; + r_traverse(node, empty, false); + resume_all(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::traverse_below +// Access: Public +// Description: Fires off the traversal, beginning *below* the +// indicated node. The transmit_data() function is not +// called on the starting node; instead, the indicated +// data attributes are taken as the output of that node. +// +// If the node defines transmit_data_per_child(), that +// function is still called, once for each child as +// usual. +//////////////////////////////////////////////////////////////////// +INLINE void DataGraphTraverser:: +traverse_below(Node *node, const NodeAttributes &data) { + NodeAttributes copy = data; + r_traverse_below(node, copy, false); + resume_all(); +} diff --git a/panda/src/dgraph/dataGraphTraverser.cxx b/panda/src/dgraph/dataGraphTraverser.cxx new file mode 100644 index 0000000000..55a6bdd1ae --- /dev/null +++ b/panda/src/dgraph/dataGraphTraverser.cxx @@ -0,0 +1,223 @@ +// Filename: dataGraphTraverser.cxx +// Created by: drose (05Feb01) +// +//////////////////////////////////////////////////////////////////// + +#include "dataGraphTraverser.h" +#include "dataRelation.h" +#include "dataNode.h" +#include "config_dgraph.h" +#include "describe_data_verbose.h" + + + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::r_traverse +// Access: Private +// Description: The recursive implementation of traverse(). +//////////////////////////////////////////////////////////////////// +void DataGraphTraverser:: +r_traverse(Node *node, NodeAttributes &data, bool has_spam_mode) { + DataNode *data_node = (DataNode *)NULL; + if (node->is_of_type(DataNode::get_class_type())) { + DCAST_INTO_V(data_node, node); + +#ifndef NDEBUG + has_spam_mode = has_spam_mode || data_node->get_spam_mode(); +#endif + } + + int num_parents = node->get_num_parents(DataRelation::get_class_type()); + + if (num_parents > 1) { + // This node is multiply parented, so we must save it for later. + save(node, data, has_spam_mode, num_parents); + + } else { + + // Now ask the node to transmit its overall data. + if (data_node != (DataNode *)NULL) { +#ifndef NDEBUG + if (has_spam_mode && dgraph_cat.is_info()) { + dgraph_cat.info() << "Sending into " << *node << " {\n"; + describe_data_verbose(dgraph_cat.info(false), data, 2); + dgraph_cat.info(false) << "}\n"; + + } else if (dgraph_cat.is_spam()) { + dgraph_cat.spam() << "Sending into " << *node << " {\n"; + describe_data_verbose(dgraph_cat.spam(false), data, 2); + dgraph_cat.spam(false) << "}\n"; + } +#endif + + data_node->transmit_data(data); + } + + r_traverse_below(node, data, has_spam_mode); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::r_traverse_below +// Access: Private +// Description: Resumes the traversal below the indicated node, given +// the output from a previous call to +// Node::transmit_data(). +//////////////////////////////////////////////////////////////////// +void DataGraphTraverser:: +r_traverse_below(Node *node, NodeAttributes &data, bool has_spam_mode) { + DataNode *data_node = (DataNode *)NULL; + if (node->is_of_type(DataNode::get_class_type())) { + DCAST_INTO_V(data_node, node); + +#ifndef NDEBUG + has_spam_mode = has_spam_mode || data_node->get_spam_mode(); +#endif + } + + int num_children = node->get_num_children(DataRelation::get_class_type()); + + if (num_children > 0) { + // For the first n - 1 children we need to make a copy of our + // NodeAttributes for each one--this allows our children to modify + // the set freely without affecting its siblings. + + for (int i = 0; i < num_children - 1; i++) { + NodeAttributes copy = data; + if (data_node != (DataNode *)NULL) { + data_node->transmit_data_per_child(copy, i); + } + + NodeRelation *arc = + node->get_child(DataRelation::get_class_type(), i); + r_traverse(arc->get_child(), copy, has_spam_mode); + } + + // For the last child, we don't have to bother making a copy since + // no one cares any more. This is a slight optimization. + if (data_node != (DataNode *)NULL) { + data_node->transmit_data_per_child(data, num_children - 1); + } + + NodeRelation *arc = + node->get_child(DataRelation::get_class_type(), num_children - 1); + + if (dgraph_cat.is_spam()) { + dgraph_cat.spam() << "Traversing " << *arc << "\n"; + } + + r_traverse(arc->get_child(), data, has_spam_mode); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::save +// Access: Private +// Description: Saves the current state for later, until we have +// extracted the data from all the parents of this node. +// When the last parent is accounted for, resumes the +// traversal for this node and removes it from the saved +// queue. +//////////////////////////////////////////////////////////////////// +void DataGraphTraverser:: +save(Node *node, const NodeAttributes &data, bool has_spam_mode, + int num_parents) { + + States::iterator si; + si = _saved_states.find(node); + + if (si != _saved_states.end()) { + SavedState &state = (*si).second; + state._data.merge_from(state._data, data); + state._has_spam_mode = state._has_spam_mode || has_spam_mode; + state._num_parents_so_far++; + + if (dgraph_cat.is_spam()) { + dgraph_cat.spam() + << "Encountered " << *node << " with " << num_parents + << " parents; " << state._num_parents_so_far + << " processed so far.\n"; + } + + nassertv(state._num_parents_so_far <= num_parents); + if (state._num_parents_so_far == num_parents) { + // All parents are accounted for, so resume traversal! + resume(node, state); + _saved_states.erase(si); + } + return; + } + + // This node has not been encountered before, so save an entry for + // it. + if (dgraph_cat.is_spam()) { + dgraph_cat.spam() + << "Encountered " << *node << " with " << num_parents + << " parents.\n"; + } + + SavedState &state = _saved_states[node]; + state._data = data; + state._has_spam_mode = has_spam_mode; + state._num_parents_so_far = 1; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::resume +// Access: Private +// Description: Resumes traversal from a previously-saved state. +//////////////////////////////////////////////////////////////////// +void DataGraphTraverser:: +resume(Node *node, DataGraphTraverser::SavedState &state) { + DataNode *data_node = (DataNode *)NULL; + if (node->is_of_type(DataNode::get_class_type())) { + DCAST_INTO_V(data_node, node); + +#ifndef NDEBUG + if (state._has_spam_mode && dgraph_cat.is_info()) { + dgraph_cat.info() << "Sending into " << *node << " {\n"; + describe_data_verbose(dgraph_cat.info(false), state._data, 2); + dgraph_cat.info(false) << "}\n"; + + } else if (dgraph_cat.is_spam()) { + dgraph_cat.spam() << "Sending into " << *node << " {\n"; + describe_data_verbose(dgraph_cat.spam(false), state._data, 2); + dgraph_cat.spam(false) << "}\n"; + } +#endif + data_node->transmit_data(state._data); + } + + r_traverse_below(node, state._data, state._has_spam_mode); +} + +//////////////////////////////////////////////////////////////////// +// Function: DataGraphTraverser::resume_all +// Access: Private +// Description: Called after the traversal has completed, this +// resumes all of the unresumed saved states. There +// shouldn't actually be any such things, unless a node +// is multiply parented to a node outside of the data +// graph. +//////////////////////////////////////////////////////////////////// +void DataGraphTraverser:: +resume_all() { + while (!_saved_states.empty()) { + States::iterator si = _saved_states.begin(); + Node *node = (*si).first; + SavedState &state = (*si).second; + + dgraph_cat.warning() + << *node << " is parented both inside and outside of the data graph:\n"; + int num_parents = node->get_num_parents(DataRelation::get_class_type()); + for (int i = 0; i < num_parents; i++) { + NodeRelation *arc = node->get_parent(DataRelation::get_class_type(), i); + dgraph_cat.warning(false) + << " " << *arc << "\n"; + } + + resume(node, state); + _saved_states.erase(si); + } +} + diff --git a/panda/src/dgraph/dataGraphTraverser.h b/panda/src/dgraph/dataGraphTraverser.h new file mode 100644 index 0000000000..6697a7999a --- /dev/null +++ b/panda/src/dgraph/dataGraphTraverser.h @@ -0,0 +1,55 @@ +// Filename: dataGraphTraverser.h +// Created by: drose (05Feb01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef DATAGRAPHTRAVERSER_H +#define DATAGRAPHTRAVERSER_H + +#include + +#include + +class Node; + +//////////////////////////////////////////////////////////////////// +// Class : DataGraphTraverser +// Description : This class manages the traversal of the data graph, +// so that all data attributes generated by nodes in the +// graph are transmitted to nodes below them. +// +// A bit of logic is employed to ensure that if a node +// is assigned to two parents, the data from both +// parents is merged before passing it to the child. +// +// This class need not be exported from PANDA.DLL. +//////////////////////////////////////////////////////////////////// +class DataGraphTraverser { +public: + INLINE DataGraphTraverser(); + + INLINE void traverse(Node *node); + INLINE void traverse_below(Node *node, const NodeAttributes &data); + +private: + class SavedState { + public: + NodeAttributes _data; + bool _has_spam_mode; + int _num_parents_so_far; + }; + + void r_traverse(Node *node, NodeAttributes &data, bool has_spam_mode); + void r_traverse_below(Node *node, NodeAttributes &data, bool has_spam_mode); + void save(Node *node, const NodeAttributes &data, bool has_spam_mode, + int num_parents); + void resume(Node *node, SavedState &state); + void resume_all(); + + typedef map States; + States _saved_states; +}; + +#include "dataGraphTraverser.I" + +#endif diff --git a/panda/src/dgraph/dataNode.cxx b/panda/src/dgraph/dataNode.cxx index 2394c0a91c..edcd1292cc 100644 --- a/panda/src/dgraph/dataNode.cxx +++ b/panda/src/dgraph/dataNode.cxx @@ -16,6 +16,23 @@ DataNode:: DataNode(const string &name) : NamedNode(name) { _spam_mode = false; } + +//////////////////////////////////////////////////////////////////// +// Function: DataNode::transmit_data_per_child +// Access: Public, Virtual +// Description: Should be overridden in a derived class that wants to +// send a different data stream to each child. +// Normally, a node only overrides transmit_data(), +// which takes a set of input data attributes and +// generates a set of output data attributes. A node +// may also override transmit_data_per_child(), which is +// called after transmit_data(), once per child; this +// function may be used to send individual data +// attributes to each child. +//////////////////////////////////////////////////////////////////// +void DataNode:: +transmit_data_per_child(NodeAttributes &, int) { +} //////////////////////////////////////////////////////////////////// // Function: DataNode::set_spam_mode diff --git a/panda/src/dgraph/dataNode.h b/panda/src/dgraph/dataNode.h index 78818e4b77..55bb37a0b7 100644 --- a/panda/src/dgraph/dataNode.h +++ b/panda/src/dgraph/dataNode.h @@ -70,6 +70,9 @@ public: virtual void transmit_data(NodeAttributes &data)=0; + virtual void + transmit_data_per_child(NodeAttributes &data, int child_index); + PUBLISHED: void set_spam_mode(bool flag); bool get_spam_mode() const; diff --git a/panda/src/dgraph/describe_data_verbose.cxx b/panda/src/dgraph/describe_data_verbose.cxx index ba6e03ce07..3b9368940e 100644 --- a/panda/src/dgraph/describe_data_verbose.cxx +++ b/panda/src/dgraph/describe_data_verbose.cxx @@ -26,35 +26,32 @@ describe_data_verbose(ostream &out, const NodeAttributes &state, NodeAttributes::const_iterator nai; for (nai = state.begin(); nai != state.end(); ++nai) { - // We'll exclude the spam flag. No one wants to see that. - TypeHandle type = (*nai).first; - if (type != DataGraphTraversal::_spam_flag_type) { - const PT(NodeAttribute) &attrib = (*nai).second; - if (attrib != (NodeAttribute *)NULL) { - // Now extract the type name out of the type flag. - string actual_name = type.get_name(); - string::size_type underscore = actual_name.rfind('_'); - string name; - if (underscore == string::npos) { - // There was no underscore, so this name wasn't created via - // register_data_transition(). Huh. Well, that's legitimate - // (if unexpected), so just print the whole name. - name = actual_name; - } else { - // Assume that, if the name was created via - // register_data_transition(), the original name was the part - // before the last underscore. - name = actual_name.substr(0, underscore); - } - - indent(out, indent_level) << name; - if ((int)name.length() < data_indent_level) { - indent(out, data_indent_level - name.length()); - } else { - out << " "; - } - out << *attrib << "\n"; + const PT(NodeAttribute) &attrib = (*nai).second; + if (attrib != (NodeAttribute *)NULL) { + // Now extract the type name out of the type flag. + TypeHandle type = (*nai).first; + string actual_name = type.get_name(); + string::size_type underscore = actual_name.rfind('_'); + string name; + if (underscore == string::npos) { + // There was no underscore, so this name wasn't created via + // register_data_transition(). Huh. Well, that's legitimate + // (if unexpected), so just print the whole name. + name = actual_name; + } else { + // Assume that, if the name was created via + // register_data_transition(), the original name was the part + // before the last underscore. + name = actual_name.substr(0, underscore); } + + indent(out, indent_level) << name; + if ((int)name.length() < data_indent_level) { + indent(out, data_indent_level - name.length()); + } else { + out << " "; + } + out << *attrib << "\n"; } } } diff --git a/panda/src/dgraph/modifierButtonDataAttribute.I b/panda/src/dgraph/modifierButtonDataAttribute.I deleted file mode 100644 index ddfc4948c6..0000000000 --- a/panda/src/dgraph/modifierButtonDataAttribute.I +++ /dev/null @@ -1,56 +0,0 @@ -// Filename: modifierButtonDataAttribute.I -// Created by: drose (27Mar00) -// -//////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ModifierButtonDataAttribute:: -ModifierButtonDataAttribute() { -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ModifierButtonDataAttribute:: -ModifierButtonDataAttribute(const ModifierButtonDataAttribute ©) : - NodeAttribute(copy), - _mods(copy._mods) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::Copy Assignment Operator -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void ModifierButtonDataAttribute:: -operator = (const ModifierButtonDataAttribute ©) { - NodeAttribute::operator = (copy); - _mods = copy._mods; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::set_mods -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void ModifierButtonDataAttribute:: -set_mods(const ModifierButtons &mods) { - _mods = mods; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::set_mods -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE const ModifierButtons &ModifierButtonDataAttribute:: -get_mods() const { - return _mods; -} diff --git a/panda/src/dgraph/modifierButtonDataAttribute.cxx b/panda/src/dgraph/modifierButtonDataAttribute.cxx deleted file mode 100644 index 1ffc44d96b..0000000000 --- a/panda/src/dgraph/modifierButtonDataAttribute.cxx +++ /dev/null @@ -1,78 +0,0 @@ -// Filename: modifierButtonDataAttribute.cxx -// Created by: drose (27Mar00) -// -//////////////////////////////////////////////////////////////////// - -#include "modifierButtonDataAttribute.h" -#include "modifierButtonDataTransition.h" - -#include - -TypeHandle ModifierButtonDataAttribute::_type_handle; - - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::make_copy -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -NodeAttribute *ModifierButtonDataAttribute:: -make_copy() const { - return new ModifierButtonDataAttribute(*this); -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::make_initial -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -NodeAttribute *ModifierButtonDataAttribute:: -make_initial() const { - return new ModifierButtonDataAttribute; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::get_handle -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -TypeHandle ModifierButtonDataAttribute:: -get_handle() const { - return ModifierButtonDataTransition::get_class_type(); -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::output -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void ModifierButtonDataAttribute:: -output(ostream &out) const { - out << _mods; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::write -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -void ModifierButtonDataAttribute:: -write(ostream &out, int indent_level) const { - indent(out, indent_level) << _mods << "\n"; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataAttribute::internal_compare_to -// Access: Protected, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -int ModifierButtonDataAttribute:: -internal_compare_to(const NodeAttribute *other) const { - const ModifierButtonDataAttribute *ot; - DCAST_INTO_R(ot, other, false); - - if (_mods != ot->_mods) { - return (_mods < ot->_mods) ? -1 : 1; - } - return 0; -} diff --git a/panda/src/dgraph/modifierButtonDataAttribute.h b/panda/src/dgraph/modifierButtonDataAttribute.h deleted file mode 100644 index d792922fd6..0000000000 --- a/panda/src/dgraph/modifierButtonDataAttribute.h +++ /dev/null @@ -1,68 +0,0 @@ -// Filename: modifierButtonDataAttribute.h -// Created by: drose (27Mar00) -// -//////////////////////////////////////////////////////////////////// - -#ifndef MODIFIERBUTTONDATAATTRIBUTE_H -#define MODIFIERBUTTONDATAATTRIBUTE_H - -#include - -#include -#include - -class ModifierButtonDataTransition; - -//////////////////////////////////////////////////////////////////// -// Class : ModifierButtonDataAttribute -// Description : This data graph attribute stores the current state of -// some various modifier buttons (e.g. shift, control, -// alt, and the mouse buttons), as generated for -// instance by a GraphicsWindow. -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA ModifierButtonDataAttribute : public NodeAttribute { -public: - INLINE ModifierButtonDataAttribute(); - INLINE ModifierButtonDataAttribute(const ModifierButtonDataAttribute ©); - INLINE void operator = (const ModifierButtonDataAttribute ©); - -public: - INLINE void set_mods(const ModifierButtons &mods); - INLINE const ModifierButtons &get_mods() const; - - virtual NodeAttribute *make_copy() const; - virtual NodeAttribute *make_initial() const; - - virtual TypeHandle get_handle() const; - - virtual void output(ostream &out) const; - virtual void write(ostream &out, int indent_level = 0) const; - -protected: - virtual int internal_compare_to(const NodeAttribute *other) const; - -private: - ModifierButtons _mods; - -public: - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - NodeAttribute::init_type(); - register_type(_type_handle, "ModifierButtonDataAttribute", - NodeAttribute::get_class_type()); - } - -private: - static TypeHandle _type_handle; -friend class ModifierButtonDataTransition; -}; - -#include "modifierButtonDataAttribute.I" - -#endif diff --git a/panda/src/dgraph/modifierButtonDataTransition.I b/panda/src/dgraph/modifierButtonDataTransition.I deleted file mode 100644 index f9ee79e84e..0000000000 --- a/panda/src/dgraph/modifierButtonDataTransition.I +++ /dev/null @@ -1,34 +0,0 @@ -// Filename: modifierButtonDataTransition.I -// Created by: drose (27Mar00) -// -//////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ModifierButtonDataTransition:: -ModifierButtonDataTransition() { -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ModifierButtonDataTransition:: -ModifierButtonDataTransition(const ModifierButtonDataTransition ©) : - NodeTransition(copy) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::Copy Assignment Operator -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void ModifierButtonDataTransition:: -operator = (const ModifierButtonDataTransition ©) { - NodeTransition::operator = (copy); -} diff --git a/panda/src/dgraph/modifierButtonDataTransition.cxx b/panda/src/dgraph/modifierButtonDataTransition.cxx deleted file mode 100644 index 60d211e9f9..0000000000 --- a/panda/src/dgraph/modifierButtonDataTransition.cxx +++ /dev/null @@ -1,80 +0,0 @@ -// Filename: modifierButtonDataTransition.cxx -// Created by: drose (01Mar00) -// -//////////////////////////////////////////////////////////////////// - -#include "modifierButtonDataTransition.h" -#include "modifierButtonDataAttribute.h" - -TypeHandle ModifierButtonDataTransition::_type_handle; - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::make_copy -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -NodeTransition *ModifierButtonDataTransition:: -make_copy() const { - return new ModifierButtonDataTransition(*this); -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::make_attrib -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -NodeAttribute *ModifierButtonDataTransition:: -make_attrib() const { - return new ModifierButtonDataAttribute; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::compose -// Access: Public, Virtual -// Description: Returns a new transition that corresponds to the -// composition of this transition with the second -// transition (which must be of an equivalent type). -// This may return the same pointer as either source -// transition. Applying the transition returned from -// this function to an attribute attribute will produce -// the same effect as applying each transition -// separately. -//////////////////////////////////////////////////////////////////// -NodeTransition *ModifierButtonDataTransition:: -compose(const NodeTransition *) const { - return NULL; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::invert -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -NodeTransition *ModifierButtonDataTransition:: -invert() const { - return NULL; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::apply -// Access: Public, Virtual -// Description: Returns a new attribute (or possibly the same -// attribute) that represents the effect of applying this -// indicated transition to the indicated attribute. The -// source attribute may be NULL, indicating the initial -// attribute. -//////////////////////////////////////////////////////////////////// -NodeAttribute *ModifierButtonDataTransition:: -apply(const NodeAttribute *attrib) const { - return (NodeAttribute *)attrib; -} - -//////////////////////////////////////////////////////////////////// -// Function: ModifierButtonDataTransition::internal_compare_to -// Access: Protected, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -int ModifierButtonDataTransition:: -internal_compare_to(const NodeTransition *) const { - return 0; -} diff --git a/panda/src/dgraph/modifierButtonDataTransition.h b/panda/src/dgraph/modifierButtonDataTransition.h deleted file mode 100644 index 870eac6a49..0000000000 --- a/panda/src/dgraph/modifierButtonDataTransition.h +++ /dev/null @@ -1,54 +0,0 @@ -// Filename: modifierButtonDataTransition.h -// Created by: drose (01Mar00) -// -//////////////////////////////////////////////////////////////////// - -#ifndef MODIFIERBUTTONDATATRANSITION_H -#define MODIFIERBUTTONDATATRANSITION_H - -#include - -#include - -//////////////////////////////////////////////////////////////////// -// Class : ModifierButtonDataTransition -// Description : -//////////////////////////////////////////////////////////////////// -class EXPCL_PANDA ModifierButtonDataTransition : public NodeTransition { -public: - INLINE ModifierButtonDataTransition(); - INLINE ModifierButtonDataTransition(const ModifierButtonDataTransition ©); - INLINE void operator = (const ModifierButtonDataTransition ©); - -public: - virtual NodeTransition *make_copy() const; - virtual NodeAttribute *make_attrib() const; - - virtual NodeTransition *compose(const NodeTransition *other) const; - virtual NodeTransition *invert() const; - virtual NodeAttribute *apply(const NodeAttribute *attrib) const; - -protected: - virtual int internal_compare_to(const NodeTransition *other) const; - -public: - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - NodeTransition::init_type(); - register_type(_type_handle, "ModifierButtonDataTransition", - NodeTransition::get_class_type()); - } - -private: - static TypeHandle _type_handle; -}; - -#include "modifierButtonDataTransition.I" - -#endif diff --git a/panda/src/display/graphicsWindow.I b/panda/src/display/graphicsWindow.I index e5b5cdb873..d1428e10cf 100644 --- a/panda/src/display/graphicsWindow.I +++ b/panda/src/display/graphicsWindow.I @@ -134,34 +134,6 @@ has_keyboard(int device) const { return _input_devices[device].has_keyboard(); } -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::get_modifier_buttons -// Access: Public -// Description: Returns the set of ModifierButtons currently being -// monitored for the nth input device. -//////////////////////////////////////////////////////////////////// -INLINE const ModifierButtons &GraphicsWindow:: -get_modifier_buttons(int device) const { - nassertr(device >= 0 && device < (int)_input_devices.size(), - *(new ModifierButtons)); - return _input_devices[device].get_modifier_buttons(); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::set_modifier_buttons -// Access: Public -// Description: Changes the set of ModifierButtons that will be -// monitored for the nth input device. It is -// recommended that you first retrieve the existing set -// via get_modifier_buttons(), so that any current -// button state will not be lost. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindow:: -set_modifier_buttons(int device, const ModifierButtons &mods) { - nassertv(device >= 0 && device < (int)_input_devices.size()); - _input_devices[device].set_modifier_buttons(mods); -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsWindow::get_mouse_data // Access: Public diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index b74d35c139..b6b225fe4e 100644 --- a/panda/src/display/graphicsWindow.h +++ b/panda/src/display/graphicsWindow.h @@ -133,9 +133,6 @@ PUBLISHED: INLINE bool has_pointer(int device) const; INLINE bool has_keyboard(int device) const; - INLINE const ModifierButtons &get_modifier_buttons(int device) const; - INLINE void set_modifier_buttons(int device, const ModifierButtons &mods); - public: INLINE const MouseData &get_mouse_data(int device) const; INLINE bool has_button_event(int device) const; diff --git a/panda/src/display/graphicsWindowInputDevice.I b/panda/src/display/graphicsWindowInputDevice.I index d054936b89..f60d465726 100644 --- a/panda/src/display/graphicsWindowInputDevice.I +++ b/panda/src/display/graphicsWindowInputDevice.I @@ -44,31 +44,6 @@ get_mouse_data() const { return _mouse_data; } -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::get_modifier_buttons -// Access: Public -// Description: Returns the set of ModifierButtons currently being -// monitored for the nth input device. -//////////////////////////////////////////////////////////////////// -INLINE const ModifierButtons &GraphicsWindowInputDevice:: -get_modifier_buttons() const { - return _mods; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindowInputDevice::set_modifier_buttons -// Access: Public -// Description: Changes the set of ModifierButtons that will be -// monitored for the nth input device. It is -// recommended that you first retrieve the existing set -// via get_modifier_buttons(), so that any current -// button state will not be lost. -//////////////////////////////////////////////////////////////////// -INLINE void GraphicsWindowInputDevice:: -set_modifier_buttons(const ModifierButtons &mods) { - _mods = mods; -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsWindowInputDevice::set_pointer_in_window // Access: Public diff --git a/panda/src/display/graphicsWindowInputDevice.cxx b/panda/src/display/graphicsWindowInputDevice.cxx index 2f38e16dc5..a6be5e6ea1 100644 --- a/panda/src/display/graphicsWindowInputDevice.cxx +++ b/panda/src/display/graphicsWindowInputDevice.cxx @@ -29,16 +29,6 @@ GraphicsWindowInputDevice(const string &name, int flags) : _name(name), _flags(flags) { - // We'll define the mouse buttons and the traditional modifier keys - // as the default modifiers. Individual GraphicsWindows can change - // this if they want. - - _mods.add_button(MouseButton::one()); - _mods.add_button(MouseButton::two()); - _mods.add_button(MouseButton::three()); - _mods.add_button(KeyboardButton::shift()); - _mods.add_button(KeyboardButton::control()); - _mods.add_button(KeyboardButton::alt()); } //////////////////////////////////////////////////////////////////// @@ -85,7 +75,6 @@ GraphicsWindowInputDevice(const GraphicsWindowInputDevice ©) : _name(copy._name), _flags(copy._flags), _mouse_data(copy._mouse_data), - _mods(copy._mods), _button_events(copy._button_events) { } @@ -100,7 +89,6 @@ operator = (const GraphicsWindowInputDevice ©) { _name = copy._name; _flags = copy._flags; _mouse_data = copy._mouse_data; - _mods = copy._mods; _button_events = copy._button_events; } @@ -147,8 +135,7 @@ get_button_event() { //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: button_down(ButtonHandle button) { - _button_events.push_back(ButtonEvent(button, true, _mods)); - _mods.button_down(button); + _button_events.push_back(ButtonEvent(button, true)); } //////////////////////////////////////////////////////////////////// @@ -158,6 +145,5 @@ button_down(ButtonHandle button) { //////////////////////////////////////////////////////////////////// void GraphicsWindowInputDevice:: button_up(ButtonHandle button) { - _mods.button_up(button); - _button_events.push_back(ButtonEvent(button, false, _mods)); + _button_events.push_back(ButtonEvent(button, false)); } diff --git a/panda/src/display/graphicsWindowInputDevice.h b/panda/src/display/graphicsWindowInputDevice.h index 71f04aae44..01d6f5d6e8 100644 --- a/panda/src/display/graphicsWindowInputDevice.h +++ b/panda/src/display/graphicsWindowInputDevice.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -41,8 +40,6 @@ public: INLINE bool has_keyboard() const; INLINE const MouseData &get_mouse_data() const; - INLINE const ModifierButtons &get_modifier_buttons() const; - INLINE void set_modifier_buttons(const ModifierButtons &mods); bool has_button_event() const; ButtonEvent get_button_event(); @@ -73,7 +70,6 @@ private: string _name; int _flags; MouseData _mouse_data; - ModifierButtons _mods; ButtonEvents _button_events; }; diff --git a/panda/src/framework/framework.cxx b/panda/src/framework/framework.cxx index 4e100d9d3e..0ffc7f9577 100644 --- a/panda/src/framework/framework.cxx +++ b/panda/src/framework/framework.cxx @@ -1048,7 +1048,10 @@ int framework_main(int argc, char *argv[]) { PT(Transform2SG) tball2cam = new Transform2SG("tball2cam"); tball2cam->set_arc(arc1); new DataRelation(trackball, tball2cam); - new DataRelation(drive_interface, tball2cam); + + PT(Transform2SG) drive2cam = new Transform2SG("drive2cam"); + drive2cam->set_arc(arc1); + new DataRelation(drive_interface, drive2cam); // Create a ButtonThrower to throw events from the keyboard. PT(ButtonThrower) et = new ButtonThrower("kb-events"); diff --git a/panda/src/graph/nodeAttribute.cxx b/panda/src/graph/nodeAttribute.cxx index d991d6534c..b082f3eddf 100644 --- a/panda/src/graph/nodeAttribute.cxx +++ b/panda/src/graph/nodeAttribute.cxx @@ -9,6 +9,20 @@ TypeHandle NodeAttribute::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: NodeAttribute::merge +// Access: Public, Virtual +// Description: Attempts to merge this attribute with the other one, +// if that makes sense to do. Returns a new +// NodeAttribute pointer that represents the merge, or +// if the merge is not possible, returns the "other" +// pointer unchanged (which is the result of the merge). +//////////////////////////////////////////////////////////////////// +NodeAttribute *NodeAttribute:: +merge(const NodeAttribute *other) const { + return (NodeAttribute *)other; +} + //////////////////////////////////////////////////////////////////// // Function: NodeAttribute::output // Access: Public, Virtual diff --git a/panda/src/graph/nodeAttribute.h b/panda/src/graph/nodeAttribute.h index ba7a4cea82..14961859ff 100644 --- a/panda/src/graph/nodeAttribute.h +++ b/panda/src/graph/nodeAttribute.h @@ -66,6 +66,8 @@ public: virtual TypeHandle get_handle() const=0; + virtual NodeAttribute *merge(const NodeAttribute *other) const; + PUBLISHED: virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; diff --git a/panda/src/graph/nodeAttributes.cxx b/panda/src/graph/nodeAttributes.cxx index 479af92c90..576e33f723 100644 --- a/panda/src/graph/nodeAttributes.cxx +++ b/panda/src/graph/nodeAttributes.cxx @@ -221,6 +221,35 @@ apply_from(const NodeAttributes &other, const NodeTransitionCache &trans) { } } +//////////////////////////////////////////////////////////////////// +// Function: NodeAttributes::merge_from +// Access: Public +// Description: Computes the union of the two NodeAttributes sets and +// stores the result in this object (which may be the +// same object as either of the two sources). If a +// given attribute is set in both sources (and cannot be +// union sensibly), the one from the second source +// overrides. +//////////////////////////////////////////////////////////////////// +void NodeAttributes:: +merge_from(const NodeAttributes &a, const NodeAttributes &b) { + if (&a == this && b.is_empty()) { + // Trivial do-nothing case. + + } else if (&b == this && a.is_empty()) { + // Trivial do-nothing case. + + } else { + Attributes temp; + + tmap_merge_union(a._attributes.begin(), a._attributes.end(), + b._attributes.begin(), b._attributes.end(), + inserter(temp, temp.begin())); + + _attributes.swap(temp); + } +} + //////////////////////////////////////////////////////////////////// // Function: NodeAttributes::output diff --git a/panda/src/graph/nodeAttributes.h b/panda/src/graph/nodeAttributes.h index bed8163a75..b46063f34f 100644 --- a/panda/src/graph/nodeAttributes.h +++ b/panda/src/graph/nodeAttributes.h @@ -68,7 +68,9 @@ public: void apply_from(const NodeAttributes &other, const NodeTransitionCache &trans); -public: + void merge_from(const NodeAttributes &a, const NodeAttributes &b); + +PUBLISHED: void output(ostream &out) const; void write(ostream &out, int indent_level = 0) const; diff --git a/panda/src/graph/nodeTransitionCache.cxx b/panda/src/graph/nodeTransitionCache.cxx index e31837b8d4..ccbd96b945 100644 --- a/panda/src/graph/nodeTransitionCache.cxx +++ b/panda/src/graph/nodeTransitionCache.cxx @@ -252,9 +252,9 @@ store_to(const NodeTransitionCache *a, NodeRelation *arc, // And now actually add them. NodeTransitions temp; - tmap_union(nt._transitions.begin(), nt._transitions.end(), - a->_cache.begin(), a->_cache.end(), - inserter(temp._transitions, temp._transitions.begin())); + tmap_override_union(nt._transitions.begin(), nt._transitions.end(), + a->_cache.begin(), a->_cache.end(), + inserter(temp._transitions, temp._transitions.begin())); nt._transitions.swap(temp._transitions); } @@ -281,9 +281,9 @@ c_union(const NodeTransitionCache *a, const NodeTransitionCache *b) { // Neither is empty. Build and return a new list. NodeTransitionCache *result = new NodeTransitionCache; - tmap_union(a->_cache.begin(), a->_cache.end(), - b->_cache.begin(), b->_cache.end(), - inserter(result->_cache, result->_cache.begin())); + tmap_override_union(a->_cache.begin(), a->_cache.end(), + b->_cache.begin(), b->_cache.end(), + inserter(result->_cache, result->_cache.begin())); return result; } diff --git a/panda/src/graph/nodeTransitions.cxx b/panda/src/graph/nodeTransitions.cxx index 576b3e6fc1..1b3332c02b 100644 --- a/panda/src/graph/nodeTransitions.cxx +++ b/panda/src/graph/nodeTransitions.cxx @@ -170,9 +170,9 @@ clear() { void NodeTransitions:: copy_transitions_from(const NodeTransitions &other) { Transitions temp; - tmap_union(_transitions.begin(), _transitions.end(), - other._transitions.begin(), other._transitions.end(), - inserter(temp, temp.begin())); + tmap_override_union(_transitions.begin(), _transitions.end(), + other._transitions.begin(), other._transitions.end(), + inserter(temp, temp.begin())); _transitions.swap(temp); } diff --git a/panda/src/graph/setTransitionHelpers.I b/panda/src/graph/setTransitionHelpers.I index 870d2403d9..5f580aad77 100644 --- a/panda/src/graph/setTransitionHelpers.I +++ b/panda/src/graph/setTransitionHelpers.I @@ -37,7 +37,7 @@ tmap_get_interest(InputIterator1 first1, InputIterator1 last1, } //////////////////////////////////////////////////////////////////// -// Function: tmap_union +// Function: tmap_override_union // Description: Accepts two NodeTransition or NodeAttribute maps, and // builds a new map which is the union of the first two. // If an element appears in both maps, the entry from @@ -45,9 +45,9 @@ tmap_get_interest(InputIterator1 first1, InputIterator1 last1, //////////////////////////////////////////////////////////////////// template OutputIterator -tmap_union(InputIterator1 first1, InputIterator1 last1, - InputIterator2 first2, InputIterator2 last2, - OutputIterator result) { +tmap_override_union(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) { while (first1 != last1 && first2 != last2) { if ((*first1).first < (*first2).first) { *result = *first1; @@ -79,6 +79,50 @@ tmap_union(InputIterator1 first1, InputIterator1 last1, return result; } +//////////////////////////////////////////////////////////////////// +// Function: tmap_merge_union +// Description: Accepts two NodeAttribute maps, and builds a new map +// which is the union of the first two. If an element +// appears in both maps, the two are merged, preferring +// the second. +//////////////////////////////////////////////////////////////////// +template +OutputIterator +tmap_merge_union(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + OutputIterator result) { + while (first1 != last1 && first2 != last2) { + if ((*first1).first < (*first2).first) { + *result = *first1; + ++first1; + ++result; + } else if ((*first2).first < (*first1).first) { + *result = *first2; + ++first2; + ++result; + } else { + PT(NodeAttribute) c = (*first1).second->merge((*first2).second); + *result = pair((*first1).first, c); + ++first1; + ++first2; + ++result; + } + } + + while (first1 != last1) { + *result = *first1; + ++first1; + ++result; + } + + while (first2 != last2) { + *result = *first2; + ++first2; + ++result; + } + return result; +} + //////////////////////////////////////////////////////////////////// // Function: tmap_arc_union // Description: As above, but updates the transitions on the way to diff --git a/panda/src/putil/buttonEvent.I b/panda/src/putil/buttonEvent.I index 7bb9c6f72a..c574d7dfd0 100644 --- a/panda/src/putil/buttonEvent.I +++ b/panda/src/putil/buttonEvent.I @@ -28,19 +28,6 @@ ButtonEvent(ButtonHandle button, bool down) : { } -//////////////////////////////////////////////////////////////////// -// Function: ButtonEvent::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ButtonEvent:: -ButtonEvent(ButtonHandle button, bool down, ModifierButtons mods) : - _button(button), - _down(down), - _mods(mods) -{ -} - //////////////////////////////////////////////////////////////////// // Function: ButtonEvent::Copy Constructor // Access: Public @@ -49,8 +36,7 @@ ButtonEvent(ButtonHandle button, bool down, ModifierButtons mods) : INLINE ButtonEvent:: ButtonEvent(const ButtonEvent ©) : _button(copy._button), - _down(copy._down), - _mods(copy._mods) + _down(copy._down) { } @@ -63,7 +49,6 @@ INLINE void ButtonEvent:: operator = (const ButtonEvent ©) { _button = copy._button; _down = copy._down; - ((ModifierButtons &)_mods) = copy._mods; } //////////////////////////////////////////////////////////////////// @@ -74,8 +59,7 @@ operator = (const ButtonEvent ©) { INLINE bool ButtonEvent:: operator == (const ButtonEvent &other) const { return (_button == other._button && - _down == other._down && - _mods == other._mods); + _down == other._down); } //////////////////////////////////////////////////////////////////// @@ -99,9 +83,5 @@ operator < (const ButtonEvent &other) const { return _button < other._button; } - if (_down != other._down) { - return _down < other._down; - } - - return _mods < other._mods; + return _down < other._down; } diff --git a/panda/src/putil/buttonEvent.cxx b/panda/src/putil/buttonEvent.cxx index e0eca2c1ba..3d7342e8f0 100644 --- a/panda/src/putil/buttonEvent.cxx +++ b/panda/src/putil/buttonEvent.cxx @@ -18,5 +18,4 @@ output(ostream &out) const { } else { out << " up"; } - out << " with " << _mods; } diff --git a/panda/src/putil/buttonEvent.h b/panda/src/putil/buttonEvent.h index 264d2c7340..76098751c5 100644 --- a/panda/src/putil/buttonEvent.h +++ b/panda/src/putil/buttonEvent.h @@ -9,19 +9,16 @@ #include #include "buttonHandle.h" -#include "modifierButtons.h" //////////////////////////////////////////////////////////////////// // Class : ButtonEvent // Description : Records a transition of one button from up to down or -// vice-versa, as well as an optional recording of some -// ModifierButtons that were being tracked at the time. +// vice-versa. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA ButtonEvent { public: INLINE ButtonEvent(); INLINE ButtonEvent(ButtonHandle button, bool down); - INLINE ButtonEvent(ButtonHandle button, bool down, ModifierButtons mods); INLINE ButtonEvent(const ButtonEvent ©); INLINE void operator = (const ButtonEvent ©); @@ -33,7 +30,6 @@ public: ButtonHandle _button; bool _down; - const ModifierButtons _mods; }; INLINE ostream &operator << (ostream &out, const ButtonEvent &be) { diff --git a/panda/src/putil/modifierButtons.I b/panda/src/putil/modifierButtons.I index a22a48c60b..52cabe9e64 100644 --- a/panda/src/putil/modifierButtons.I +++ b/panda/src/putil/modifierButtons.I @@ -75,6 +75,21 @@ get_button(int index) const { return _button_list[index]; } +//////////////////////////////////////////////////////////////////// +// Function: ModifierButtons::add_event +// Access: Public +// Description: Calls button_down() or button_up(), as appropriate, +// according to the indicated ButtonEvent. +//////////////////////////////////////////////////////////////////// +INLINE bool ModifierButtons:: +add_event(const ButtonEvent &event) { + if (event._down) { + return button_down(event._button); + } else { + return button_up(event._button); + } +} + //////////////////////////////////////////////////////////////////// // Function: ModifierButtons::is_down // Access: Public @@ -86,3 +101,14 @@ is_down(int index) const { nassertr(index >= 0 && index < (int)_button_list.size(), false); return ((_state & ((BitmaskType)1 << index)) != 0); } + +//////////////////////////////////////////////////////////////////// +// Function: ModifierButtons::is_any_down +// Access: Public +// Description: Returns true if any of the tracked button are known +// to be down, or false if all of them are up. +//////////////////////////////////////////////////////////////////// +INLINE bool ModifierButtons:: +is_any_down() const { + return _state != 0; +} diff --git a/panda/src/putil/modifierButtons.cxx b/panda/src/putil/modifierButtons.cxx index d2b7488f09..26b595dedc 100644 --- a/panda/src/putil/modifierButtons.cxx +++ b/panda/src/putil/modifierButtons.cxx @@ -129,16 +129,19 @@ remove_button(ButtonHandle button) { // If the given button is one of the buttons that is // currently being monitored, this will update the // internal state appropriately; otherwise, it will do -// nothing. +// nothing. Returns true if the button is one that was +// monitored, or false otherwise. //////////////////////////////////////////////////////////////////// -void ModifierButtons:: +bool ModifierButtons:: button_down(ButtonHandle button) { for (int i = 0; i < (int)_button_list.size(); i++) { if (button == _button_list[i]) { _state |= ((BitmaskType)1 << i); - return; + return true; } } + + return false; } //////////////////////////////////////////////////////////////////// @@ -148,16 +151,19 @@ button_down(ButtonHandle button) { // If the given button is one of the buttons that is // currently being monitored, this will update the // internal state appropriately; otherwise, it will do -// nothing. +// nothing. Returns true if the button is one that was +// monitored, or false otherwise. //////////////////////////////////////////////////////////////////// -void ModifierButtons:: +bool ModifierButtons:: button_up(ButtonHandle button) { for (int i = 0; i < (int)_button_list.size(); i++) { if (button == _button_list[i]) { _state &= ~((BitmaskType)1 << i); - return; + return true; } } + + return false; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/modifierButtons.h b/panda/src/putil/modifierButtons.h index 9fa037d3fc..9133c22089 100644 --- a/panda/src/putil/modifierButtons.h +++ b/panda/src/putil/modifierButtons.h @@ -10,6 +10,7 @@ #include "buttonHandle.h" #include "pointerToArray.h" +#include "buttonEvent.h" //////////////////////////////////////////////////////////////////// // Class : ModifierButtons @@ -18,7 +19,7 @@ // known to be down or up. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA ModifierButtons { -public: +PUBLISHED: ModifierButtons(); ModifierButtons(const ModifierButtons ©); ~ModifierButtons(); @@ -35,11 +36,13 @@ public: INLINE int get_num_buttons() const; INLINE ButtonHandle get_button(int index) const; - void button_down(ButtonHandle button); - void button_up(ButtonHandle button); + bool button_down(ButtonHandle button); + bool button_up(ButtonHandle button); + INLINE bool add_event(const ButtonEvent &event); bool is_down(ButtonHandle button) const; INLINE bool is_down(int index) const; + INLINE bool is_any_down() const; void output(ostream &out) const; void write(ostream &out) const; diff --git a/panda/src/tform/Sources.pp b/panda/src/tform/Sources.pp index 67a7ffcc73..7bb5ec9111 100644 --- a/panda/src/tform/Sources.pp +++ b/panda/src/tform/Sources.pp @@ -9,6 +9,7 @@ #define SOURCES \ buttonThrower.cxx buttonThrower.h config_tform.cxx config_tform.h \ + dataValve.I dataValve.cxx dataValve.h \ driveInterface.cxx driveInterface.h mouseWatcher.I mouseWatcher.cxx \ mouseWatcher.h mouseWatcherRegion.I mouseWatcherRegion.cxx \ mouseWatcherRegion.h planarSlider.cxx planarSlider.h trackball.cxx \ @@ -16,7 +17,8 @@ transform2sg.cxx transform2sg.h #define INSTALL_HEADERS \ - buttonThrower.h driveInterface.h mouseWatcher.I mouseWatcher.h \ + buttonThrower.h dataValve.I dataValve.h \ + driveInterface.h mouseWatcher.I mouseWatcher.h \ mouseWatcherRegion.I mouseWatcherRegion.h planarSlider.h \ trackball.h transform2sg.h diff --git a/panda/src/tform/buttonThrower.cxx b/panda/src/tform/buttonThrower.cxx index d28b994614..4c78650721 100644 --- a/panda/src/tform/buttonThrower.cxx +++ b/panda/src/tform/buttonThrower.cxx @@ -86,9 +86,14 @@ get_modifier_buttons() const { // be empty, and the ButtonThrower will therefore ignore // all ModifierButtons attached to the key events, but // if one or more buttons have been added to this set, -// and those modifier buttons are set on the button -// event, then the event name will be prepended with the -// names of the modifier buttons. +// then the event name will be prepended with the names +// of the modifier buttons. +// +// It is recommended that you change this setting by +// first calling get_modifier_buttons(), making +// adjustments, and passing the new value to +// set_modifier_buttons(). This way the current state +// of the modifier buttons will not be lost. //////////////////////////////////////////////////////////////////// void ButtonThrower:: set_modifier_buttons(const ModifierButtons &mods) { @@ -110,20 +115,24 @@ transmit_data(NodeAttributes &data) { for (bi = b->begin(); bi != b->end(); ++bi) { const ButtonEvent &be = (*bi); string event_name = _prefix + be._button.get_name(); - if (!be._down) { - event_name += "-up"; - - } else { - // We only prepend modifier names on the button-down events. - string prepend; - - for (int i = 0; i < _mods.get_num_buttons(); i++) { - ButtonHandle modifier = _mods.get_button(i); - if (be._mods.is_down(modifier)) { - prepend += modifier.get_name() + "-"; + if (be._down) { + if (!_mods.button_down(be._button)) { + // We only prepend modifier names on the button-down events, + // and only for buttons which are not themselves modifiers. + string prepend; + + for (int i = 0; i < _mods.get_num_buttons(); i++) { + ButtonHandle modifier = _mods.get_button(i); + if (_mods.is_down(modifier)) { + prepend += modifier.get_name() + "-"; + } } + event_name = prepend + event_name; } - event_name = prepend + event_name; + + } else { + _mods.button_up(be._button); + event_name += "-up"; } throw_event(event_name); diff --git a/panda/src/tform/config_tform.cxx b/panda/src/tform/config_tform.cxx index 9136ca7670..ddefa1823a 100644 --- a/panda/src/tform/config_tform.cxx +++ b/panda/src/tform/config_tform.cxx @@ -4,6 +4,8 @@ //////////////////////////////////////////////////////////////////// #include "config_tform.h" + +#include "dataValve.h" #include "driveInterface.h" #include "buttonThrower.h" #include "mouseWatcher.h" @@ -30,6 +32,7 @@ const double drive_horizontal_ramp_up_time = config_tform.GetDouble("drive-horiz const double drive_horizontal_ramp_down_time = config_tform.GetDouble("drive-horizontal-ramp-down-time", 0.0); ConfigureFn(config_tform) { + DataValve::init_type(); DriveInterface::init_type(); ButtonThrower::init_type(); MouseWatcher::init_type(); diff --git a/panda/src/tform/dataValve.I b/panda/src/tform/dataValve.I new file mode 100644 index 0000000000..197aab7676 --- /dev/null +++ b/panda/src/tform/dataValve.I @@ -0,0 +1,126 @@ +// Filename: dataValve.I +// Created by: drose (05Feb01) +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Control::Constructor +// Access: Published +// Description: A unique Control can be assigned to each child of the +// DataValve, or the same Control may be shared between +// different children as desired. Each Control may be +// explicitly set on or off to enable or disable all +// data flow to that child, respectively; it may also be +// set to a "buttons" state, in which it enables or +// disables data flow to the child based on the current +// state of the modifier buttons as held by the user. +// +// In addition to being assigned to control all data to +// a particular child, a particular Control may be set +// to control only data of a particular type to a +// particular child. See set_control() and +// set_fine_control() on DataValve. +//////////////////////////////////////////////////////////////////// +INLINE DataValve::Control:: +Control() { + _state = S_on; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Control::set_on +// Access: Published +// Description: Sets the state on this particular Control to be on +// until further notice. Child nodes guarded by this +// Control will receive data. +//////////////////////////////////////////////////////////////////// +INLINE void DataValve::Control:: +set_on() { + _state = S_on; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Control::set_off +// Access: Published +// Description: Sets the state on this particular Control to be off +// until further notice. Child nodes guarded by this +// Control will not receive data. +//////////////////////////////////////////////////////////////////// +INLINE void DataValve::Control:: +set_off() { + _state = S_off; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Control::set_buttons +// Access: Published +// Description: Sets the state on this particular Control to be +// dependent on the current set of buttons being held +// down by the user. The ModifierButtons object here +// must exactly match the ModifierButtons object set on +// the DataValve in order and number of buttons. +// +// The best way to generate the ModifierButtons list is +// to create a new ModifierButtons based on the value +// returned by DataValve::get_modifier_buttons(), then +// explicitly call button_up() and button_down() on each +// button that you want to be up or down. +//////////////////////////////////////////////////////////////////// +INLINE void DataValve::Control:: +set_buttons(const ModifierButtons &mods) { + _state = S_buttons; + _mods = mods; +} + + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::set_default_control +// Access: Public +// Description: Sets the Control that will apply to each child that +// does not have a particular control set via +// set_control(). +//////////////////////////////////////////////////////////////////// +INLINE void DataValve:: +set_default_control(DataValve::Control *control) { + _default_control = control; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::get_default_control +// Access: Public +// Description: Returns the Control that will apply to each child +// that does not have a particular control set via +// set_control(). +//////////////////////////////////////////////////////////////////// +INLINE DataValve::Control *DataValve:: +get_default_control() const { + return _default_control; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::set_modifier_buttons +// Access: Public +// Description: Specifies the set of buttons that the DataValve will +// monitor as modifier buttons. The exact same set of +// ModifierButtons must be specified on the DataValve as +// well as on all of its Controls in order to +// successfully use modifier buttons to switch the +// valves automatically. +// +// This need not match the set of ModifierButtons set on +// the window, but it may be less confusing if it does. +//////////////////////////////////////////////////////////////////// +INLINE void DataValve:: +set_modifier_buttons(const ModifierButtons &mods) { + _mods = mods; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::get_modifier_buttons +// Access: Public +// Description: Returns the set of ModifierButtons currently being +// monitored. See set_modifier_buttons(). +//////////////////////////////////////////////////////////////////// +INLINE const ModifierButtons &DataValve:: +get_modifier_buttons() const { + return _mods; +} diff --git a/panda/src/tform/dataValve.cxx b/panda/src/tform/dataValve.cxx new file mode 100644 index 0000000000..7c92519941 --- /dev/null +++ b/panda/src/tform/dataValve.cxx @@ -0,0 +1,369 @@ +// Filename: dataValve.cxx +// Created by: drose (05Feb01) +// +//////////////////////////////////////////////////////////////////// + +#include "dataValve.h" + +#include +#include +#include +#include + +TypeHandle DataValve::_type_handle; + +TypeHandle DataValve::_button_events_type; + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Control::is_on +// Access: Published +// Description: Returns true if the indicated Control is currently +// on, given the particular DataNode it applies to. +// (The DataNode is necessary to determine the current +// state of the ModiferButtons. +//////////////////////////////////////////////////////////////////// +bool DataValve::Control:: +is_on(const DataValve &valve) const { + switch (_state) { + case S_on: + return true; + + case S_off: + return false; + + case S_buttons: + return _mods == valve.get_modifier_buttons(); + } + + // Invalid state. + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +DataValve:: +DataValve(const string &name) : DataNode(name) { + _default_control = new Control; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +DataValve:: +~DataValve() { +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::set_control +// Access: Published +// Description: Sets an overall Control on the indicated child node. +// The nth child of this node, zero-based, will receive +// data only while the indicated Control is on. This +// affects all types of data that is not specifically +// mentioned by set_fine_control(). +//////////////////////////////////////////////////////////////////// +void DataValve:: +set_control(int child_index, Control *control) { + ensure_child_index(child_index); + nassertv(child_index >= 0 && child_index < (int)_controls.size()); + _controls[child_index]._control = control; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::clear_control +// Access: Published +// Description: Removes the overall Control, as well as all fine +// controls, from the indicated child node. The +// indicated child will now be affected only by the +// default control. See set_control() and +// set_fine_control(). +//////////////////////////////////////////////////////////////////// +void DataValve:: +clear_control(int child_index) { + nassertv(child_index >= 0); + if (child_index < (int)_controls.size()) { + _controls[child_index]._control.clear(); + _controls[child_index]._fine_controls.clear(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::has_control +// Access: Published +// Description: Returns true if the indicated child has a particular +// Control set, or if it has *any* fine controls set. +// If this returns false, the child is controlled only +// by the default control. See set_control() and +// set_fine_control(). +//////////////////////////////////////////////////////////////////// +bool DataValve:: +has_control(int child_index) const { + nassertr(child_index >= 0, false); + if (child_index < (int)_controls.size()) { + return + !_controls[child_index]._control.is_null() || + !_controls[child_index]._fine_controls.empty(); + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::get_control +// Access: Published +// Description: Returns the control that has been set for the +// indicated child, or NULL if no control has been set +// (which implies the default control is in affect for +// the indicated child). Note that it is possible for +// this function to return NULL even if has_control(), +// above, returned true, since a fine control may have +// been set without setting a particular general +// control. +//////////////////////////////////////////////////////////////////// +DataValve::Control *DataValve:: +get_control(int child_index) const { + nassertr(child_index >= 0, NULL); + if (child_index < (int)_controls.size()) { + return _controls[child_index]._control; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::set_fine_control +// Access: Published +// Description: Sets the "fine" control for the indicated child index +// and the indicated data type. This overrides the +// control set by set_control() for this child, but only +// for data of this type. This can be used to send +// data of different types to different children. +//////////////////////////////////////////////////////////////////// +void DataValve:: +set_fine_control(int child_index, TypeHandle data_type, Control *control) { + ensure_child_index(child_index); + nassertv(child_index >= 0 && child_index < (int)_controls.size()); + _controls[child_index]._fine_controls[data_type] = control; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::clear_fine_control +// Access: Published +// Description: Removes the particular fine control set by +// set_fine_control() for the indicated child index and +// data type. Data of this type will now be controlled +// by the Control indicated by set_control() for this +// child, or by set_default_control() if nothing is +// indicated by set_control(). +//////////////////////////////////////////////////////////////////// +void DataValve:: +clear_fine_control(int child_index, TypeHandle data_type) { + nassertv(child_index >= 0); + if (child_index < (int)_controls.size()) { + _controls[child_index]._fine_controls.erase(data_type); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::has_fine_control +// Access: Published +// Description: Returns true if the indicated child has a particular +// fine control set for the indicated data type, or +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool DataValve:: +has_fine_control(int child_index, TypeHandle data_type) const { + nassertr(child_index >= 0, false); + if (child_index < (int)_controls.size()) { + return _controls[child_index]._fine_controls.count(data_type) != 0; + } + return false; +} + + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::get_fine_control +// Access: Published +// Description: Returns the fine control that has been set for the +// indicated child and data type, or NULL if no such +// fine control has been set. +//////////////////////////////////////////////////////////////////// +DataValve::Control *DataValve:: +get_fine_control(int child_index, TypeHandle data_type) const { + nassertr(child_index >= 0, NULL); + if (child_index < (int)_controls.size()) { + FineControls::const_iterator fci = + _controls[child_index]._fine_controls.find(data_type); + if (fci != _controls[child_index]._fine_controls.end()) { + return (*fci).second; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void DataValve:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << "DataValve " << get_name() << ": (default control is " + << (_default_control->is_on(*this) ? "on" : "off") << ")\n"; + + size_t i; + for (i = 0; i < _controls.size(); i++) { + if (has_control(i)) { + const Child &child = _controls[i]; + indent(out, indent_level + 2) + << "Child " << i << ": "; + + if (child._control.is_null()) { + out << "(default)"; + } else { + out << (child._control->is_on(*this) ? "on" : "off"); + } + out << "\n"; + + FineControls::const_iterator fci; + for (fci = child._fine_controls.begin(); + fci != child._fine_controls.end(); + ++fci) { + indent(out, indent_level + 4) + << (*fci).first << " " + << ((*fci).second->is_on(*this) ? "on" : "off") + << "\n"; + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::ensure_child_index +// Access: Private +// Description: Guarantees that we have at least enough children in +// the _control vector to describe the indicated +// child_index. +//////////////////////////////////////////////////////////////////// +void DataValve:: +ensure_child_index(int child_index) { + _controls.reserve(child_index + 1); + while ((int)_controls.size() <= child_index) { + _controls.push_back(Child()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::transmit_data +// Access: Public, Virtual +// Description: Called once before transmit_data_per_child() is +// called for each child, this gives the node a chance +// to process its inputs. +//////////////////////////////////////////////////////////////////// +void DataValve:: +transmit_data(NodeAttributes &data) { + // Update our modifier buttons during the overall pass. + const ButtonEventDataAttribute *b; + if (get_attribute_into(b, data, _button_events_type)) { + b->update_mods(_mods); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::transmit_data_per_child +// Access: Public, Virtual +// Description: Should be overridden in a derived class that wants to +// send a different data stream to each child. +// Normally, a node only overrides transmit_data(), +// which takes a set of input data attributes and +// generates a set of output data attributes. A node +// may also override transmit_data_per_child(), which is +// called after transmit_data(), once per child; this +// function may be used to send individual data +// attributes to each child. +//////////////////////////////////////////////////////////////////// +void DataValve:: +transmit_data_per_child(NodeAttributes &data, int child_index) { + // Consider which data this child wants to see. + static const FineControls empty_controls; + + Control *control = _default_control; + const FineControls *fine_controls = &empty_controls; + + if (child_index < (int)_controls.size()) { + if (!_controls[child_index]._control.is_null()) { + control = _controls[child_index]._control; + } + fine_controls = &_controls[child_index]._fine_controls; + } + + if (control->is_on(*this)) { + if (fine_controls->empty()) { + // The control is on, and we have no further fine-tuning. All + // data goes to the indicated node. + return; + + } else { + // The control is on, and we have some fine-tuning. Any data + // type explicitly "off" should be yanked. + FineControls::const_iterator fci; + for (fci = fine_controls->begin(); fci != fine_controls->end(); ++fci) { + TypeHandle data_type = (*fci).first; + Control *fcontrol = (*fci).second; + + if (!fcontrol->is_on(*this)) { + data.clear_attribute(data_type); + } + } + } + + } else { + if (fine_controls->empty()) { + // The control is off, and we have no further fine-tuning. All + // data gets eliminated. + data.clear(); + + } else { + // The control is off, and we have some fine-tuning. Any data + // type explicitly "on" should be preserved. + NodeAttributes temp; + + FineControls::const_iterator fci; + for (fci = fine_controls->begin(); fci != fine_controls->end(); ++fci) { + TypeHandle data_type = (*fci).first; + Control *fcontrol = (*fci).second; + + if (fcontrol->is_on(*this)) { + NodeAttribute *attrib = data.get_attribute(data_type); + if (attrib != (NodeAttribute *)NULL) { + temp.set_attribute(data_type, attrib); + } + } + } + + data = temp; + } + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: DataValve::init_type +// Access: Public, Static +// Description: +//////////////////////////////////////////////////////////////////// +void DataValve:: +init_type() { + DataNode::init_type(); + register_type(_type_handle, "DataValve", + DataNode::get_class_type()); + + ButtonEventDataTransition::init_type(); + register_data_transition(_button_events_type, "ButtonEvents", + ButtonEventDataTransition::get_class_type()); +} diff --git a/panda/src/tform/dataValve.h b/panda/src/tform/dataValve.h new file mode 100644 index 0000000000..afdd508751 --- /dev/null +++ b/panda/src/tform/dataValve.h @@ -0,0 +1,124 @@ +// Filename: dataValve.h +// Created by: drose (05Feb01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef DATAVALVE_H +#define DATAVALVE_H + +#include + +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////// +// Class : DataValve +// Description : This DataNode can be used to selectively control +// which child node or nodes receive certain data graph +// events, based on the type of data and possibly on the +// combination of modifier buttons being held down by +// the user. +// +// It's particularly useful when used in conjunction +// with one or more Trackball interfaces, for instance, +// to move around various different objects according to +// the key combination being held down. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA DataValve : public DataNode { +PUBLISHED: + DataValve(const string &name = ""); + virtual ~DataValve(); + + // The Control is used extensively within the DataValve class to + // manage the data flow; see the comments on the Control + // constructor. + class EXPCL_PANDA Control : public ReferenceCount { + PUBLISHED: + INLINE Control(); + + INLINE void set_on(); + INLINE void set_off(); + INLINE void set_buttons(const ModifierButtons &mods); + + bool is_on(const DataValve &valve) const; + + private: + enum State { + S_on, + S_off, + S_buttons + }; + State _state; + ModifierButtons _mods; + }; + + INLINE void set_default_control(Control *control); + INLINE Control *get_default_control() const; + + void set_control(int child_index, Control *control); + void clear_control(int child_index); + bool has_control(int child_index) const; + Control *get_control(int child_index) const; + + void set_fine_control(int child_index, TypeHandle data_type, Control *control); + void clear_fine_control(int child_index, TypeHandle data_type); + bool has_fine_control(int child_index, TypeHandle data_type) const; + Control *get_fine_control(int child_index, TypeHandle data_type) const; + + INLINE void set_modifier_buttons(const ModifierButtons &mods); + INLINE const ModifierButtons &get_modifier_buttons() const; + +public: + virtual void write(ostream &out, int indent_level = 0) const; + +private: + void ensure_child_index(int child_index); + + ModifierButtons _mods; + PT(Control) _default_control; + + typedef map FineControls; + + class Child { + public: + PT(Control) _control; + FineControls _fine_controls; + }; + + typedef vector Controls; + Controls _controls; + + +//////////////////////////////////////////////////////////////////// +// From parent class DataNode +//////////////////////////////////////////////////////////////////// +public: + virtual void + transmit_data(NodeAttributes &data); + + virtual void + transmit_data_per_child(NodeAttributes &data, int child_index); + + // inputs + static TypeHandle _button_events_type; + + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type(); + +private: + static TypeHandle _type_handle; +}; + +#include "dataValve.I" + +#endif diff --git a/panda/src/tform/driveInterface.cxx b/panda/src/tform/driveInterface.cxx index 0fbe16e6c7..fa5e0fff16 100644 --- a/panda/src/tform/driveInterface.cxx +++ b/panda/src/tform/driveInterface.cxx @@ -13,18 +13,14 @@ #include #include #include -#include -#include #include #include -#include +#include #include -#include #include TypeHandle DriveInterface::_type_handle; -TypeHandle DriveInterface::_mods_type; TypeHandle DriveInterface::_xyz_type; TypeHandle DriveInterface::_button_events_type; TypeHandle DriveInterface::_transform_type; @@ -126,6 +122,10 @@ DriveInterface(const string &name) : DataNode(name) { _cs = default_coordinate_system; + _mods.add_button(MouseButton::one()); + _mods.add_button(MouseButton::two()); + _mods.add_button(MouseButton::three()); + _transform = new MatrixDataAttribute; _transform->set_value(_mat); _attrib.set_attribute(_transform_type, _transform); @@ -652,13 +652,9 @@ get_mat() const { void DriveInterface:: force_dgraph() { _transform->set_value(_mat); - int num_children = get_num_children(DataRelation::get_class_type()); - for (int i = 0; i < num_children; i++) { - DataGraphVisitor dgv; - df_traverse(get_child(DataRelation::get_class_type(), i), - dgv, AllAttributesWrapper(_attrib), - NullLevelState(), DataRelation::get_class_type()); - } + + DataGraphTraverser dgt; + dgt.traverse_below(this, _attrib); } @@ -858,6 +854,7 @@ transmit_data(NodeAttributes &data) { ButtonEventDataAttribute::const_iterator bi; for (bi = b->begin(); bi != b->end(); ++bi) { const ButtonEvent &be = (*bi); + _mods.add_event(be); if (be._button == KeyboardButton::up()) { _up_arrow.set_key(be._down); @@ -872,7 +869,6 @@ transmit_data(NodeAttributes &data) { } // Now look for mouse activity. - bool any_button = false; double x = 0.0; double y = 0.0; @@ -881,18 +877,9 @@ transmit_data(NodeAttributes &data) { LVecBase3f p = xyz->get_value(); x = p[0]; y = p[1]; - - const ModifierButtonDataAttribute *button; - if (get_attribute_into(button, data, _mods_type)) { - ModifierButtons mods = button->get_mods(); - any_button = - mods.is_down(MouseButton::one()) || - mods.is_down(MouseButton::two()) || - mods.is_down(MouseButton::three()); - } } - apply(x, y, any_button); + apply(x, y, _mods.is_any_down()); _transform->set_value(_mat); // Now send our matrix down the pipe. @@ -911,9 +898,6 @@ init_type() { register_type(_type_handle, "DriveInterface", DataNode::get_class_type()); - ModifierButtonDataTransition::init_type(); - register_data_transition(_mods_type, "ModifierButtons", - ModifierButtonDataTransition::get_class_type()); Vec3DataTransition::init_type(); register_data_transition(_xyz_type, "XYZ", Vec3DataTransition::get_class_type()); diff --git a/panda/src/tform/driveInterface.h b/panda/src/tform/driveInterface.h index f6a77e4484..c34ea6367a 100644 --- a/panda/src/tform/driveInterface.h +++ b/panda/src/tform/driveInterface.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -122,6 +123,9 @@ private: bool _is_force_roll; CoordinateSystem _cs; + // Remember which mouse buttons are being held down. + ModifierButtons _mods; + // Remember which arrow keys are being held down and which aren't, // and at what point they last changed state. class KeyHeld { @@ -152,7 +156,6 @@ public: PT(MatrixDataAttribute) _transform; // inputs - static TypeHandle _mods_type; static TypeHandle _xyz_type; static TypeHandle _button_events_type; diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index a8e517afe0..ebc23a594f 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/panda/src/tform/mouseWatcher.cxx @@ -8,11 +8,8 @@ #include #include -#include #include #include -#include -#include #include #include #include @@ -21,7 +18,6 @@ TypeHandle MouseWatcher::_type_handle; -TypeHandle MouseWatcher::_mods_type; TypeHandle MouseWatcher::_xyz_type; TypeHandle MouseWatcher::_button_events_type; @@ -313,9 +309,6 @@ init_type() { register_type(_type_handle, "MouseWatcher", DataNode::get_class_type()); - ModifierButtonDataTransition::init_type(); - register_data_transition(_mods_type, "ModifierButtons", - ModifierButtonDataTransition::get_class_type()); Vec3DataTransition::init_type(); register_data_transition(_xyz_type, "XYZ", Vec3DataTransition::get_class_type()); diff --git a/panda/src/tform/mouseWatcher.h b/panda/src/tform/mouseWatcher.h index a2b3aed35c..d2b0f86581 100644 --- a/panda/src/tform/mouseWatcher.h +++ b/panda/src/tform/mouseWatcher.h @@ -110,7 +110,6 @@ public: transmit_data(NodeAttributes &data); // inputs & outputs - static TypeHandle _mods_type; static TypeHandle _xyz_type; static TypeHandle _button_events_type; diff --git a/panda/src/tform/planarSlider.cxx b/panda/src/tform/planarSlider.cxx index ef15a0161e..66cfe717be 100644 --- a/panda/src/tform/planarSlider.cxx +++ b/panda/src/tform/planarSlider.cxx @@ -9,14 +9,15 @@ #include #include #include -#include +#include +#include #include #include TypeHandle PlanarSlider::_type_handle; -TypeHandle PlanarSlider::_mods_type; TypeHandle PlanarSlider::_xyz_type; +TypeHandle PlanarSlider::_button_events_type; TypeHandle PlanarSlider::_transform_type; @@ -34,6 +35,8 @@ PlanarSlider(const string &name) : DataNode(name) { _transform = new MatrixDataAttribute; _attrib.set_attribute(_transform_type, _transform); + + _mods.add_button(MouseButton::one()); } @@ -146,19 +149,17 @@ get_mouse_pos() const { //////////////////////////////////////////////////////////////////// void PlanarSlider:: transmit_data(NodeAttributes &data) { - const NodeAttribute *button = data.get_attribute(_mods_type); + // First, update our modifier buttons. + const ButtonEventDataAttribute *b; + if (get_attribute_into(b, data, _button_events_type)) { + b->update_mods(_mods); + } + + // Now look for a mouse position. const NodeAttribute *xyz = data.get_attribute(_xyz_type); if (xyz != (NodeAttribute *)NULL) { - bool is_down = false; - - if (button != (NodeAttribute *)NULL) { - ModifierButtons mods = - DCAST(ModifierButtonDataAttribute, button)->get_mods(); - is_down = mods.is_down(MouseButton::one()); - } - - if (is_down) { + if (_mods.is_any_down()) { LVecBase3f p = DCAST(Vec3DataAttribute, xyz)->get_value(); set_mouse_pos(LPoint2f(p[0], p[1])); } @@ -180,13 +181,13 @@ init_type() { register_type(_type_handle, "PlanarSlider", DataNode::get_class_type()); - ModifierButtonDataTransition::init_type(); - register_data_transition(_mods_type, "ModifierButtons", - ModifierButtonDataTransition::get_class_type()); Vec3DataTransition::init_type(); register_data_transition(_xyz_type, "XYZ", Vec3DataTransition::get_class_type()); MatrixDataTransition::init_type(); register_data_transition(_transform_type, "Transform", MatrixDataTransition::get_class_type()); + ButtonEventDataTransition::init_type(); + register_data_transition(_button_events_type, "ButtonEvents", + ButtonEventDataTransition::get_class_type()); } diff --git a/panda/src/tform/planarSlider.h b/panda/src/tform/planarSlider.h index caa5fe382a..45899f2d0a 100644 --- a/panda/src/tform/planarSlider.h +++ b/panda/src/tform/planarSlider.h @@ -16,6 +16,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////// @@ -46,6 +47,7 @@ private: CoordinateSystem _cs; LMatrix4f _transform_mat, _inverse_mat; LPoint2f _mouse_pos; + ModifierButtons _mods; //////////////////////////////////////////////////////////////////// // From parent class DataNode @@ -59,8 +61,8 @@ public: PT(MatrixDataAttribute) _transform; // inputs - static TypeHandle _mods_type; static TypeHandle _xyz_type; + static TypeHandle _button_events_type; // outputs static TypeHandle _transform_type; diff --git a/panda/src/tform/trackball.cxx b/panda/src/tform/trackball.cxx index ae99184c51..de0c66f32f 100644 --- a/panda/src/tform/trackball.cxx +++ b/panda/src/tform/trackball.cxx @@ -10,15 +10,14 @@ #include #include #include -#include -#include +#include #include #include TypeHandle Trackball::_type_handle; -TypeHandle Trackball::_mods_type; TypeHandle Trackball::_pixel_xyz_type; +TypeHandle Trackball::_button_events_type; TypeHandle Trackball::_transform_type; #define B1_MASK 1 @@ -46,6 +45,10 @@ Trackball(const string &name) : DataNode(name) { _rel_to = NULL; _cs = default_coordinate_system; + _mods.add_button(MouseButton::one()); + _mods.add_button(MouseButton::two()); + _mods.add_button(MouseButton::three()); + _transform = new MatrixDataAttribute; _transform->set_value(LMatrix4f::ident_mat()); _attrib.set_attribute(_transform_type, _transform); @@ -471,7 +474,13 @@ recompute() { //////////////////////////////////////////////////////////////////// void Trackball:: transmit_data(NodeAttributes &data) { - const NodeAttribute *button = data.get_attribute(_mods_type); + // First, update our modifier buttons. + const ButtonEventDataAttribute *b; + if (get_attribute_into(b, data, _button_events_type)) { + b->update_mods(_mods); + } + + // Now, check for mouse motion. const NodeAttribute *pixel_xyz = data.get_attribute(_pixel_xyz_type); if (pixel_xyz != (NodeAttribute *)NULL) { @@ -480,19 +489,14 @@ transmit_data(NodeAttributes &data) { float this_y = p[1]; int this_button = 0; - if (button != (NodeAttribute *)NULL) { - ModifierButtons mods = - DCAST(ModifierButtonDataAttribute, button)->get_mods(); - - if (mods.is_down(MouseButton::one())) { - this_button |= B1_MASK; - } - if (mods.is_down(MouseButton::two())) { - this_button |= B2_MASK; - } - if (mods.is_down(MouseButton::three())) { - this_button |= B3_MASK; - } + if (_mods.is_down(MouseButton::one())) { + this_button |= B1_MASK; + } + if (_mods.is_down(MouseButton::two())) { + this_button |= B2_MASK; + } + if (_mods.is_down(MouseButton::three())) { + this_button |= B3_MASK; } float x = this_x - _lastx; @@ -521,12 +525,12 @@ init_type() { register_type(_type_handle, "Trackball", DataNode::get_class_type()); - ModifierButtonDataTransition::init_type(); - register_data_transition(_mods_type, "ModifierButtons", - ModifierButtonDataTransition::get_class_type()); Vec3DataTransition::init_type(); register_data_transition(_pixel_xyz_type, "PixelXYZ", Vec3DataTransition::get_class_type()); + ButtonEventDataTransition::init_type(); + register_data_transition(_button_events_type, "ButtonEvents", + ButtonEventDataTransition::get_class_type()); MatrixDataTransition::init_type(); register_data_transition(_transform_type, "Transform", MatrixDataTransition::get_class_type()); diff --git a/panda/src/tform/trackball.h b/panda/src/tform/trackball.h index dd54a082b1..76c53696bf 100644 --- a/panda/src/tform/trackball.h +++ b/panda/src/tform/trackball.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,9 @@ private: const Node *_rel_to; CoordinateSystem _cs; + // Remember which mouse buttons are being held down. + ModifierButtons _mods; + //////////////////////////////////////////////////////////////////// // From parent class DataNode @@ -116,8 +120,8 @@ public: PT(MatrixDataAttribute) _transform; // inputs - static TypeHandle _mods_type; static TypeHandle _pixel_xyz_type; + static TypeHandle _button_events_type; // outputs static TypeHandle _transform_type;